Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
5 deleted
7 edited
7 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4444#include <private/qbezier_p.h>
    4545
     46
     47
    4648void QGL2PEXVertexArray::clear()
    4749{
    4850    vertexArray.reset();
    49     vertexArrayStops.clear();
     51    vertexArrayStops.();
    5052    boundingRectDirty = true;
    5153}
     
    6062}
    6163
    62 void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale)
     64void QGL2PEXVertexArray::addRect(const QRectF &rect)
     65{
     66    vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight()
     67                << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
     68}
     69
     70void QGL2PEXVertexArray::addClosingLine(int index)
     71{
     72    if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last()))
     73        vertexArray.add(vertexArray.at(index));
     74}
     75
     76void QGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex)
     77{
     78    const QPointF *const points = reinterpret_cast<const QPointF *>(path.points());
     79    const QPainterPath::ElementType *const elements = path.elements();
     80
     81    QPointF sum = points[subPathIndex];
     82    int count = 1;
     83
     84    for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) {
     85        sum += points[i];
     86        ++count;
     87    }
     88
     89    const QPointF centroid = sum / qreal(count);
     90    vertexArray.add(centroid);
     91}
     92
     93void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline)
    6394{
    6495    const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
     
    71102    }
    72103
     104
     105
     106
     107
    73108    vertexArray.add(points[0]); // The first element is always a moveTo
    74109
     
    86121
    87122        for (int i=1; i<path.elementCount(); ++i) {
    88             const QPainterPath::ElementType elementType = elements[i];
    89             switch (elementType) {
     123            switch (elements[i]) {
    90124            case QPainterPath::MoveToElement:
     125
     126
    91127//                qDebug("element[%d] is a MoveToElement", i);
    92                 vertexArrayStops.append(vertexArray.size());
    93                 vertexArray.add(points[i]); // Add the moveTo as a new vertex
     128                vertexArrayStops.add(vertexArray.size());
     129                if (!outline) {
     130                    if (!path.isConvex()) addCentroid(path, i);
     131                    lastMoveTo = vertexArray.size();
     132                }
     133                lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex
    94134                break;
    95135            case QPainterPath::LineToElement:
     
    97137                lineToArray(points[i].x(), points[i].y());
    98138                break;
    99             case QPainterPath::CurveToElement:
    100 //                qDebug("element[%d] is a CurveToElement", i);
    101                 curveToArray(points[i], points[i+1], points[i+2], curveInverseScale);
    102                 i+=2;
    103                 break;
     139            case QPainterPath::CurveToElement: {
     140                QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1),
     141                                                points[i],
     142                                                points[i+1],
     143                                                points[i+2]);
     144                QRectF bounds = b.bounds();
     145                // threshold based on same algorithm as in qtriangulatingstroker.cpp
     146                int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6));
     147                if (threshold < 3) threshold = 3;
     148                qreal one_over_threshold_minus_1 = 1.f / (threshold - 1);
     149                for (int t=0; t<threshold; ++t) {
     150                    QPointF pt = b.pointAt(t * one_over_threshold_minus_1);
     151                    lineToArray(pt.x(), pt.y());
     152                }
     153                i += 2;
     154                break; }
    104155            default:
    105156                break;
     
    108159    } while (0);
    109160
    110     vertexArrayStops.append(vertexArray.size());
     161    if (!outline)
     162        addClosingLine(lastMoveTo);
     163    vertexArrayStops.add(vertexArray.size());
    111164}
    112165
     
    125178}
    126179
    127 void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale)
    128 {
    129     qreal inverseScaleHalf = inverseScale / 2;
    130 
    131     QBezier beziers[32];
    132     beziers[0] = QBezier::fromPoints(vertexArray.last(), cp1, cp2, ep);
    133     QBezier *b = beziers;
    134     while (b >= beziers) {
    135         // check if we can pop the top bezier curve from the stack
    136         qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1);
    137         qreal d;
    138         if (l > inverseScale) {
    139             d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2) - (b->y4 - b->y1)*(b->x1 - b->x2) )
    140                 + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3) - (b->y4 - b->y1)*(b->x1 - b->x3) );
    141             d /= l;
    142         } else {
    143             d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) +
    144                 qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
    145         }
    146         if (d < inverseScaleHalf || b == beziers + 31) {
    147             // good enough, we pop it off and add the endpoint
    148             lineToArray(b->x4, b->y4);
    149             --b;
    150         } else {
    151             // split, second half of the polygon goes lower into the stack
    152             b->split(b+1, b);
    153            ++b;
    154         }
    155     }
    156 }
     180QT_END_NAMESPACE
  • trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5151//
    5252
     53
     54
     55
    5356#include <QRectF>
    5457
     
    5659#include <private/qvectorpath_p.h>
    5760#include <private/qgl_p.h>
     61
     62
    5863
    5964class QGLPoint
     
    6368        x(new_x), y(new_y) {};
    6469
    65     QGLPoint(QPointF p) :
     70    QGLPoint(p) :
    6671        x(p.x()), y(p.y()) {};
    6772
     
    7883struct QGLRect
    7984{
    80     QGLRect(QRectF r)
     85    QGLRect(r)
    8186        :  left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {}
    8287
     
    99104        boundingRectDirty(true) {}
    100105
    101     void addPath(const QVectorPath &path, GLfloat curveInverseScale);
     106    void addRect(const QRectF &rect);
     107    void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true);
    102108    void clear();
    103109
    104110    QGLPoint*        data() {return vertexArray.data();}
    105     QVector<int>&   stops() {return vertexArrayStops;}
     111    int *stops() const { return vertexArrayStops.data(); }
     112    int stopCount() const { return vertexArrayStops.size(); }
    106113    QGLRect         boundingRect() const;
     114
     115
    107116
    108117    void lineToArray(const GLfloat x, const GLfloat y);
     
    110119private:
    111120    QDataBuffer<QGLPoint> vertexArray;
    112     QVector<int>          vertexArrayStops;
     121    Q      vertexArrayStops;
    113122
    114123    GLfloat     maxX;
     
    117126    GLfloat     minY;
    118127    bool        boundingRectDirty;
     128
     129
     130
    119131
    120     inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale);
    121 };
     132QT_END_NAMESPACE
     133
     134#endif
  • trunk/src/opengl/gl2paintengineex/qglgradientcache.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4545#include "qglgradientcache_p.h"
    4646
    47 void QGLGradientCache::cleanCache() {
     47QT_BEGIN_NAMESPACE
     48
     49static void QGL2GradientCache_free(void *ptr)
     50{
     51    delete reinterpret_cast<QGL2GradientCache *>(ptr);
     52}
     53
     54Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free))
     55
     56QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
     57{
     58    QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context));
     59    if (!p) {
     60        QGLShareContextScope scope(context);
     61        p = new QGL2GradientCache;
     62        qt_gradient_caches()->insert(context, p);
     63    }
     64    return p;
     65}
     66
     67void QGL2GradientCache::cleanCache() {
    4868    QGLGradientColorTableHash::const_iterator it = cache.constBegin();
    4969    for (; it != cache.constEnd(); ++it) {
     
    5474}
    5575
    56 GLuint QGLGradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx)
     76GLuint QGL)
    5777{
    58     if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))
    59         cleanCache();
    60 
    61     buffer_ctx = ctx;
    62 
    6378    quint64 hash_val = 0;
    6479
     
    85100
    86101
    87 GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
     102GLuint QGLGradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
    88103{
    89104    if (cache.size() == maxCacheSize()) {
     
    110125
    111126
    112 // GL's expects pixels in RGBA, bin-endian (ABGR on x86).
    113 // Qt stores in ARGB using whatever byte-order the mancine uses.
     127// GL's expects pixels in RGBA, bin-endian (ABGR on x86).
     128// Qt byte-order the mancine uses.
    114129static inline uint qtToGlColor(uint c)
    115130{
    116131    uint o;
    117132#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
    118     o = c & 0xFF00FF00; // alpha & green already in the right place
    119     o |= (c >> 16) & 0x000000FF; // red
    120     o |= (c << 16) & 0x00FF0000; // blue
    121 
     133    o = (c & 0xff00ff00)  // alpha & green already in the right place
     134        | ((c >> 16) & 0x000000ff) // red
     135        | ((c << 16) & 0x00ff0000); // blue
    122136#else //Q_BIG_ENDIAN
    123     o = c & 0x00FF00FF; // alpha & green already in the right place
    124     o |= (c << 16) & 0xFF000000; // red
    125     o |= (c >> 16) & 0x0000FF00; // blue
    126 #error big endian not tested with QGLGraphicsContext
     137    o = (c << 8)
     138        | ((c >> 24) & 0x000000ff);
    127139#endif // Q_BYTE_ORDER
    128140    return o;
     
    130142
    131143//TODO: Let GL generate the texture using an FBO
    132 void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
     144void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
    133145{
    134146    int pos = 0;
     
    137149
    138150    for (int i = 0; i < s.size(); ++i)
    139         colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB
     151        colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB
    140152
    141153    bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
     
    184196    colorTable[size-1] = last_color;
    185197}
     198
     199
  • trunk/src/opengl/gl2paintengineex/qglgradientcache_p.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5353#include <QMultiHash>
    5454#include <QObject>
    55 #include <QtOpenGL>
     55#include <QtOpenGL/QtOpenGL>
     56#include <private/qgl_p.h>
    5657
    57 class QGLGradientCache : public QObject
     58QT_BEGIN_NAMESPACE
     59
     60class QGL2GradientCache
    5861{
    59     Q_OBJECT
    6062    struct CacheInfo
    6163    {
     
    7274
    7375public:
    74     QGLGradientCache() : QObject(), buffer_ctx(0)
    75     {
    76 /*
    77         connect(QGLSignalProxy::instance(),
    78                 SIGNAL(aboutToDestroyContext(const QGLContext *)),
    79                 SLOT(cleanupGLContextRefs(const QGLContext *)));
    80 */
    81     }
     76    static QGL2GradientCache *cacheForContext(const QGLContext *context);
    8277
    83     GLuint getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx);
     78    QGL2GradientCache() { }
     79    ~QGL2GradientCache() {cleanCache();}
     80
     81    GLuint getBuffer(const QGradient &gradient, qreal opacity);
    8482    inline int paletteSize() const { return 1024; }
    8583
     
    9492
    9593    QGLGradientColorTableHash cache;
    96     const QGLContext *buffer_ctx;
    97 
    98 public slots:
    99     void cleanupGLContextRefs(const QGLContext *context) {
    100         if (context == buffer_ctx) {
    101             cleanCache();
    102             buffer_ctx = 0;
    103         }
    104     }
    10594};
    10695
     96
    10797
    108 
  • trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    6363*/
    6464
     65
    6566
    6667#include "qpaintengineex_opengl2_p.h"
     
    7677#include <private/qfontengine_p.h>
    7778#include <private/qtextureglyphcache_p.h>
     79
     80
    7881
    7982#include "qglgradientcache_p.h"
    80 #include "qglpexshadermanager_p.h"
     83#include "qglshadermanager_p.h"
    8184#include "qgl2pexvertexarray_p.h"
    8285
    83 
    84 extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
    85 
     86#include "qtriangulatingstroker_p.h"
    8687
    8788#include <QDebug>
    8889
    89 
    90 static const GLuint QT_VERTEX_COORDS_ATTR  = 0;
    91 static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
    92 static const GLuint QT_BRUSH_TEXTURE_UNIT  = 0;
    93 
    94 class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
    95 {
    96     Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
     90QT_BEGIN_NAMESPACE
     91
     92//#define QT_GL_NO_SCISSOR_TEST
     93
     94static const GLuint GL_STENCIL_HIGH_BIT         = 0x80;
     95static const GLuint QT_BRUSH_TEXTURE_UNIT       = 0;
     96static const GLuint QT_IMAGE_TEXTURE_UNIT       = 0; //Can be the same as brush texture unit
     97static const GLuint QT_MASK_TEXTURE_UNIT        = 1;
     98static const GLuint QT_BACKGROUND_TEXTURE_UNIT  = 2;
     99
     100#ifdef Q_WS_WIN
     101extern Q_GUI_EXPORT bool qt_cleartype_enabled;
     102#endif
     103
     104class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
     105{
     106    Q_OBJECT
    97107public:
    98     QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) :
    99             q(q_ptr),
    100             width(0), height(0),
    101             ctx(0),
    102             currentBrush( &(q->state()->brush) ),
    103             inverseScale(1),
    104             shaderManager(0)
    105     { }
    106 
    107     ~QGL2PaintEngineExPrivate();
    108 
    109     void updateBrushTexture();
    110     void updateBrushUniforms();
    111     void updateMatrix();
    112     void updateCompositionMode();
    113     void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform);
    114 
    115     void setBrush(const QBrush* brush);
    116 
    117     void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight);
    118 
    119     void fill(const QVectorPath &path);
    120     void drawOutline(const QVectorPath& path);
    121 
    122     void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive);
    123         // ^ draws whatever is in the vertex array
    124     void composite(const QGLRect& boundingRect);
    125         // ^ Composites the bounding rect onto dest buffer
    126     void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill);
    127         // ^ Calls drawVertexArrays to render into stencil buffer
    128     void cleanStencilBuffer(const QGLRect& area);
    129 
    130     void prepareForDraw();
    131 
    132     inline void useSimpleShader();
    133     inline QColor premultiplyColor(QColor c, GLfloat opacity);
    134 
    135     QGL2PaintEngineEx* q;
    136 
    137     //### Move into QGLDrawable
    138     int width, height;
    139     QGLContext* ctx;
    140 
    141     // Dirty flags
    142     bool matrixDirty; // Implies matrix uniforms are also dirty
    143     bool compositionModeDirty;
    144     bool brushTextureDirty;
    145     bool brushUniformsDirty;
    146     bool simpleShaderMatrixUniformDirty;
    147     bool brushShaderMatrixUniformDirty;
    148     bool imageShaderMatrixUniformDirty;
    149     bool textShaderMatrixUniformDirty;
    150     bool stencilBuferDirty;
    151 
    152     const QBrush*    currentBrush; // May not be the state's brush!
    153 
    154     GLfloat     inverseScale;
    155 
    156     QGL2PEXVertexArray pathVertexArray;
    157 
    158     GLfloat pmvMatrix[4][4];
    159 
    160     QGLPEXShaderManager* shaderManager;
    161 
    162     // Clipping & state stuff stolen from QOpenGLPaintEngine:
    163     void updateDepthClip();
    164     uint use_system_clip : 1;
     108    QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
     109    ~QGLTextureGlyphCache();
     110
     111    virtual void createTextureData(int width, int height);
     112    virtual void resizeTextureData(int width, int height);
     113    virtual void fillTexture(const Coord &c, glyph_t glyph);
     114    virtual int glyphMargin() const;
     115
     116    inline GLuint texture() const { return m_texture; }
     117
     118    inline int width() const { return m_width; }
     119    inline int height() const { return m_height; }
     120
     121    inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
     122
     123
     124public Q_SLOTS:
     125    void contextDestroyed(const QGLContext *context) {
     126        if (context == ctx) {
     127            QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx);
     128            if (shares.isEmpty()) {
     129                glDeleteFramebuffers(1, &m_fbo);
     130                if (m_width || m_height)
     131                    glDeleteTextures(1, &m_texture);
     132                ctx = 0;
     133            } else {
     134                // since the context holding the texture is shared, and
     135                // about to be destroyed, we have to transfer ownership
     136                // of the texture to one of the share contexts
     137                ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0));
     138            }
     139        }
     140    }
     141
     142private:
     143    QGLContext *ctx;
     144
     145    QGL2PaintEngineExPrivate *pex;
     146
     147    GLuint m_texture;
     148    GLuint m_fbo;
     149
     150    int m_width;
     151    int m_height;
     152
     153    QGLShaderProgram *m_program;
    165154};
    166155
     156
     157
     158
     159
     160
     161
     162
     163
     164
     165
     166
     167
     168
     169
     170
     171
     172
     173
     174
     175
     176
     177
     178
     179
     180
     181
     182
     183
     184
     185
     186
     187
     188
     189
     190
     191
     192
     193
     194
     195
     196
     197
     198
     199
     200
     201
     202
     203
     204
     205
     206
     207
     208
     209
     210
     211
     212
     213
     214
     215
     216
     217
     218
     219
     220
     221
     222
     223
     224
     225
     226
     227
     228
     229
     230
     231
     232
     233
     234
     235
     236
     237
     238
     239
     240
     241
     242
     243
     244
     245
     246
     247
     248
     249
     250
     251
     252
     253
     254
     255
     256
     257
     258
     259
     260
     261
     262
     263
     264
     265
     266
     267
     268
     269
     270
     271
     272
     273
     274
     275
     276
     277
     278
     279
     280
     281
     282
     283
     284
     285
     286
     287
     288
     289
     290
     291
     292
     293
     294
     295
     296
     297
     298
     299
     300
     301
     302
     303
     304
     305
     306
     307
     308
     309
     310
     311
     312
     313
     314
     315
     316
     317
     318
     319
     320
     321
     322
     323
     324
     325
     326
     327
     328
     329
     330
     331
     332
    167333
    168334////////////////////////////////// Private Methods //////////////////////////////////////////
     
    170336QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
    171337{
    172     if (shaderManager) {
    173         delete shaderManager;
    174         shaderManager = 0;
    175     }
    176 }
    177 
    178 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform)
    179 {
    180     glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
     338    delete shaderManager;
     339
     340    while (pathCaches.size()) {
     341        QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
     342        e->cleanup(e->engine, e->data);
     343        e->data = 0;
     344        e->engine = 0;
     345    }
     346}
     347
     348void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
     349{
     350//    glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
     351    if (id != GLuint(-1) && id == lastTextureUsed)
     352        return;
     353
     354    lastTextureUsed = id;
    181355
    182356    if (smoothPixmapTransform) {
     
    192366
    193367
    194 QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity)
    195 {
    196     uint alpha = qRound(c.alpha() * opacity);
    197     return QColor ( ((c.red() * alpha + 128) >> 8),
    198                     ((c.green() * alpha + 128) >> 8),
    199                     ((c.blue() * alpha + 128) >> 8),
    200                     alpha);
    201 }
    202 
    203 
    204 void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
    205 {
     368inline QColor qt_premultiplyColor(QColor c, GLfloat opacity)
     369{
     370    qreal alpha = c.alphaF() * opacity;
     371    c.setAlphaF(alpha);
     372    c.setRedF(c.redF() * alpha);
     373    c.setGreenF(c.greenF() * alpha);
     374    c.setBlueF(c.blueF() * alpha);
     375    return c;
     376}
     377
     378
     379void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
     380{
     381    if (qbrush_fast_equals(currentBrush, brush))
     382        return;
     383
     384    const Qt::BrushStyle newStyle = qbrush_style(brush);
     385    Q_ASSERT(newStyle != Qt::NoBrush);
     386
    206387    currentBrush = brush;
    207     brushTextureDirty = true;
    208     brushUniformsDirty = true;
    209     shaderManager->setBrushStyle(currentBrush->style());
    210     shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine());
    211 }
    212 
    213 
    214 // Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray
     388    brushUniformsDirty = true; // All brushes have at least one uniform
     389
     390    if (newStyle > Qt::SolidPattern)
     391        brushTextureDirty = true;
     392
     393    if (currentBrush.style() == Qt::TexturePattern
     394        && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
     395    {
     396        shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern);
     397    } else {
     398        shaderManager->setSrcPixelType(newStyle);
     399    }
     400    shaderManager->optimiseForBrushTransform(currentBrush.transform().type());
     401}
     402
     403
    215404void QGL2PaintEngineExPrivate::useSimpleShader()
    216405{
    217     shaderManager->simpleShader()->use();
     406    shaderManager->simpleProgram()->bind();
     407    shaderManager->setDirty();
    218408
    219409    if (matrixDirty)
     
    221411
    222412    if (simpleShaderMatrixUniformDirty) {
    223         shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
     413        const GLuint location = shaderManager->simpleProgram()->uniformLocation("pmvMatrix");
     414        glUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)pmvMatrix);
    224415        simpleShaderMatrixUniformDirty = false;
    225416    }
    226417}
    227418
    228 
    229 Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache)
    230 
    231419void QGL2PaintEngineExPrivate::updateBrushTexture()
    232420{
     421
    233422//     qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
    234     Qt::BrushStyle style = currentBrush->style();
     423    Qt::BrushStyle style = currentBrushstyle();
    235424
    236425    if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
    237426        // Get the image data for the pattern
    238         QImage texImage = qt_imageForBrush(style, true);
    239 
    240         glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
    241         ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true);
    242         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
     427        QImage texImage = qt_imageForBrush(style, e);
     428
     429        glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
     430        ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true);
     431        updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, );
    243432    }
    244433    else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
    245434        // Gradiant brush: All the gradiants use the same texture
    246435
    247         const QGradient* g = currentBrush->gradient();
     436        const QGradient* g = currentBrushgradient();
    248437
    249438        // We apply global opacity in the fragment shaders, so we always pass 1.0
    250439        // for opacity to the cache.
    251         GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx);
     440        GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
     441
     442        glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
     443        glBindTexture(GL_TEXTURE_2D, texId);
    252444
    253445        if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient)
    254             updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
     446            updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, );
    255447        else if (g->spread() == QGradient::ReflectSpread)
    256             updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);
     448            updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, );
    257449        else
    258             updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true);
    259 
    260         glBindTexture(GL_TEXTURE_2D, texId);
     450            updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform);
    261451    }
    262452    else if (style == Qt::TexturePattern) {
    263         const QPixmap& texPixmap = currentBrush->texture();
    264 
    265         glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
    266         ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true);
    267         updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
     453        const QPixmap& texPixmap = currentBrush.texture();
     454
     455        glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
     456        QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
     457        updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
     458        textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
    268459    }
    269460    brushTextureDirty = false;
     
    274465{
    275466//     qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()");
    276     Qt::BrushStyle style = currentBrush->style();
     467    Qt::BrushStyle style = currentBrushstyle();
    277468
    278469    if (style == Qt::NoBrush)
    279470        return;
    280471
    281     GLfloat opacity = 1.0;
    282     if (q->state()->opacity < 0.99f)
    283         opacity = (GLfloat)q->state()->opacity;
    284     bool setOpacity = true;
    285 
    286     QTransform brushQTransform = currentBrush->transform();
     472    QTransform brushQTransform = currentBrush.transform();
    287473
    288474    if (style == Qt::SolidPattern) {
    289         QColor col = premultiplyColor(currentBrush->color(), opacity);
    290         shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col;
    291         setOpacity = false;
     475        QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
     476        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col);
    292477    }
    293478    else {
     
    296481
    297482        if (style <= Qt::DiagCrossPattern) {
    298             translationPoint = q->state()->brushOrigin;
    299 
    300             QColor col = premultiplyColor(currentBrush->color(), opacity);
    301 
    302             shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col;
    303             setOpacity = false; //So code below doesn't try to set the opacity uniform
    304 
    305             QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
    306             shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
     483            QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
     484
     485            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
     486
     487            QVector2D halfViewportSize(width*0.5, height*0.5);
     488            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
    307489        }
    308490        else if (style == Qt::LinearGradientPattern) {
    309             const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient());
     491            const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrushgradient());
    310492
    311493            QPointF realStart = g->start();
     
    315497            QPointF l = realFinal - realStart;
    316498
    317             // ###
    318             QGLVec3 linearData = {
     499            QVector3D linearData(
    319500                l.x(),
    320501                l.y(),
    321502                1.0f / (l.x() * l.x() + l.y() * l.y())
    322             };
    323 
    324             shaderManager->brushShader()->uniforms()[QLatin1String("linearData")] = linearData;
    325 
    326             QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
    327             shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
     503            ;
     504
     505            shaderManager->;
     506
     507            Q;
     508            shaderManager->;
    328509        }
    329510        else if (style == Qt::ConicalGradientPattern) {
    330             const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient());
     511            const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrushgradient());
    331512            translationPoint   = g->center();
    332513
    333514            GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
    334515
    335             shaderManager->brushShader()->uniforms()[QLatin1String("angle")] = angle;
    336 
    337             QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
    338             shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
     516            shaderManager->;
     517
     518            Q;
     519            shaderManager->;
    339520        }
    340521        else if (style == Qt::RadialGradientPattern) {
    341             const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient());
     522            const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrushgradient());
    342523            QPointF realCenter = g->center();
    343524            QPointF realFocal  = g->focalPoint();
     
    346527
    347528            QPointF fmp = realCenter - realFocal;
    348             shaderManager->brushShader()->uniforms()[QLatin1String("fmp")] = fmp;
     529            shaderManager->;
    349530
    350531            GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius;
    351             shaderManager->brushShader()->uniforms()[QLatin1String("fmp2_m_radius2")] = fmp2_m_radius2;
    352 
    353             shaderManager->brushShader()->uniforms()[QLatin1String("inverse_2_fmp2_m_radius2")] =
    354                                                         GLfloat(1.0 / (2.0*fmp2_m_radius2));
    355 
    356             QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
    357             shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
     532            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2);
     533            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2),
     534                                                             GLfloat(1.0 / (2.0*fmp2_m_radius2)));
     535
     536            QVector2D halfViewportSize(width*0.5, height*0.5);
     537            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
    358538        }
    359539        else if (style == Qt::TexturePattern) {
    360             translationPoint = q->state()->brushOrigin;
    361 
    362             const QPixmap& texPixmap = currentBrush->texture();
    363 
    364             QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() );
    365             shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize;
    366 
    367             QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
    368             shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
     540            const QPixmap& texPixmap = currentBrush.texture();
     541
     542            if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) {
     543                QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
     544                shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
     545            }
     546
     547            QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height());
     548            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize);
     549
     550            QVector2D halfViewportSize(width*0.5, height*0.5);
     551            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
    369552        }
    370553        else
    371554            qWarning("QGL2PaintEngineEx: Unimplemented fill style");
    372555
     556
     557
     558
     559
    373560        QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
    374561        QTransform gl_to_qt(1, 0, 0, -1, 0, height);
    375         QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate;
    376 
    377         shaderManager->brushShader()->uniforms()[QLatin1String("brushTransform")] = inv_matrix;
    378         shaderManager->brushShader()->uniforms()[QLatin1String("brushTexture")] = QT_BRUSH_TEXTURE_UNIT;
    379 
    380         if (setOpacity)
    381             shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity;
     562        QTransform inv_matrix;
     563        if (style == Qt::TexturePattern && textureInvertedY == -1)
     564            inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate;
     565        else
     566            inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate;
     567
     568        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix);
     569        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
    382570    }
    383571    brushUniformsDirty = false;
     
    390578//     qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
    391579
    392     // We setup the Projection matrix to be the equivilant of glOrtho(0, w, h, 0, -1, 1):
    393     GLfloat P[4][4] = {
    394         {2.0/width,  0.0,        0.0, -1.0},
    395         {0.0,       -2.0/height, 0.0,  1.0},
    396         {0.0,        0.0,       -1.0,  0.0},
    397         {0.0,        0.0,        0.0,  1.0}
    398     };
    399 
    400     // Use the (3x3) transform for the Model~View matrix:
    401580    const QTransform& transform = q->state()->matrix;
    402     GLfloat MV[4][4] = {
    403         {transform.m11(), transform.m21(), 0.0, transform.dx() + 0.5},
    404         {transform.m12(), transform.m22(), 0.0, transform.dy() + 0.5},
    405         {0.0,             0.0,             1.0, 0.0},
    406         {transform.m13(), transform.m23(), 0.0, transform.m33()}
    407     };
    408 
    409     // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices,
    410     //       we also transpose them ready for GL.
    411     for (int row = 0; row < 4; ++row) {
    412         for (int col = 0; col < 4; ++col) {
    413             pmvMatrix[col][row] = 0.0;
    414             for (int n = 0; n < 4; ++n)
    415                 pmvMatrix[col][row] += P[row][n] * MV[n][col];
    416         }
    417     }
     581
     582    // The projection matrix converts from Qt's coordinate system to GL's coordinate system
     583    //    * GL's viewport is 2x2, Qt's is width x height
     584    //    * GL has +y -> -y going from bottom -> top, Qt is the other way round
     585    //    * GL has [0,0] in the center, Qt has it in the top-left
     586    //
     587    // This results in the Projection matrix below, which is multiplied by the painter's
     588    // transformation matrix, as shown below:
     589    //
     590    //                Projection Matrix                      Painter Transform
     591    // ------------------------------------------------   ------------------------
     592    // | 2.0 / width  |      0.0      |     -1.0      |   |  m11  |  m21  |  dx  |
     593    // |     0.0      | -2.0 / height |      1.0      | * |  m12  |  m22  |  dy  |
     594    // |     0.0      |      0.0      |      1.0      |   |  m13  |  m23  |  m33 |
     595    // ------------------------------------------------   ------------------------
     596    //
     597    // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies
     598
     599    const GLfloat wfactor = 2.0f / width;
     600    const GLfloat hfactor = -2.0f / height;
     601    GLfloat dx = transform.dx();
     602    GLfloat dy = transform.dy();
     603
     604    // Non-integer translates can have strange effects for some rendering operations such as
     605    // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid.
     606    if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) {
     607        // 0.50 needs to rounded down to 0.0 for consistency with raster engine:
     608        dx = ceilf(dx - 0.5f);
     609        dy = ceilf(dy - 0.5f);
     610    }
     611
     612    if (addOffset) {
     613        dx += 0.49f;
     614        dy += 0.49f;
     615    }
     616
     617    pmvMatrix[0][0] = (wfactor * transform.m11())  - transform.m13();
     618    pmvMatrix[1][0] = (wfactor * transform.m21())  - transform.m23();
     619    pmvMatrix[2][0] = (wfactor * dx) - transform.m33();
     620    pmvMatrix[0][1] = (hfactor * transform.m12())  + transform.m13();
     621    pmvMatrix[1][1] = (hfactor * transform.m22())  + transform.m23();
     622    pmvMatrix[2][1] = (hfactor * dy) + transform.m33();
     623    pmvMatrix[0][2] = transform.m13();
     624    pmvMatrix[1][2] = transform.m23();
     625    pmvMatrix[2][2] = transform.m33();
    418626
    419627    // 1/10000 == 0.0001, so we have good enough res to cover curves
     
    427635    // The actual data has been updated so both shader program's uniforms need updating
    428636    simpleShaderMatrixUniformDirty = true;
    429     brushShaderMatrixUniformDirty = true;
    430     imageShaderMatrixUniformDirty = true;
    431     textShaderMatrixUniformDirty = true;
     637    shaderMatrixUniformDirty = true;
     638
     639    dasher.setInvScale(inverseScale);
     640    stroker.setInvScale(inverseScale);
    432641}
    433642
     
    486695}
    487696
    488 
    489 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight)
    490 {
    491 //     qDebug("QGL2PaintEngineExPrivate::drawImage()");
    492 
    493     // We have a shader specifically for drawPixmap/drawImage...
    494     shaderManager->imageShader()->use();
    495 
    496     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
    497 
    498     if (compositionModeDirty)
    499         updateCompositionMode();
    500 
     697static inline void setCoords(GLfloat *coords, const QGLRect &rect)
     698{
     699    coords[0] = rect.left;
     700    coords[1] = rect.top;
     701    coords[2] = rect.right;
     702    coords[3] = rect.top;
     703    coords[4] = rect.right;
     704    coords[5] = rect.bottom;
     705    coords[6] = rect.left;
     706    coords[7] = rect.bottom;
     707}
     708
     709void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
     710{
     711    // Setup for texture drawing
     712    currentBrush = noBrush;
     713    shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
     714
     715    if (addOffset) {
     716        addOffset = false;
     717        matrixDirty = true;
     718    }
     719
     720    if (snapToPixelGrid) {
     721        snapToPixelGrid = false;
     722        matrixDirty = true;
     723    }
     724
     725    if (prepareForDraw(opaque))
     726        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
     727
     728    if (pattern) {
     729        QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
     730        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
     731    }
     732
     733    GLfloat dx = 1.0 / textureSize.width();
     734    GLfloat dy = 1.0 / textureSize.height();
     735
     736    QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy);
     737
     738    setCoords(staticVertexCoordinateArray, dest);
     739    setCoords(staticTextureCoordinateArray, srcTextureRect);
     740
     741    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     742}
     743
     744void QGL2PaintEngineEx::beginNativePainting()
     745{
     746    Q_D(QGL2PaintEngineEx);
     747    ensureActive();
     748    d->transferMode(BrushDrawingMode);
     749
     750    QGLContext *ctx = d->ctx;
     751    glUseProgram(0);
     752
     753#ifndef QT_OPENGL_ES_2
     754    // be nice to people who mix OpenGL 1.x code with QPainter commands
     755    // by setting modelview and projection matrices to mirror the GL 1
     756    // paint engine
     757    const QTransform& mtx = state()->matrix;
     758
     759    float mv_matrix[4][4] =
     760    {
     761        { mtx.m11(), mtx.m12(),     0, mtx.m13() },
     762        { mtx.m21(), mtx.m22(),     0, mtx.m23() },
     763        {         0,         0,     1,         0 },
     764        {  mtx.dx(),  mtx.dy(),     0, mtx.m33() }
     765    };
     766
     767    const QSize sz = d->device->size();
     768
     769    glMatrixMode(GL_PROJECTION);
     770    glLoadIdentity();
     771    glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);
     772
     773    glMatrixMode(GL_MODELVIEW);
     774    glLoadMatrixf(&mv_matrix[0][0]);
     775#else
     776    Q_UNUSED(ctx);
     777#endif
     778
     779    d->lastTextureUsed = GLuint(-1);
     780    d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
     781    d->resetGLState();
     782
     783    d->shaderManager->setDirty();
     784
     785    d->needsSync = true;
     786}
     787
     788void QGL2PaintEngineExPrivate::resetGLState()
     789{
     790    glDisable(GL_BLEND);
     791    glActiveTexture(GL_TEXTURE0);
     792    glDisable(GL_STENCIL_TEST);
     793    glDisable(GL_DEPTH_TEST);
     794    glDisable(GL_SCISSOR_TEST);
     795    glDepthMask(true);
     796    glDepthFunc(GL_LESS);
     797    glClearDepth(1);
     798}
     799
     800void QGL2PaintEngineEx::endNativePainting()
     801{
     802    Q_D(QGL2PaintEngineEx);
     803    d->needsSync = true;
     804}
     805
     806void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
     807{
     808    if (newMode == mode)
     809        return;
     810
     811    if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
     812        glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     813        glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     814        glDisableVertexAttribArray(QT_OPACITY_ATTR);
     815
     816        lastTextureUsed = GLuint(-1);
     817    }
     818
     819    if (newMode == TextDrawingMode) {
     820        glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     821        glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     822
     823        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
     824        glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
     825    }
     826
     827    if (newMode == ImageDrawingMode) {
     828        glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     829        glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     830
     831        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray);
     832        glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray);
     833    }
     834
     835    if (newMode == ImageArrayDrawingMode) {
     836        glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     837        glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     838        glEnableVertexAttribArray(QT_OPACITY_ATTR);
     839
     840        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
     841        glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
     842        glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data());
     843    }
     844
     845    // This needs to change when we implement high-quality anti-aliasing...
     846    if (newMode != TextDrawingMode)
     847        shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
     848
     849    mode = newMode;
     850}
     851
     852struct QGL2PEVectorPathCache
     853{
     854#ifdef QT_OPENGL_CACHE_AS_VBOS
     855    GLuint vbo;
     856#else
     857    float *vertices;
     858#endif
     859    int vertexCount;
     860    GLenum primitiveType;
     861    qreal iscale;
     862};
     863
     864void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data)
     865{
     866    QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
     867#ifdef QT_OPENGL_CACHE_AS_VBOS
     868    Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
     869    static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
     870#else
     871    Q_UNUSED(engine);
     872    qFree(c->vertices);
     873#endif
     874    delete c;
     875}
     876
     877// Assumes everything is configured for the brush you want to use
     878void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
     879{
     880    transferMode(BrushDrawingMode);
     881
     882    const QOpenGL2PaintEngineState *s = q->state();
     883    const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) &&
     884                              (qbrush_style(currentBrush) == Qt::SolidPattern) &&
     885                              !multisamplingAlwaysEnabled;
     886
     887    if (addOffset != newAddOffset) {
     888        addOffset = newAddOffset;
     889        matrixDirty = true;
     890    }
     891
     892    if (snapToPixelGrid) {
     893        snapToPixelGrid = false;
     894        matrixDirty = true;
     895    }
     896
     897    // Might need to call updateMatrix to re-calculate inverseScale
    501898    if (matrixDirty)
    502899        updateMatrix();
    503900
    504     if (imageShaderMatrixUniformDirty) {
    505         shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
    506         imageShaderMatrixUniformDirty = false;
    507     }
    508 
    509     shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;
    510 
    511 //    if (q->state()->opacity < 0.99f)
    512         shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity;
    513 
    514     GLfloat vertexCoords[] = {
    515         dest.left,  dest.top,
    516         dest.left,  dest.bottom,
    517         dest.right, dest.bottom,
    518         dest.right, dest.top
    519     };
    520 
    521     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    522     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
    523 
    524     GLfloat dx = 1.0 / txtWidth;
    525     GLfloat dy = 1.0 / txtHeight;
    526 
    527     QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
    528 
    529     GLfloat textureCoords[] = {
    530         srcTextureRect.left,  srcTextureRect.top,
    531         srcTextureRect.left,  srcTextureRect.bottom,
    532         srcTextureRect.right, srcTextureRect.bottom,
    533         srcTextureRect.right, srcTextureRect.top
    534     };
    535 
    536     glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
    537     glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
    538 
    539     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    540 
    541     glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
    542     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    543 }
    544 
    545 
    546 void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path)
    547 {
    548 //     qDebug("QGL2PaintEngineExPrivate::drawOutline()");
    549     if (matrixDirty)
    550         updateMatrix();
    551 
    552     pathVertexArray.clear();
    553     pathVertexArray.addPath(path, inverseScale);
    554 
    555     if (path.hasImplicitClose()) {
    556         // Close the path's outline
    557         pathVertexArray.lineToArray(path.points()[0], path.points()[1]);
    558         pathVertexArray.stops().last() += 1;
    559     }
    560 
    561     prepareForDraw();
    562     drawVertexArrays(pathVertexArray, GL_LINE_STRIP);
    563 }
    564 
    565 
    566 // Assumes everything is configured for the brush you want to use
    567 void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
    568 {
    569     if (matrixDirty)
    570         updateMatrix();
    571 
    572901    const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
    573 
    574902
    575903    // Check to see if there's any hints
    576904    if (path.shape() == QVectorPath::RectangleHint) {
    577905        QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
    578         prepareForDraw();
     906        prepareForDraw();
    579907        composite(rect);
    580     }
    581     else if (path.shape() == QVectorPath::EllipseHint) {
    582         pathVertexArray.clear();
    583         pathVertexArray.addPath(path, inverseScale);
    584         prepareForDraw();
    585         drawVertexArrays(pathVertexArray, GL_TRIANGLE_FAN);
    586     }
    587     else {
     908    } else if (path.isConvex()) {
     909
     910        if (path.isCacheable()) {
     911            QVectorPath::CacheEntry *data = path.lookupCacheData(q);
     912            QGL2PEVectorPathCache *cache;
     913
     914            if (data) {
     915                cache = (QGL2PEVectorPathCache *) data->data;
     916                // Check if scale factor is exceeded for curved paths and generate curves if so...
     917                if (path.isCurved()) {
     918                    qreal scaleFactor = cache->iscale / inverseScale;
     919                    if (scaleFactor < 0.5 || scaleFactor > 2.0) {
     920#ifdef QT_OPENGL_CACHE_AS_VBOS
     921                        glDeleteBuffers(1, &cache->vbo);
     922                        cache->vbo = 0;
     923#else
     924                        qFree(cache->vertices);
     925#endif
     926                        cache->vertexCount = 0;
     927                    }
     928                }
     929            } else {
     930                cache = new QGL2PEVectorPathCache;
     931                cache->vertexCount = 0;
     932                data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
     933            }
     934
     935            // Flatten the path at the current scale factor and fill it into the cache struct.
     936            if (!cache->vertexCount) {
     937                vertexCoordinateArray.clear();
     938                vertexCoordinateArray.addPath(path, inverseScale, false);
     939                int vertexCount = vertexCoordinateArray.vertexCount();
     940                int floatSizeInBytes = vertexCount * 2 * sizeof(float);
     941                cache->vertexCount = vertexCount;
     942                cache->primitiveType = GL_TRIANGLE_FAN;
     943                cache->iscale = inverseScale;
     944#ifdef QT_OPENGL_CACHE_AS_VBOS
     945                glGenBuffers(1, &cache->vbo);
     946                glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
     947                glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
     948#else
     949                cache->vertices = (float *) qMalloc(floatSizeInBytes);
     950                memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
     951#endif
     952            }
     953
     954            prepareForDraw(currentBrush.isOpaque());
     955            glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     956#ifdef QT_OPENGL_CACHE_AS_VBOS
     957            glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
     958            glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
     959#else
     960            glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices);
     961#endif
     962            glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
     963
     964        } else {
     965      //        printf(" - Marking path as cachable...\n");
     966            // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
     967            // ### Remove before release...
     968            static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
     969            if (do_vectorpath_cache)
     970                path.makeCacheable();
     971            vertexCoordinateArray.clear();
     972            vertexCoordinateArray.addPath(path, inverseScale, false);
     973            prepareForDraw(currentBrush.isOpaque());
     974            drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
     975        }
     976
     977    } else {
    588978        // The path is too complicated & needs the stencil technique
    589         pathVertexArray.clear();
    590         pathVertexArray.addPath(path, inverseScale);
    591 
    592         fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill());
     979        vertexCoordinateArray.clear();
     980        vertexCoordinateArray.addPath(path, inverseScale, false);
     981
     982        fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
     983
     984        glStencilMask(0xff);
     985        glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
     986
     987        if (q->state()->clipTestEnabled) {
     988            // Pass when high bit is set, replace stencil value with current clip
     989            glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
     990        } else if (path.hasWindingFill()) {
     991            // Pass when any bit is set, replace stencil value with 0
     992            glStencilFunc(GL_NOTEQUAL, 0, 0xff);
     993        } else {
     994            // Pass when high bit is set, replace stencil value with 0
     995            glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
     996        }
     997        prepareForDraw(currentBrush.isOpaque());
    593998
    594999        // Stencil the brush onto the dest buffer
    595         glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0
    596         glEnable(GL_STENCIL_TEST);
    597         prepareForDraw();
    598         composite(pathVertexArray.boundingRect());
    599         glDisable(GL_STENCIL_TEST);
    600 
    601         cleanStencilBuffer(pathVertexArray.boundingRect());
    602     }
    603 }
    604 
    605 
    606 void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill)
    607 {
     1000        composite(vertexCoordinateArray.boundingRect());
     1001        glStencilMask(0);
     1002        updateClipScissorTest();
     1003    }
     1004}
     1005
     1006
     1007void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
     1008                                                          int count,
     1009                                                          int *stops,
     1010                                                          int stopCount,
     1011                                                          const QGLRect &bounds,
     1012                                                          StencilFillMode mode)
     1013{
     1014    Q_ASSERT(count || stops);
     1015
    6081016//     qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()");
    609     if (stencilBuferDirty) {
    610         // Clear the stencil buffer to zeros
    611         glDisable(GL_STENCIL_TEST);
    612         glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything.
     1017   
     1018
     1019   
     1020       
    6131021        glClearStencil(0); // Clear to zero
    614         glClear(GL_STENCIL_BUFFER_BIT);
    615         stencilBuferDirty = false;
     1022        for (int i = 0; i < clearRegion.size(); ++i) {
     1023#ifndef QT_GL_NO_SCISSOR_TEST
     1024            setScissor(clearRegion.at(i));
     1025#endif
     1026            glClear(GL_STENCIL_BUFFER_BIT);
     1027        }
     1028
     1029        dirtyStencilRegion -= currentScissorBounds;
     1030
     1031#ifndef QT_GL_NO_SCISSOR_TEST
     1032        updateClipScissorTest();
     1033#endif
    6161034    }
    6171035
    6181036    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
    619     glStencilMask(0xFFFF); // Enable stencil writes
    620     glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
    621 
    622     // Setup the stencil op:
    623     if (useWindingFill) {
    624         glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); // Inc. for front-facing triangle
    625         glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); //Dec. for back-facing "holes"
    626     } else
     1037    useSimpleShader();
     1038    glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
     1039
     1040    if (mode == WindingFillMode) {
     1041        Q_ASSERT(stops && !count);
     1042        if (q->state()->clipTestEnabled) {
     1043            // Flatten clip values higher than current clip, and set high bit to match current clip
     1044            glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
     1045            glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
     1046            composite(bounds);
     1047
     1048            glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT);
     1049        } else if (!stencilClean) {
     1050            // Clear stencil buffer within bounding rect
     1051            glStencilFunc(GL_ALWAYS, 0, 0xff);
     1052            glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
     1053            composite(bounds);
     1054        }
     1055
     1056        // Inc. for front-facing triangle
     1057        glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
     1058        // Dec. for back-facing "holes"
     1059        glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP);
     1060        glStencilMask(~GL_STENCIL_HIGH_BIT);
     1061        drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
     1062
     1063        if (q->state()->clipTestEnabled) {
     1064            // Clear high bit of stencil outside of path
     1065            glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
     1066            glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
     1067            glStencilMask(GL_STENCIL_HIGH_BIT);
     1068            composite(bounds);
     1069        }
     1070    } else if (mode == OddEvenFillMode) {
     1071        glStencilMask(GL_STENCIL_HIGH_BIT);
    6271072        glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
    628 
    629     // No point in using a fancy gradiant shader for writing into the stencil buffer!
    630     useSimpleShader();
    631 
    632     glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
    633     glDisable(GL_BLEND);
    634 
    635     // Draw the vertecies into the stencil buffer:
    636     drawVertexArrays(vertexArray, GL_TRIANGLE_FAN);
     1073        drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
     1074
     1075    } else { // TriStripStrokeFillMode
     1076        Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
     1077        glStencilMask(GL_STENCIL_HIGH_BIT);
     1078#if 0
     1079        glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
     1080        glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1081        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
     1082        glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
     1083        glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1084#else
     1085
     1086        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
     1087        if (q->state()->clipTestEnabled) {
     1088            glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
     1089                          ~GL_STENCIL_HIGH_BIT);
     1090        } else {
     1091            glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
     1092        }
     1093        glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1094        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
     1095        glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
     1096        glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1097#endif
     1098    }
    6371099
    6381100    // Enable color writes & disable stencil writes
    6391101    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    640     glStencilMask(0);
    641 }
    642 
    643 void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area)
    644 {
    645 //     qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()");
     1102}
     1103
     1104/*
     1105    If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1,
     1106    restore the stencil buffer to a pristine state.  The current clip region
     1107    is set to 1, and the rest to 0.
     1108*/
     1109void QGL2PaintEngineExPrivate::resetClipIfNeeded()
     1110{
     1111    if (maxClip != (GL_STENCIL_HIGH_BIT - 1))
     1112        return;
     1113
     1114    Q_Q(QGL2PaintEngineEx);
     1115
    6461116    useSimpleShader();
    647 
    648     GLfloat rectVerts[] = {
    649         area.left,  area.top,
    650         area.left,  area.bottom,
    651         area.right, area.bottom,
    652         area.right, area.top
    653     };
    654 
    655     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    656     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);
    657 
    6581117    glEnable(GL_STENCIL_TEST);
    659     glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
    660 
    661     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
    662     glStencilMask(0xFFFF); // Enable writing to stencil buffer
    663     glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer
    664 
    665     glDisable(GL_BLEND);
    666 
    667     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    668 
    669     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    670 
    671     // Enable color writes & disable stencil writes
     1118    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
     1119
     1120    QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height));
     1121    QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
     1122
     1123    // Set high bit on clip region
     1124    glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff);
     1125    glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
     1126    glStencilMask(GL_STENCIL_HIGH_BIT);
     1127    composite(rect);
     1128
     1129    // Reset clipping to 1 and everything else to zero
     1130    glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT);
     1131    glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE);
     1132    glStencilMask(0xff);
     1133    composite(rect);
     1134
     1135    q->state()->currentClip = 1;
     1136    q->state()->canRestoreClip = false;
     1137
     1138    maxClip = 1;
     1139
     1140    glStencilMask(0x0);
    6721141    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    673     glStencilMask(0);
    674     glDisable(GL_STENCIL_TEST);
    675 }
    676 
    677 void QGL2PaintEngineExPrivate::prepareForDraw()
    678 {
    679     if (brushTextureDirty)
     1142}
     1143
     1144bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
     1145{
     1146    if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
    6801147        updateBrushTexture();
    6811148
     
    6831150        updateCompositionMode();
    6841151
    685     if (shaderManager->useCorrectShaderProg()) {
     1152    if (matrixDirty)
     1153        updateMatrix();
     1154
     1155    const bool stateHasOpacity = q->state()->opacity < 0.99f;
     1156    if (q->state()->composition_mode == QPainter::CompositionMode_Source
     1157        || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver
     1158            && srcPixelsAreOpaque && !stateHasOpacity))
     1159    {
     1160        glDisable(GL_BLEND);
     1161    } else {
     1162        glEnable(GL_BLEND);
     1163    }
     1164
     1165    QGLEngineShaderManager::OpacityMode opacityMode;
     1166    if (mode == ImageArrayDrawingMode) {
     1167        opacityMode = QGLEngineShaderManager::AttributeOpacity;
     1168    } else {
     1169        opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity
     1170                                      : QGLEngineShaderManager::NoOpacity;
     1171        if (stateHasOpacity && (mode != ImageDrawingMode)) {
     1172            // Using a brush
     1173            bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
     1174                                  (currentBrush.style() <= Qt::DiagCrossPattern);
     1175
     1176            if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern)
     1177                opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader
     1178        }
     1179    }
     1180    shaderManager->setOpacityMode(opacityMode);
     1181
     1182    bool changed = shaderManager->useCorrectShaderProg();
     1183    // If the shader program needs changing, we change it and mark all uniforms as dirty
     1184    if (changed) {
    6861185        // The shader program has changed so mark all uniforms as dirty:
    6871186        brushUniformsDirty = true;
    688         brushShaderMatrixUniformDirty = true;
    689     }
    690 
    691     if (brushUniformsDirty)
     1187        shaderMatrixUniformDirty = true;
     1188        opacityUniformDirty = true;
     1189    }
     1190
     1191    if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
    6921192        updateBrushUniforms();
    6931193
    694     if (brushShaderMatrixUniformDirty) {
    695         shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
    696         brushShaderMatrixUniformDirty = false;
    697     }
    698 
    699     if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque())
    700         glEnable(GL_BLEND);
    701     else
    702         glDisable(GL_BLEND);
     1194    if (shaderMatrixUniformDirty) {
     1195        glUniformMatrix3fv(location(QGLEngineShaderManager::PmvMatrix), 1, GL_FALSE, (GLfloat*)pmvMatrix);
     1196        shaderMatrixUniformDirty = false;
     1197    }
     1198
     1199    if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
     1200        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
     1201        opacityUniformDirty = false;
     1202    }
     1203
     1204    return changed;
    7031205}
    7041206
     
    7221224
    7231225// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
    724 void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive)
     1226void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
     1227                                                GLenum primitive)
    7251228{
    7261229    // Now setup the pointer to the vertex array:
    7271230    glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    728     glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data());
     1231    glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, );
    7291232
    7301233    int previousStop = 0;
    731     foreach(int stop, vertexArray.stops()) {
     1234    for (int i=0; i<stopCount; ++i) {
     1235        int stop = stops[i];
    7321236/*
    7331237        qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
     
    7411245}
    7421246
    743 
    744 
    745 
    746 
    7471247/////////////////////////////////// Public Methods //////////////////////////////////////////
    7481248
     
    7501250    : QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this)))
    7511251{
    752     qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()");
    753 
    7541252}
    7551253
     
    7621260    Q_D(QGL2PaintEngineEx);
    7631261
    764     QTime startTime = QTime::currentTime();
    765 
    766     d->setBrush(&brush);
     1262    if (qbrush_style(brush) == Qt::NoBrush)
     1263        return;
     1264    ensureActive();
     1265    d->setBrush(brush);
    7671266    d->fill(path);
    768     d->setBrush(&(state()->brush)); // reset back to the state's brush
    769 }
     1267}
     1268
     1269extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
     1270
    7701271
    7711272void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
     
    7731274    Q_D(QGL2PaintEngineEx);
    7741275
    775     if (pen.style() == Qt::NoPen)
     1276    const QBrush &penBrush = qpen_brush(pen);
     1277    if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
    7761278        return;
    7771279
    778     if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) )
    779     {
    780         // We only handle solid, cosmetic pens with a width of 1 pixel
    781         const QBrush& brush = pen.brush();
    782         d->setBrush(&brush);
    783 
    784         if (pen.widthF() < 0.01f)
    785             glLineWidth(1.0);
    786         else
    787             glLineWidth(pen.widthF());
    788 
    789         d->drawOutline(path);
    790         d->setBrush(&(state()->brush));
    791     } else
    792         return QPaintEngineEx::stroke(path, pen);
    793 
    794 }
    795 
    796 void QGL2PaintEngineEx::penChanged()
    797 {
    798 //    qDebug("QGL2PaintEngineEx::penChanged() not implemented!");
    799 }
    800 
    801 
    802 void QGL2PaintEngineEx::brushChanged()
    803 {
    804 //    qDebug("QGL2PaintEngineEx::brushChanged()");
    805     Q_D(QGL2PaintEngineEx);
    806     d->setBrush(&(state()->brush));
    807 }
    808 
    809 void QGL2PaintEngineEx::brushOriginChanged()
    810 {
    811 //    qDebug("QGL2PaintEngineEx::brushOriginChanged()");
    812     Q_D(QGL2PaintEngineEx);
    813     d->brushUniformsDirty = true;
    814 }
     1280    QOpenGL2PaintEngineState *s = state();
     1281    if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
     1282        // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
     1283        QPaintEngineEx::stroke(path, pen);
     1284        return;
     1285    }
     1286
     1287    ensureActive();
     1288    d->setBrush(penBrush);
     1289    d->stroke(path, pen);
     1290}
     1291
     1292void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen)
     1293{
     1294    const QOpenGL2PaintEngineState *s = q->state();
     1295    const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled;
     1296    if (addOffset != newAddOffset) {
     1297        addOffset = newAddOffset;
     1298        matrixDirty = true;
     1299    }
     1300
     1301    if (snapToPixelGrid) {
     1302        snapToPixelGrid = false;
     1303        matrixDirty = true;
     1304    }
     1305
     1306    const Qt::PenStyle penStyle = qpen_style(pen);
     1307    const QBrush &penBrush = qpen_brush(pen);
     1308    const bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
     1309
     1310    transferMode(BrushDrawingMode);
     1311
     1312    // updateMatrix() is responsible for setting the inverse scale on
     1313    // the strokers, so we need to call it here and not wait for
     1314    // prepareForDraw() down below.
     1315    updateMatrix();
     1316
     1317    if (penStyle == Qt::SolidLine) {
     1318        stroker.process(path, pen);
     1319
     1320    } else { // Some sort of dash
     1321        dasher.process(path, pen);
     1322
     1323        QVectorPath dashStroke(dasher.points(),
     1324                               dasher.elementCount(),
     1325                               dasher.elementTypes());
     1326        stroker.process(dashStroke, pen);
     1327    }
     1328
     1329    if (opaque) {
     1330        prepareForDraw(opaque);
     1331        glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1332        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, stroker.vertices());
     1333        glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
     1334
     1335//         QBrush b(Qt::green);
     1336//         d->setBrush(&b);
     1337//         d->prepareForDraw(true);
     1338//         glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
     1339
     1340        glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1341
     1342    } else {
     1343        qreal width = qpen_widthf(pen) / 2;
     1344        if (width == 0)
     1345            width = 0.5;
     1346        qreal extra = pen.joinStyle() == Qt::MiterJoin
     1347                      ? qMax(pen.miterLimit() * width, width)
     1348                      : width;
     1349
     1350        if (pen.isCosmetic())
     1351            extra = extra * inverseScale;
     1352
     1353        QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
     1354
     1355        fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2,
     1356                                      0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode);
     1357
     1358        glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
     1359
     1360        // Pass when any bit is set, replace stencil value with 0
     1361        glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
     1362        prepareForDraw(false);
     1363
     1364        // Stencil the brush onto the dest buffer
     1365        composite(bounds);
     1366
     1367        glStencilMask(0);
     1368
     1369        updateClipScissorTest();
     1370    }
     1371}
     1372
     1373void QGL2PaintEngineEx::penChanged() { }
     1374void QGL2PaintEngineEx::brushChanged() { }
     1375void QGL2PaintEngineEx::brushOriginChanged() { }
    8151376
    8161377void QGL2PaintEngineEx::opacityChanged()
     
    8181379//    qDebug("QGL2PaintEngineEx::opacityChanged()");
    8191380    Q_D(QGL2PaintEngineEx);
     1381
    8201382
    8211383    Q_ASSERT(d->shaderManager);
    822     d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);
    8231384    d->brushUniformsDirty = true;
     1385
    8241386}
    8251387
     
    8281390//     qDebug("QGL2PaintEngineEx::compositionModeChanged()");
    8291391    Q_D(QGL2PaintEngineEx);
     1392
    8301393    d->compositionModeDirty = true;
    8311394}
     
    8331396void QGL2PaintEngineEx::renderHintsChanged()
    8341397{
     1398
     1399
     1400
     1401
     1402
     1403
     1404
     1405
     1406
     1407
     1408
     1409
     1410
    8351411//    qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
    8361412}
     
    8401416    Q_D(QGL2PaintEngineEx);
    8411417    d->matrixDirty = true;
     1418
    8421419}
    8431420
     
    8461423{
    8471424    Q_D(QGL2PaintEngineEx);
    848     glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
    849 
    850     d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true);
    851 
    852     //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment
    853     if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel())
    854         glEnable(GL_BLEND);
    855     else
    856         glDisable(GL_BLEND);
    857 
    858     d->drawTexture(dest, src, pixmap.width(), pixmap.height());
     1425    ensureActive();
     1426    d->transferMode(ImageDrawingMode);
     1427
     1428    QGLContext *ctx = d->ctx;
     1429    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
     1430    QGLTexture *texture =
     1431        ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
     1432                                   QGLContext::InternalBindOption
     1433                                   | QGLContext::CanFlipNativePixmapBindOption);
     1434
     1435    GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top();
     1436    GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom();
     1437    QGLRect srcRect(src.left(), top, src.right(), bottom);
     1438
     1439    bool isBitmap = pixmap.isQBitmap();
     1440    bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel();
     1441
     1442    d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
     1443                           state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
     1444    d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap);
    8591445}
    8601446
     
    8631449{
    8641450    Q_D(QGL2PaintEngineEx);
    865     glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
    866     d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
    867 
    868     if ((state()->opacity < 0.99f) || image.hasAlphaChannel())
    869         glEnable(GL_BLEND);
    870     else
    871         glDisable(GL_BLEND);
    872 
    873     d->drawTexture(dest, src, image.width(), image.height());
     1451    ensureActive();
     1452    d->transferMode(ImageDrawingMode);
     1453
     1454    QGLContext *ctx = d->ctx;
     1455    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
     1456    QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
     1457    GLuint id = texture->id;
     1458
     1459    d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
     1460                           state()->renderHints & QPainter::SmoothPixmapTransform, id);
     1461    d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
     1462}
     1463
     1464void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
     1465{
     1466    Q_D(QGL2PaintEngineEx);
     1467    ensureActive();
     1468    d->transferMode(ImageDrawingMode);
     1469
     1470#ifndef QT_OPENGL_ES_2
     1471    QGLContext *ctx = d->ctx;
     1472#endif
     1473    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
     1474    glBindTexture(GL_TEXTURE_2D, textureId);
     1475
     1476    QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top());
     1477
     1478    d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
     1479                           state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
     1480    d->drawTexture(dest, srcRect, size, false);
    8741481}
    8751482
    8761483void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
    8771484{
    878     QOpenGLPaintEngineState *s = state();
     1485    Q_D(QGL2PaintEngineEx);
     1486
     1487    ensureActive();
     1488    QOpenGL2PaintEngineState *s = state();
    8791489
    8801490    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
    8811491
    882     bool drawCached = true;
    883 
    884     if (state()->pen.brush().style() != Qt::SolidPattern)
     1492    QTransform::TransformationType txtype = s->matrix.type();
     1493
     1494    float det = s->matrix.determinant();
     1495    bool drawCached = txtype < QTransform::TxProject;
     1496
     1497    // don't try to cache huge fonts or vastly transformed fonts
     1498    const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
     1499    if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f)
    8851500        drawCached = false;
    8861501
    887     if (s->matrix.type() > QTransform::TxTranslate)
     1502    QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
     1503                                            ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
     1504                                            : d->glyphCacheType;
     1505
     1506    if (txtype > QTransform::TxTranslate)
     1507        glyphType = QFontEngineGlyphCache::Raster_A8;
     1508
     1509    if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
     1510        && state()->composition_mode != QPainter::CompositionMode_Source
     1511        && state()->composition_mode != QPainter::CompositionMode_SourceOver)
     1512    {
    8881513        drawCached = false;
    889 
    890     // don't try to cache huge fonts
    891     if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64)
    892         drawCached = false;
     1514    }
    8931515
    8941516    if (drawCached) {
    895         drawCachedGlyphs(p, ti);
     1517        d, ti);
    8961518        return;
    8971519    }
     
    9001522}
    9011523
    902 void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
    903 {
    904     Q_D(QGL2PaintEngineEx);
    905     QOpenGLPaintEngineState *s = state();
     1524void QGL2PaintEngineEx
     1525                                                const QTextItemInt &ti)
     1526{
     1527    Q);
    9061528
    9071529    QVarLengthArray<QFixedPoint> positions;
    9081530    QVarLengthArray<glyph_t> glyphs;
    909     QTransform matrix;
    910     matrix.translate(p.x(), p.y());
     1531    QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
    9111532    ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
    9121533
    913     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
    914         ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
    915         : QFontEngineGlyphCache::Raster_A8;
    916 
    917     QImageTextureGlyphCache *cache =
    918         (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix);
    919     if (!cache) {
    920         cache = new QImageTextureGlyphCache(glyphType, s->matrix);
    921         ti.fontEngine->setGlyphCache(glyphType, cache);
    922     }
    923 
     1534    QGLTextureGlyphCache *cache =
     1535            (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform());
     1536
     1537    if (!cache || cache->cacheType() != glyphType) {
     1538        cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
     1539        ti.fontEngine->setGlyphCache(ctx, cache);
     1540    }
     1541
     1542    cache->setPaintEnginePrivate(this);
    9241543    cache->populate(ti, glyphs, positions);
    9251544
    926     const QImage &image = cache->image();
     1545    if (cache->width() == 0 || cache->height() == 0)
     1546        return;
     1547
     1548    transferMode(TextDrawingMode);
     1549
    9271550    int margin = cache->glyphMargin();
    9281551
    929     glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
    930     d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
    931 
    932     glEnable(GL_BLEND);
    933 
    934     d->shaderManager->textShader()->use();
    935     d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
    936 
    937     if (d->compositionModeDirty)
    938         d->updateCompositionMode();
    939 
    940     if (d->matrixDirty)
    941         d->updateMatrix();
    942 
    943     if (d->textShaderMatrixUniformDirty) {
    944         d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix;
    945         d->textShaderMatrixUniformDirty = false;
    946     }
    947 
    948     d->shaderManager->textShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;
    949     QColor col = d->premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity);
    950     d->shaderManager->textShader()->uniforms()[QLatin1String("fragmentColor")] = col;
    951 
    952     GLfloat dx = 1.0 / image.width();
    953     GLfloat dy = 1.0 / image.height();
    954 
    955     glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    956     glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     1552    GLfloat dx = 1.0 / cache->width();
     1553    GLfloat dy = 1.0 / cache->height();
     1554
     1555    QGLPoint *oldVertexCoordinateDataPtr = vertexCoordinateArray.data();
     1556    QGLPoint *oldTextureCoordinateDataPtr = textureCoordinateArray.data();
     1557
     1558    vertexCoordinateArray.clear();
     1559    textureCoordinateArray.clear();
     1560
    9571561    for (int i=0; i<glyphs.size(); ++i) {
    9581562        const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
     
    9601564        int y = positions[i].y.toInt() - c.baseLineY - margin;
    9611565
    962         QGLRect dest = QRectF(x, y, c.w, c.h);
    963         QGLRect src = QRectF(c.x, c.y, c.w, c.h);
    964 
    965         GLfloat vertexCoords[] = {
    966             dest.left,  dest.top,
    967             dest.left,  dest.bottom,
    968             dest.right, dest.bottom,
    969             dest.right, dest.top
    970         };
    971 
    972         glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
    973 
    974         QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
    975 
    976         GLfloat textureCoords[] = {
    977             srcTextureRect.left,  srcTextureRect.top,
    978             srcTextureRect.left,  srcTextureRect.bottom,
    979             srcTextureRect.right, srcTextureRect.bottom,
    980             srcTextureRect.right, srcTextureRect.top
    981         };
    982 
    983         glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
    984 
    985         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    986     }
    987     glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
    988     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     1566        vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
     1567        textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
     1568    }
     1569
     1570    if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
     1571        glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
     1572    if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
     1573        glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
     1574
     1575    if (addOffset) {
     1576        addOffset = false;
     1577        matrixDirty = true;
     1578    }
     1579    if (!snapToPixelGrid) {
     1580        snapToPixelGrid = true;
     1581        matrixDirty = true;
     1582    }
     1583
     1584    QBrush pensBrush = q->state()->pen.brush();
     1585    setBrush(pensBrush);
     1586
     1587    if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
     1588
     1589        // Subpixel antialiasing without gamma correction
     1590
     1591        QPainter::CompositionMode compMode = q->state()->composition_mode;
     1592        Q_ASSERT(compMode == QPainter::CompositionMode_Source
     1593            || compMode == QPainter::CompositionMode_SourceOver);
     1594
     1595        shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass1);
     1596
     1597        if (pensBrush.style() == Qt::SolidPattern) {
     1598            // Solid patterns can get away with only one pass.
     1599            QColor c = pensBrush.color();
     1600            qreal oldOpacity = q->state()->opacity;
     1601            if (compMode == QPainter::CompositionMode_Source) {
     1602                c = qt_premultiplyColor(c, q->state()->opacity);
     1603                q->state()->opacity = 1;
     1604                opacityUniformDirty = true;
     1605            }
     1606
     1607            compositionModeDirty = false; // I can handle this myself, thank you very much
     1608            prepareForDraw(false); // Text always causes src pixels to be transparent
     1609
     1610            // prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset.
     1611            if (compMode == QPainter::CompositionMode_Source) {
     1612                q->state()->opacity = oldOpacity;
     1613                opacityUniformDirty = true;
     1614            }
     1615
     1616            glEnable(GL_BLEND);
     1617            glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
     1618            glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
     1619        } else {
     1620            // Other brush styles need two passes.
     1621
     1622            qreal oldOpacity = q->state()->opacity;
     1623            if (compMode == QPainter::CompositionMode_Source) {
     1624                q->state()->opacity = 1;
     1625                opacityUniformDirty = true;
     1626                pensBrush = Qt::white;
     1627                setBrush(pensBrush);
     1628            }
     1629
     1630            compositionModeDirty = false; // I can handle this myself, thank you very much
     1631            prepareForDraw(false); // Text always causes src pixels to be transparent
     1632            glEnable(GL_BLEND);
     1633            glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
     1634
     1635            glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
     1636            glBindTexture(GL_TEXTURE_2D, cache->texture());
     1637            updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
     1638
     1639            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
     1640            glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
     1641
     1642            shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
     1643
     1644            if (compMode == QPainter::CompositionMode_Source) {
     1645                q->state()->opacity = oldOpacity;
     1646                opacityUniformDirty = true;
     1647                pensBrush = q->state()->pen.brush();
     1648                setBrush(pensBrush);
     1649            }
     1650
     1651            compositionModeDirty = false;
     1652            prepareForDraw(false); // Text always causes src pixels to be transparent
     1653            glEnable(GL_BLEND);
     1654            glBlendFunc(GL_ONE, GL_ONE);
     1655        }
     1656        compositionModeDirty = true;
     1657    } else {
     1658        // Greyscale/mono glyphs
     1659
     1660        shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
     1661        prepareForDraw(false); // Text always causes src pixels to be transparent
     1662    }
     1663    //### TODO: Gamma correction
     1664
     1665    glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
     1666    glBindTexture(GL_TEXTURE_2D, cache->texture());
     1667    updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
     1668
     1669    shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
     1670    glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
     1671}
     1672
     1673void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
     1674{
     1675    Q_D(QGL2PaintEngineEx);
     1676    // Use fallback for extended composition modes.
     1677    if (state()->composition_mode > QPainter::CompositionMode_Plus) {
     1678        QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
     1679        return;
     1680    }
     1681
     1682    ensureActive();
     1683    d->drawPixmaps(drawingData, dataCount, pixmap, hints);
     1684}
     1685
     1686
     1687void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
     1688{
     1689    GLfloat dx = 1.0f / pixmap.size().width();
     1690    GLfloat dy = 1.0f / pixmap.size().height();
     1691
     1692    vertexCoordinateArray.clear();
     1693    textureCoordinateArray.clear();
     1694    opacityArray.reset();
     1695
     1696    if (addOffset) {
     1697        addOffset = false;
     1698        matrixDirty = true;
     1699    }
     1700
     1701    if (snapToPixelGrid) {
     1702        snapToPixelGrid = false;
     1703        matrixDirty = true;
     1704    }
     1705
     1706    bool allOpaque = true;
     1707
     1708    for (int i = 0; i < dataCount; ++i) {
     1709        qreal s = 0;
     1710        qreal c = 1;
     1711        if (drawingData[i].rotation != 0) {
     1712            s = qFastSin(drawingData[i].rotation * Q_PI / 180);
     1713            c = qFastCos(drawingData[i].rotation * Q_PI / 180);
     1714        }
     1715
     1716        qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
     1717        qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
     1718        QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
     1719        QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
     1720
     1721        vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
     1722        vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
     1723        vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
     1724        vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
     1725        vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
     1726        vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
     1727
     1728        QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
     1729                    drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
     1730
     1731        textureCoordinateArray.lineToArray(src.right, src.bottom);
     1732        textureCoordinateArray.lineToArray(src.right, src.top);
     1733        textureCoordinateArray.lineToArray(src.left, src.top);
     1734        textureCoordinateArray.lineToArray(src.left, src.top);
     1735        textureCoordinateArray.lineToArray(src.left, src.bottom);
     1736        textureCoordinateArray.lineToArray(src.right, src.bottom);
     1737
     1738        qreal opacity = drawingData[i].opacity * q->state()->opacity;
     1739        opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
     1740        allOpaque &= (opacity >= 0.99f);
     1741    }
     1742
     1743    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
     1744    QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
     1745                                                     QGLContext::InternalBindOption
     1746                                                     | QGLContext::CanFlipNativePixmapBindOption);
     1747
     1748    if (texture->options & QGLContext::InvertedYBindOption) {
     1749        // Flip texture y-coordinate.
     1750        QGLPoint *data = textureCoordinateArray.data();
     1751        for (int i = 0; i < 6 * dataCount; ++i)
     1752            data[i].y = 1 - data[i].y;
     1753    }
     1754
     1755    transferMode(ImageArrayDrawingMode);
     1756
     1757    bool isBitmap = pixmap.isQBitmap();
     1758    bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
     1759
     1760    updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
     1761                           q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
     1762
     1763    // Setup for texture drawing
     1764    currentBrush = noBrush;
     1765    shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
     1766    if (prepareForDraw(isOpaque))
     1767        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
     1768
     1769    if (isBitmap) {
     1770        QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
     1771        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
     1772    }
     1773
     1774    glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
    9891775}
    9901776
     
    9941780
    9951781//     qDebug("QGL2PaintEngineEx::begin()");
    996 
    997     QGLWidget* widget = static_cast<QGLWidget*>(pdev);
    998     d->ctx = const_cast<QGLContext*>(widget->context());
    999     d->ctx->makeCurrent();
    1000     d->width = widget->width();
    1001     d->height = widget->height();
    1002 
    1003     if (!d->shaderManager)
    1004         d->shaderManager = new QGLPEXShaderManager(d->ctx);
    1005 
    1006     glViewport(0, 0, d->width, d->height);
    1007 
    1008 //     glClearColor(0.0, 1.0, 0.0, 1.0);
    1009 //     glClear(GL_COLOR_BUFFER_BIT);
    1010 //     d->ctx->swapBuffers();
    1011 //     qDebug("You should see green now");
    1012 //     sleep(5);
    1013 
     1782    if (pdev->devType() == QInternal::OpenGL)
     1783        d->device = static_cast<QGLPaintDevice*>(pdev);
     1784    else
     1785        d->device = QGLPaintDevice::getDevice(pdev);
     1786
     1787    if (!d->device)
     1788        return false;
     1789
     1790    d->ctx = d->device->context();
     1791    d->ctx->d_ptr->active_engine = this;
     1792
     1793    const QSize sz = d->device->size();
     1794    d->width = sz.width();
     1795    d->height = sz.height();
     1796    d->mode = BrushDrawingMode;
    10141797    d->brushTextureDirty = true;
    10151798    d->brushUniformsDirty = true;
    10161799    d->matrixDirty = true;
    10171800    d->compositionModeDirty = true;
    1018     d->stencilBuferDirty = true;
    1019 
    1020     d->use_system_clip = !systemClip().isEmpty();
    1021 
     1801    d->opacityUniformDirty = true;
     1802    d->needsSync = true;
     1803    d->useSystemClip = !systemClip().isEmpty();
     1804    d->currentBrush = QBrush();
     1805
     1806    d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
     1807    d->stencilClean = true;
     1808
     1809    // Calling begin paint should make the correct context current. So, any
     1810    // code which calls into GL or otherwise needs a current context *must*
     1811    // go after beginPaint:
     1812    d->device->beginPaint();
     1813
     1814#if !defined(QT_OPENGL_ES_2)
     1815    bool success = qt_resolve_version_2_0_functions(d->ctx)
     1816                   && qt_resolve_buffer_extensions(d->ctx);
     1817    Q_ASSERT(success);
     1818    Q_UNUSED(success);
     1819#endif
     1820
     1821    d->shaderManager = new QGLEngineShaderManager(d->ctx);
     1822
     1823    glDisable(GL_STENCIL_TEST);
    10221824    glDisable(GL_DEPTH_TEST);
     1825
     1826
     1827
     1828
     1829
     1830
     1831
     1832
     1833
     1834
     1835
     1836
     1837
     1838
     1839
     1840
     1841
     1842
     1843
     1844
     1845
     1846
    10231847
    10241848    return true;
     
    10281852{
    10291853    Q_D(QGL2PaintEngineEx);
    1030     d->ctx->swapBuffers();
     1854    QGLContext *ctx = d->ctx;
     1855
     1856    glUseProgram(0);
     1857    d->transferMode(BrushDrawingMode);
     1858    d->device->endPaint();
     1859
     1860#if defined(Q_WS_X11)
     1861    // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture
     1862    // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes
     1863    // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we
     1864    // reference all QPixmaps which have been bound to stop them being deleted and only deref
     1865    // them here, after swapBuffers, where they can be safely deleted.
     1866    ctx->d_func()->boundPixmaps.clear();
     1867#endif
     1868    d->ctx->d_ptr->active_engine = 0;
     1869
     1870    d->resetGLState();
     1871
     1872    delete d->shaderManager;
     1873    d->shaderManager = 0;
     1874
     1875#ifdef QT_OPENGL_CACHE_AS_VBOS
     1876    if (!d->unusedVBOSToClean.isEmpty()) {
     1877        glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
     1878        d->unusedVBOSToClean.clear();
     1879    }
     1880#endif
     1881
    10311882    return false;
    10321883}
    10331884
    1034 
    1035 /////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine //////////////////////////////////////////
     1885void QGL2PaintEngineEx::ensureActive()
     1886{
     1887    Q_D(QGL2PaintEngineEx);
     1888    QGLContext *ctx = d->ctx;
     1889
     1890    if (isActive() && ctx->d_ptr->active_engine != this) {
     1891        ctx->d_ptr->active_engine = this;
     1892        d->needsSync = true;
     1893    }
     1894
     1895    d->device->ensureActiveTarget();
     1896
     1897    if (d->needsSync) {
     1898        d->transferMode(BrushDrawingMode);
     1899        glViewport(0, 0, d->width, d->height);
     1900        d->needsSync = false;
     1901        d->shaderManager->setDirty();
     1902        setState(state());
     1903    }
     1904}
     1905
     1906void QGL2PaintEngineExPrivate::updateClipScissorTest()
     1907{
     1908    Q_Q(QGL2PaintEngineEx);
     1909    if (q->state()->clipTestEnabled) {
     1910        glEnable(GL_STENCIL_TEST);
     1911        glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
     1912    } else {
     1913        glDisable(GL_STENCIL_TEST);
     1914        glStencilFunc(GL_ALWAYS, 0, 0xff);
     1915    }
     1916
     1917#ifdef QT_GL_NO_SCISSOR_TEST
     1918    currentScissorBounds = QRect(0, 0, width, height);
     1919#else
     1920    QRect bounds = q->state()->rectangleClip;
     1921    if (!q->state()->clipEnabled) {
     1922        if (useSystemClip)
     1923            bounds = systemClip.boundingRect();
     1924        else
     1925            bounds = QRect(0, 0, width, height);
     1926    } else {
     1927        if (useSystemClip)
     1928            bounds = bounds.intersected(systemClip.boundingRect());
     1929        else
     1930            bounds = bounds.intersected(QRect(0, 0, width, height));
     1931    }
     1932
     1933    currentScissorBounds = bounds;
     1934
     1935    if (bounds == QRect(0, 0, width, height)) {
     1936        glDisable(GL_SCISSOR_TEST);
     1937    } else {
     1938        glEnable(GL_SCISSOR_TEST);
     1939        setScissor(bounds);
     1940    }
     1941#endif
     1942}
     1943
     1944void QGL2PaintEngineExPrivate::setScissor(const QRect &rect)
     1945{
     1946    const int left = rect.left();
     1947    const int width = rect.width();
     1948    const int bottom = height - (rect.top() + rect.height());
     1949    const int height = rect.height();
     1950
     1951    glScissor(left, bottom, width, height);
     1952}
    10361953
    10371954void QGL2PaintEngineEx::clipEnabledChanged()
     
    10391956    Q_D(QGL2PaintEngineEx);
    10401957
    1041     d->updateDepthClip();
     1958    state()->clipChanged = true;
     1959
     1960    if (painter()->hasClipping())
     1961        d->regenerateClip();
     1962    else
     1963        d->systemStateChanged();
     1964}
     1965
     1966void QGL2PaintEngineExPrivate::clearClip(uint value)
     1967{
     1968    dirtyStencilRegion -= currentScissorBounds;
     1969
     1970    glStencilMask(0xff);
     1971    glClearStencil(value);
     1972    glClear(GL_STENCIL_BUFFER_BIT);
     1973    glStencilMask(0x0);
     1974
     1975    q->state()->needsClipBufferClear = false;
     1976}
     1977
     1978void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
     1979{
     1980    transferMode(BrushDrawingMode);
     1981
     1982    if (addOffset) {
     1983        addOffset = false;
     1984        matrixDirty = true;
     1985    }
     1986    if (snapToPixelGrid) {
     1987        snapToPixelGrid = false;
     1988        matrixDirty = true;
     1989    }
     1990
     1991    if (matrixDirty)
     1992        updateMatrix();
     1993
     1994    stencilClean = false;
     1995
     1996    const bool singlePass = !path.hasWindingFill()
     1997        && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled)
     1998            || q->state()->needsClipBufferClear);
     1999    const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip;
     2000
     2001    if (q->state()->needsClipBufferClear)
     2002        clearClip(1);
     2003
     2004    if (path.isEmpty()) {
     2005        glEnable(GL_STENCIL_TEST);
     2006        glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
     2007        return;
     2008    }
     2009
     2010    if (q->state()->clipTestEnabled)
     2011        glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
     2012    else
     2013        glStencilFunc(GL_ALWAYS, 0, 0xff);
     2014
     2015    vertexCoordinateArray.clear();
     2016    vertexCoordinateArray.addPath(path, inverseScale, false);
     2017
     2018    if (!singlePass)
     2019        fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
     2020
     2021    glColorMask(false, false, false, false);
     2022    glEnable(GL_STENCIL_TEST);
     2023    useSimpleShader();
     2024
     2025    if (singlePass) {
     2026        // Under these conditions we can set the new stencil value in a single
     2027        // pass, by using the current value and the "new value" as the toggles
     2028
     2029        glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT);
     2030        glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
     2031        glStencilMask(value ^ referenceClipValue);
     2032
     2033        drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
     2034    } else {
     2035        glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
     2036        glStencilMask(0xff);
     2037
     2038        if (!q->state()->clipTestEnabled && path.hasWindingFill()) {
     2039            // Pass when any clip bit is set, set high bit
     2040            glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT);
     2041            composite(vertexCoordinateArray.boundingRect());
     2042        }
     2043
     2044        // Pass when high bit is set, replace stencil value with new clip value
     2045        glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT);
     2046
     2047        composite(vertexCoordinateArray.boundingRect());
     2048    }
     2049
     2050    glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
     2051    glStencilMask(0);
     2052
     2053    glColorMask(true, true, true, true);
    10422054}
    10432055
     
    10452057{
    10462058//     qDebug("QGL2PaintEngineEx::clip()");
    1047     const qreal *points = path.points();
    1048     const QPainterPath::ElementType *types = path.elements();
    1049     if (!types && path.shape() == QVectorPath::RectangleHint) {
    1050         QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
    1051         updateClipRegion(QRegion(r.toRect()), op);
    1052         return;
    1053     }
    1054 
    1055     QPainterPath p;
    1056     if (types) {
    1057         int id = 0;
    1058         for (int i=0; i<path.elementCount(); ++i) {
    1059             switch(types[i]) {
    1060             case QPainterPath::MoveToElement:
    1061                 p.moveTo(QPointF(points[id], points[id+1]));
    1062                 id+=2;
    1063                 break;
    1064             case QPainterPath::LineToElement:
    1065                 p.lineTo(QPointF(points[id], points[id+1]));
    1066                 id+=2;
    1067                 break;
    1068             case QPainterPath::CurveToElement: {
    1069                 QPointF p1(points[id], points[id+1]);
    1070                 QPointF p2(points[id+2], points[id+3]);
    1071                 QPointF p3(points[id+4], points[id+5]);
    1072                 p.cubicTo(p1, p2, p3);
    1073                 id+=6;
    1074                 break;
    1075             }
    1076             case QPainterPath::CurveToDataElement:
    1077                 ;
    1078                 break;
    1079             }
    1080         }
    1081     } else if (!path.isEmpty()) {
    1082         p.moveTo(QPointF(points[0], points[1]));
    1083         int id = 2;
    1084         for (int i=1; i<path.elementCount(); ++i) {
    1085             p.lineTo(QPointF(points[id], points[id+1]));
    1086             id+=2;
    1087         }
    1088     }
    1089     if (path.hints() & QVectorPath::WindingFill)
    1090         p.setFillRule(Qt::WindingFill);
    1091 
    1092     updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op);
    1093     return;
    1094 }
    1095 
    1096 void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)
    1097 {
    1098 //     qDebug("QGL2PaintEngineEx::updateClipRegion()");
    10992059    Q_D(QGL2PaintEngineEx);
    11002060
    1101     QRegion sysClip = systemClip();
    1102     if (op == Qt::NoClip && !d->use_system_clip) {
    1103         state()->hasClipping = false;
    1104         state()->clipRegion = QRegion();
    1105         d->updateDepthClip();
    1106         return;
    1107     }
    1108 
    1109     bool isScreenClip = false;
    1110     if (!d->use_system_clip) {
    1111         QVector<QRect> untransformedRects = clipRegion.rects();
    1112 
    1113         if (untransformedRects.size() == 1) {
    1114             QPainterPath path;
    1115             path.addRect(untransformedRects[0]);
    1116             //path = d->matrix.map(path);
    1117             path = state()->matrix.map(path);
    1118 
    1119 //             if (path.contains(QRectF(QPointF(), d->drawable.size())))
    1120 //                 isScreenClip = true;
    1121             if (path.contains(QRectF(0.0, 0.0, d->width, d->height)))
    1122                 isScreenClip = true;
    1123         }
    1124     }
    1125 
    1126 //     QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix;
    1127     QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix;
     2061    ;
     2062
     2063    ;
     2064
     2065   
     2066        ;
     2067   
     2068            d->systemStateChanged();
     2069    Clip = false;
     2070   
     2071   
     2072
     2073#ifndef QT_GL_NO_SCISSOR_TEST
     2074   
     2075        );
     2076        );
     2077
     2078        if (state()->matrix.type() <= QTransform::TxScale) {
     2079            state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
     2080;
     2081           
     2082       
     2083    }
     2084#endif
     2085
     2086;
     2087
    11282088    switch (op) {
    11292089    case Qt::NoClip:
    1130         if (!d->use_system_clip)
    1131             break;
    1132         state()->clipRegion = sysClip;
     2090        if (d->useSystemClip) {
     2091            state()->clipTestEnabled = true;
     2092            state()->currentClip = 1;
     2093        } else {
     2094            state()->clipTestEnabled = false;
     2095        }
     2096        state()->rectangleClip = QRect(0, 0, d->width, d->height);
     2097        state()->canRestoreClip = false;
     2098        d->updateClipScissorTest();
    11332099        break;
    11342100    case Qt::IntersectClip:
    1135         if (isScreenClip)
    1136             return;
    1137         if (state()->hasClipping) {
    1138             state()->clipRegion &= region;
    1139             break;
    1140         }
    1141         // fall through
    1142     case Qt::ReplaceClip:
    1143         if (d->use_system_clip && !sysClip.isEmpty())
    1144             state()->clipRegion = region & sysClip;
    1145         else
    1146             state()->clipRegion = region;
     2101        state()->rectangleClip = state()->rectangleClip.intersected(pathRect);
     2102        d->updateClipScissorTest();
     2103        d->resetClipIfNeeded();
     2104        ++d->maxClip;
     2105        d->writeClip(path, d->maxClip);
     2106        state()->currentClip = d->maxClip;
     2107        state()->clipTestEnabled = true;
    11472108        break;
    1148     case Qt::UniteClip:
    1149         state()->clipRegion |= region;
    1150         if (d->use_system_clip && !sysClip.isEmpty())
    1151             state()->clipRegion &= sysClip;
     2109    case Qt::UniteClip: {
     2110        d->resetClipIfNeeded();
     2111        ++d->maxClip;
     2112        if (state()->rectangleClip.isValid()) {
     2113            QPainterPath path;
     2114            path.addRect(state()->rectangleClip);
     2115
     2116            // flush the existing clip rectangle to the depth buffer
     2117            d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), d->maxClip);
     2118        }
     2119
     2120        state()->clipTestEnabled = false;
     2121#ifndef QT_GL_NO_SCISSOR_TEST
     2122        QRect oldRectangleClip = state()->rectangleClip;
     2123
     2124        state()->rectangleClip = state()->rectangleClip.united(pathRect);
     2125        d->updateClipScissorTest();
     2126
     2127        QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip;
     2128
     2129        if (!extendRegion.isEmpty()) {
     2130            QPainterPath extendPath;
     2131            extendPath.addRegion(extendRegion);
     2132
     2133            // first clear the depth buffer in the extended region
     2134            d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0);
     2135        }
     2136#endif
     2137        // now write the clip path
     2138        d->writeClip(path, d->maxClip);
     2139        state()->canRestoreClip = false;
     2140        state()->currentClip = d->maxClip;
     2141        state()->clipTestEnabled = true;
    11522142        break;
     2143
    11532144    default:
    11542145        break;
    11552146    }
    1156 
    1157     if (isScreenClip) {
    1158         state()->hasClipping = false;
    1159         state()->clipRegion = QRegion();
     2147}
     2148
     2149void QGL2PaintEngineExPrivate::regenerateClip()
     2150{
     2151    systemStateChanged();
     2152    replayClipOperations();
     2153}
     2154
     2155void QGL2PaintEngineExPrivate::systemStateChanged()
     2156{
     2157    Q_Q(QGL2PaintEngineEx);
     2158
     2159    q->state()->clipChanged = true;
     2160
     2161    if (systemClip.isEmpty()) {
     2162        useSystemClip = false;
    11602163    } else {
    1161         state()->hasClipping = op != Qt::NoClip || d->use_system_clip;
    1162     }
    1163 
    1164     if (state()->hasClipping && state()->clipRegion.rects().size() == 1)
    1165         state()->fastClip = state()->clipRegion.rects().at(0);
     2164        if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
     2165            QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
     2166            useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
     2167        } else {
     2168            useSystemClip = true;
     2169        }
     2170    }
     2171
     2172    q->state()->clipTestEnabled = false;
     2173    q->state()->needsClipBufferClear = true;
     2174
     2175    q->state()->currentClip = 1;
     2176    maxClip = 1;
     2177
     2178    q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height);
     2179    updateClipScissorTest();
     2180
     2181    if (systemClip.rectCount() == 1) {
     2182        if (systemClip.boundingRect() == QRect(0, 0, width, height))
     2183            useSystemClip = false;
     2184#ifndef QT_GL_NO_SCISSOR_TEST
     2185        // scissoring takes care of the system clip
     2186        return;
     2187#endif
     2188    }
     2189
     2190    if (useSystemClip) {
     2191        clearClip(0);
     2192
     2193        QPainterPath path;
     2194        path.addRegion(systemClip);
     2195
     2196        q->state()->currentClip = 0;
     2197        writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1);
     2198        q->state()->currentClip = 1;
     2199        q->state()->clipTestEnabled = true;
     2200    }
     2201}
     2202
     2203void QGL2PaintEngineEx::setState(QPainterState *new_state)
     2204{
     2205    //     qDebug("QGL2PaintEngineEx::setState()");
     2206
     2207    Q_D(QGL2PaintEngineEx);
     2208
     2209    QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state);
     2210    QOpenGL2PaintEngineState *old_state = state();
     2211
     2212    QPaintEngineEx::setState(s);
     2213
     2214    if (s->isNew) {
     2215        // Newly created state object.  The call to setState()
     2216        // will either be followed by a call to begin(), or we are
     2217        // setting the state as part of a save().
     2218        s->isNew = false;
     2219        return;
     2220    }
     2221
     2222    // Setting the state as part of a restore().
     2223
     2224    if (old_state == s || old_state->renderHintsChanged)
     2225        renderHintsChanged();
     2226
     2227    if (old_state == s || old_state->matrixChanged) {
     2228        d->matrixDirty = true;
     2229        d->simpleShaderMatrixUniformDirty = true;
     2230        d->shaderMatrixUniformDirty = true;
     2231    }
     2232
     2233    if (old_state == s || old_state->compositionModeChanged)
     2234        d->compositionModeDirty = true;
     2235
     2236    if (old_state == s || old_state->opacityChanged)
     2237        d->opacityUniformDirty = true;
     2238
     2239    if (old_state == s || old_state->clipChanged) {
     2240        if (old_state && old_state != s && old_state->canRestoreClip) {
     2241            d->updateClipScissorTest();
     2242            glDepthFunc(GL_LEQUAL);
     2243        } else {
     2244            d->regenerateClip();
     2245        }
     2246    }
     2247}
     2248
     2249QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
     2250{
     2251    if (orig)
     2252        const_cast<QGL2PaintEngineEx *>(this)->ensureActive();
     2253
     2254    QOpenGL2PaintEngineState *s;
     2255    if (!orig)
     2256        s = new QOpenGL2PaintEngineState();
    11662257    else
    1167         state()->fastClip = QRect();
    1168 
    1169     d->updateDepthClip();
    1170 }
    1171 
    1172 
    1173 void QGL2PaintEngineExPrivate::updateDepthClip()
    1174 {
    1175 //     qDebug("QGL2PaintEngineExPrivate::updateDepthClip()");
    1176 
    1177     Q_Q(QGL2PaintEngineEx);
    1178 
    1179     glDisable(GL_DEPTH_TEST);
    1180     glDisable(GL_SCISSOR_TEST);
    1181 
    1182     if (!q->state()->hasClipping)
    1183         return;
    1184 
    1185     QRect fastClip;
    1186     if (q->state()->clipEnabled) {
    1187         fastClip = q->state()->fastClip;
    1188     } else if (use_system_clip && q->systemClip().rects().count() == 1) {
    1189         fastClip = q->systemClip().rects().at(0);
    1190     }
    1191 
    1192     if (!fastClip.isEmpty()) {
    1193         glEnable(GL_SCISSOR_TEST);
    1194 
    1195         const int left = fastClip.left();
    1196         const int width = fastClip.width();
    1197         const int bottom = height - (fastClip.bottom() + 1);
    1198         const int height = fastClip.height();
    1199 
    1200         glScissor(left, bottom, width, height);
    1201         return;
    1202     }
    1203 
    1204     glClearDepthf(0x0);
    1205     glDepthMask(true);
    1206     glClear(GL_DEPTH_BUFFER_BIT);
    1207     glClearDepthf(0x1);
    1208 
    1209     const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects();
    1210     glEnable(GL_SCISSOR_TEST);
    1211     for (int i = 0; i < rects.size(); ++i) {
    1212         QRect rect = rects.at(i);
    1213 
    1214         const int left = rect.left();
    1215         const int width = rect.width();
    1216         const int bottom = height - (rect.bottom() + 1);
    1217         const int height = rect.height();
    1218 
    1219         glScissor(left, bottom, width, height);
    1220 
    1221         glClear(GL_DEPTH_BUFFER_BIT);
    1222     }
    1223     glDisable(GL_SCISSOR_TEST);
    1224 
    1225     glDepthMask(false);
    1226     glDepthFunc(GL_LEQUAL);
    1227     glEnable(GL_DEPTH_TEST);
    1228 }
    1229 
    1230 
    1231 
    1232 void QGL2PaintEngineEx::setState(QPainterState *s)
    1233 {
    1234 //     qDebug("QGL2PaintEngineEx::setState()");
    1235 
    1236     Q_D(QGL2PaintEngineEx);
    1237     QPaintEngineEx::setState(s);
    1238 
    1239     d->updateDepthClip();
    1240 
    1241     d->matrixDirty = true;
    1242     d->compositionModeDirty = true;
    1243     d->brushTextureDirty = true;
    1244     d->brushUniformsDirty = true;
    1245     d->simpleShaderMatrixUniformDirty = true;
    1246     d->brushShaderMatrixUniformDirty = true;
    1247     d->imageShaderMatrixUniformDirty = true;
    1248     d->textShaderMatrixUniformDirty = true;
    1249 }
    1250 
    1251 QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
    1252 {
    1253     QOpenGLPaintEngineState *s;
    1254     if (!orig)
    1255         s = new QOpenGLPaintEngineState();
    1256     else
    1257         s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig));
     2258        s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig));
     2259
     2260    s->matrixChanged = false;
     2261    s->compositionModeChanged = false;
     2262    s->opacityChanged = false;
     2263    s->renderHintsChanged = false;
     2264    s->clipChanged = false;
    12582265
    12592266    return s;
    12602267}
    12612268
    1262 QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)
     2269QOpenGLPaintEngineState &other)
    12632270    : QPainterState(other)
    12642271{
    1265     clipRegion = other.clipRegion;
    1266     hasClipping = other.hasClipping;
    1267     fastClip = other.fastClip;
    1268 }
    1269 
    1270 QOpenGLPaintEngineState::QOpenGLPaintEngineState()
    1271 {
    1272     hasClipping = false;
    1273 }
    1274 
    1275 QOpenGLPaintEngineState::~QOpenGLPaintEngineState()
    1276 {
    1277 }
    1278 
     2272    isNew = true;
     2273    needsClipBufferClear = other.needsClipBufferClear;
     2274    clipTestEnabled = other.clipTestEnabled;
     2275    currentClip = other.currentClip;
     2276    canRestoreClip = other.canRestoreClip;
     2277    rectangleClip = other.rectangleClip;
     2278}
     2279
     2280QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
     2281{
     2282    isNew = true;
     2283    needsClipBufferClear = true;
     2284    clipTestEnabled = false;
     2285    canRestoreClip = true;
     2286}
     2287
     2288QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
     2289{
     2290}
     2291
     2292QT_END_NAMESPACE
     2293
     2294#include "qpaintengineex_opengl2.moc"
  • trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5454//
    5555
     56
     57
    5658#include <private/qpaintengineex_p.h>
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
    5775
    5876class QGL2PaintEngineExPrivate;
    5977
    6078
    61 class QOpenGLPaintEngineState : public QPainterState
     79class QOpenGLPaintEngineState : public QPainterState
    6280{
    6381public:
    64     QOpenGLPaintEngineState(QOpenGLPaintEngineState &other);
    65     QOpenGLPaintEngineState();
    66     ~QOpenGLPaintEngineState();
    67 
    68     QRegion clipRegion;
    69     bool hasClipping;
    70     QRect fastClip;
    71 };
    72 
    73 
    74 class QGL2PaintEngineEx : public QPaintEngineEx
     82    QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other);
     83    QOpenGL2PaintEngineState();
     84    ~QOpenGL2PaintEngineState();
     85
     86    uint isNew : 1;
     87    uint needsClipBufferClear : 1;
     88    uint clipTestEnabled : 1;
     89    uint canRestoreClip : 1;
     90    uint matrixChanged : 1;
     91    uint compositionModeChanged : 1;
     92    uint opacityChanged : 1;
     93    uint renderHintsChanged : 1;
     94    uint clipChanged : 1;
     95    uint currentClip : 8;
     96
     97    QRect rectangleClip;
     98};
     99
     100class Q_OPENGL_EXPORT QGL2PaintEngineEx : public QPaintEngineEx
    75101{
    76102    Q_DECLARE_PRIVATE(QGL2PaintEngineEx)
     
    80106
    81107    bool begin(QPaintDevice *device);
     108
    82109    bool end();
    83 
    84     virtual void fill(const QVectorPath &path, const QBrush &brush);
    85     virtual void stroke(const QVectorPath &path, const QPen &pen);
    86     virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
    87110
    88111    virtual void clipEnabledChanged();
     
    95118    virtual void transformChanged();
    96119
    97 
     120    virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
    98121    virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
    99 
     122    virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
    100123    virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
    101124                           Qt::ImageConversionFlags flags = Qt::AutoColor);
    102125    virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
    103     void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti);
    104 
    105     Type type() const { return OpenGL; }
    106 
    107 
    108     // State stuff is just for clipping and ripped off from QGLPaintEngine
    109     void setState(QPainterState *s);
    110     QPainterState *createState(QPainterState *orig) const;
    111     inline QOpenGLPaintEngineState *state() {
    112         return static_cast<QOpenGLPaintEngineState *>(QPaintEngineEx::state());
    113     }
    114     inline const QOpenGLPaintEngineState *state() const {
    115         return static_cast<const QOpenGLPaintEngineState *>(QPaintEngineEx::state());
    116     }
    117     void updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op);
     126    virtual void fill(const QVectorPath &path, const QBrush &brush);
     127    virtual void stroke(const QVectorPath &path, const QPen &pen);
     128    virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
     129
     130
     131    Type type() const { return OpenGL2; }
     132
     133    virtual void setState(QPainterState *s);
     134    virtual QPainterState *createState(QPainterState *orig) const;
     135    inline QOpenGL2PaintEngineState *state() {
     136        return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
     137    }
     138    inline const QOpenGL2PaintEngineState *state() const {
     139        return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
     140    }
     141
     142    void beginNativePainting();
     143    void endNativePainting();
     144
     145    QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype);
     146
     147    void setRenderTextActive(bool);
    118148
    119149private:
     
    122152
    123153
     154
     155
     156
     157
     158
     159
     160
     161
     162
     163
     164
     165
     166
     167
     168
     169
     170
     171
     172
     173
     174
     175
     176
     177
     178
     179
     180
     181
     182
     183
     184
     185
     186
     187
     188
     189
     190
     191
     192
     193
     194
     195
     196
     197
     198
     199
     200
     201
     202
     203
     204
     205
     206
     207
     208
     209
     210
     211
     212
     213
     214
     215
     216
     217
     218
     219
     220
     221
     222
     223
     224
     225
     226
     227
     228
     229
     230
     231
     232
     233
     234
     235
     236
     237
     238
     239
     240
     241
     242
     243
     244
     245
     246
     247
     248
     249
     250
     251
     252
     253
     254
     255
     256
     257
     258
     259
     260
     261
     262
     263
     264
     265
     266
     267
     268
     269
     270
     271
     272
     273
     274
     275
     276
     277
     278
     279
     280
     281
     282
     283
     284
     285
     286
     287
     288
     289
     290
    124291
    125292#endif
Note: See TracChangeset for help on using the changeset viewer.