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 (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4444#include <private/qbezier_p.h>
    4545
     46QT_BEGIN_NAMESPACE
     47
    4648void QGL2PEXVertexArray::clear()
    4749{
    4850    vertexArray.reset();
    49     vertexArrayStops.clear();
     51    vertexArrayStops.reset();
    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    if (!outline && !path.isConvex())
     105        addCentroid(path, 0);
     106
     107    int lastMoveTo = vertexArray.size();
    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                if (!outline)
     126                    addClosingLine(lastMoveTo);
    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 (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5151//
    5252
     53#ifndef QGL2PEXVERTEXARRAY_P_H
     54#define QGL2PEXVERTEXARRAY_P_H
     55
    5356#include <QRectF>
    5457
     
    5659#include <private/qvectorpath_p.h>
    5760#include <private/qgl_p.h>
     61
     62QT_BEGIN_NAMESPACE
    5863
    5964class QGLPoint
     
    6368        x(new_x), y(new_y) {};
    6469
    65     QGLPoint(QPointF p) :
     70    QGLPoint(const QPointF &p) :
    6671        x(p.x()), y(p.y()) {};
    6772
     
    7883struct QGLRect
    7984{
    80     QGLRect(QRectF r)
     85    QGLRect(const QRectF &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    int vertexCount() const { return vertexArray.size(); }
    107116
    108117    void lineToArray(const GLfloat x, const GLfloat y);
     
    110119private:
    111120    QDataBuffer<QGLPoint> vertexArray;
    112     QVector<int>          vertexArrayStops;
     121    QDataBuffer<int>      vertexArrayStops;
    113122
    114123    GLfloat     maxX;
     
    117126    GLfloat     minY;
    118127    bool        boundingRectDirty;
     128    void addClosingLine(int index);
     129    void addCentroid(const QVectorPath &path, int subPathIndex);
     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 (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@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 QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
    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 QGL2GradientCache::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 (when using GL_RGBA), bin-endian (ABGR on x86).
     128// Qt always stores in ARGB reguardless of the 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 QGL2GradientCache::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 (on little-endian AND on big-endian)
    140152
    141153    bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
     
    184196    colorTable[size-1] = last_color;
    185197}
     198
     199QT_END_NAMESPACE
  • 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 (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@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
     96QT_END_NAMESPACE
    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 (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    6363*/
    6464
     65// #define QT_OPENGL_CACHE_AS_VBOS
    6566
    6667#include "qpaintengineex_opengl2_p.h"
     
    7677#include <private/qfontengine_p.h>
    7778#include <private/qtextureglyphcache_p.h>
     79#include <private/qpixmapdata_gl_p.h>
     80#include <private/qdatabuffer_p.h>
    7881
    7982#include "qglgradientcache_p.h"
    80 #include "qglpexshadermanager_p.h"
     83#include "qglengineshadermanager_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
     156QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
     157    : QTextureGlyphCache(type, matrix)
     158    , ctx(context)
     159    , m_width(0)
     160    , m_height(0)
     161{
     162    glGenFramebuffers(1, &m_fbo);
     163    connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
     164            SLOT(contextDestroyed(const QGLContext*)));
     165}
     166
     167QGLTextureGlyphCache::~QGLTextureGlyphCache()
     168{
     169    if (ctx) {
     170        QGLShareContextScope scope(ctx);
     171        glDeleteFramebuffers(1, &m_fbo);
     172
     173        if (m_width || m_height)
     174            glDeleteTextures(1, &m_texture);
     175    }
     176}
     177
     178void QGLTextureGlyphCache::createTextureData(int width, int height)
     179{
     180    glGenTextures(1, &m_texture);
     181    glBindTexture(GL_TEXTURE_2D, m_texture);
     182
     183    m_width = width;
     184    m_height = height;
     185
     186    QVarLengthArray<uchar> data(width * height);
     187    for (int i = 0; i < data.size(); ++i)
     188        data[i] = 0;
     189
     190    if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
     191        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
     192    else
     193        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
     194
     195    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     196    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     197}
     198
     199void QGLTextureGlyphCache::resizeTextureData(int width, int height)
     200{
     201    // ### the QTextureGlyphCache API needs to be reworked to allow
     202    // ### resizeTextureData to fail
     203
     204    int oldWidth = m_width;
     205    int oldHeight = m_height;
     206
     207    GLuint oldTexture = m_texture;
     208    createTextureData(width, height);
     209
     210    glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
     211
     212    GLuint tmp_texture;
     213    glGenTextures(1, &tmp_texture);
     214    glBindTexture(GL_TEXTURE_2D, tmp_texture);
     215    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
     216                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
     217    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     218    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     219    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     220    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     221    glBindTexture(GL_TEXTURE_2D, 0);
     222    glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     223                           GL_TEXTURE_2D, tmp_texture, 0);
     224
     225    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
     226    glBindTexture(GL_TEXTURE_2D, oldTexture);
     227
     228    pex->transferMode(BrushDrawingMode);
     229
     230    glDisable(GL_STENCIL_TEST);
     231    glDisable(GL_DEPTH_TEST);
     232    glDisable(GL_SCISSOR_TEST);
     233    glDisable(GL_BLEND);
     234
     235    glViewport(0, 0, oldWidth, oldHeight);
     236
     237    float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 };
     238    float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
     239
     240    glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     241    glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     242
     243    glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
     244    glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
     245
     246    pex->shaderManager->blitProgram()->bind();
     247    pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
     248    pex->shaderManager->setDirty();
     249
     250    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     251
     252    glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
     253    glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
     254
     255    glBindTexture(GL_TEXTURE_2D, m_texture);
     256
     257#ifdef QT_OPENGL_ES_2
     258    QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
     259    buffer.resize(4*oldWidth*oldHeight);
     260    glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
     261
     262    // do an in-place conversion from GL_RGBA to GL_ALPHA
     263    for (int i=0; i<oldWidth*oldHeight; ++i)
     264        buffer.data()[i] = buffer.at(4*i + 3);
     265
     266    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight,
     267                    GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data());
     268#else
     269    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
     270#endif
     271
     272    glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     273                              GL_RENDERBUFFER_EXT, 0);
     274    glDeleteTextures(1, &tmp_texture);
     275    glDeleteTextures(1, &oldTexture);
     276
     277    glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
     278
     279    glViewport(0, 0, pex->width, pex->height);
     280    pex->updateClipScissorTest();
     281}
     282
     283void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
     284{
     285    QImage mask = textureMapForGlyph(glyph);
     286    const int maskWidth = mask.width();
     287    const int maskHeight = mask.height();
     288
     289    if (mask.format() == QImage::Format_Mono) {
     290        mask = mask.convertToFormat(QImage::Format_Indexed8);
     291        for (int y = 0; y < maskHeight; ++y) {
     292            uchar *src = (uchar *) mask.scanLine(y);
     293            for (int x = 0; x < maskWidth; ++x)
     294                src[x] = -src[x]; // convert 0 and 1 into 0 and 255
     295        }
     296     }
     297
     298
     299    glBindTexture(GL_TEXTURE_2D, m_texture);
     300    if (mask.format() == QImage::Format_RGB32) {
     301        glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
     302    } else {
     303#ifdef QT_OPENGL_ES2
     304        glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
     305#else
     306        // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
     307        // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
     308        // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
     309        // multiple of four bytes per line, and most of the glyph shows up correctly in the
     310        // texture, which makes me think that this is a driver bug.
     311        // One workaround is to make sure the mask width is a multiple of four bytes, for instance
     312        // by converting it to a format with four bytes per pixel. Another is to copy one line at a
     313        // time.
     314
     315        for (int i = 0; i < maskHeight; ++i)
     316            glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
     317#endif
     318    }
     319}
     320
     321int QGLTextureGlyphCache::glyphMargin() const
     322{
     323#if defined(Q_WS_MAC)
     324    return 2;
     325#elif defined (Q_WS_X11)
     326    return 0;
     327#else
     328    return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
     329#endif
     330}
     331
     332extern QImage qt_imageForBrush(int brushStyle, bool invert);
    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    Q_Q(QGL2PaintEngineEx);
    233422//     qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
    234     Qt::BrushStyle style = currentBrush->style();
     423    Qt::BrushStyle style = currentBrush.style();
    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, false);
     428
     429        glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
     430        ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true, QGLContext::InternalBindOption);
     431        updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
    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 = currentBrush.gradient();
    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, q->state()->renderHints & QPainter::SmoothPixmapTransform);
    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, q->state()->renderHints & QPainter::SmoothPixmapTransform);
    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 = currentBrush.style();
    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 *>(currentBrush.gradient());
    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->currentProgram()->setUniformValue(location(QGLEngineShaderManager::LinearData), linearData);
     506
     507            QVector2D halfViewportSize(width*0.5, height*0.5);
     508            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
    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 *>(currentBrush.gradient());
    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->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle);
     517
     518            QVector2D halfViewportSize(width*0.5, height*0.5);
     519            shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
    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 *>(currentBrush.gradient());
    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->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp), fmp);
    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        const QPointF &brushOrigin = q->state()->brushOrigin;
     557        QTransform matrix = q->state()->matrix;
     558        matrix.translate(brushOrigin.x(), brushOrigin.y());
     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(currentBrush.isOpaque());
    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    glStencilMask(0xff); // Enable stencil writes
     1018
     1019    if (dirtyStencilRegion.intersects(currentScissorBounds)) {
     1020        QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects();
    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, data);
    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    state()->opacityChanged = true;
    8201382
    8211383    Q_ASSERT(d->shaderManager);
    822     d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);
    8231384    d->brushUniformsDirty = true;
     1385    d->opacityUniformDirty = true;
    8241386}
    8251387
     
    8281390//     qDebug("QGL2PaintEngineEx::compositionModeChanged()");
    8291391    Q_D(QGL2PaintEngineEx);
     1392    state()->compositionModeChanged = true;
    8301393    d->compositionModeDirty = true;
    8311394}
     
    8331396void QGL2PaintEngineEx::renderHintsChanged()
    8341397{
     1398    state()->renderHintsChanged = true;
     1399
     1400#if !defined(QT_OPENGL_ES_2)
     1401    if ((state()->renderHints & QPainter::Antialiasing)
     1402        || (state()->renderHints & QPainter::HighQualityAntialiasing))
     1403        glEnable(GL_MULTISAMPLE);
     1404    else
     1405        glDisable(GL_MULTISAMPLE);
     1406#endif
     1407
     1408    Q_D(QGL2PaintEngineEx);
     1409    d->lastTextureUsed = GLuint(-1);
     1410    d->brushTextureDirty = true;
    8351411//    qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
    8361412}
     
    8401416    Q_D(QGL2PaintEngineEx);
    8411417    d->matrixDirty = true;
     1418    state()->matrixChanged = true;
    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->drawCachedGlyphs(p, glyphType, 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 QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
     1525                                                const QTextItemInt &ti)
     1526{
     1527    Q_Q(QGL2PaintEngineEx);
    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    glDisable(GL_SCISSOR_TEST);
     1826
     1827#if !defined(QT_OPENGL_ES_2)
     1828    glDisable(GL_MULTISAMPLE);
     1829#endif
     1830
     1831    d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
     1832
     1833#if !defined(QT_OPENGL_ES_2)
     1834#if defined(Q_WS_WIN)
     1835    if (qt_cleartype_enabled)
     1836#endif
     1837        d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
     1838#endif
     1839
     1840#if defined(QT_OPENGL_ES_2)
     1841    // OpenGL ES can't switch MSAA off, so if the gl paint device is
     1842    // multisampled, it's always multisampled.
     1843    d->multisamplingAlwaysEnabled = d->device->format().sampleBuffers();
     1844#else
     1845    d->multisamplingAlwaysEnabled = false;
     1846#endif
    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    state()->clipChanged = true;
     2062
     2063    ensureActive();
     2064
     2065    if (op == Qt::ReplaceClip) {
     2066        op = Qt::IntersectClip;
     2067        if (d->hasClipOperations()) {
     2068            d->systemStateChanged();
     2069            state()->canRestoreClip = false;
     2070        }
     2071    }
     2072
     2073#ifndef QT_GL_NO_SCISSOR_TEST
     2074    if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) {
     2075        const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
     2076        QRectF rect(points[0], points[2]);
     2077
     2078        if (state()->matrix.type() <= QTransform::TxScale) {
     2079            state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
     2080            d->updateClipScissorTest();
     2081            return;
     2082        }
     2083    }
     2084#endif
     2085
     2086    const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
     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)
     2269QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &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 (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    5454//
    5555
     56#include <QDebug>
     57
    5658#include <private/qpaintengineex_p.h>
     59#include <private/qglengineshadermanager_p.h>
     60#include <private/qgl2pexvertexarray_p.h>
     61#include <private/qglpaintdevice_p.h>
     62#include <private/qglpixmapfilter_p.h>
     63#include <private/qfontengine_p.h>
     64#include <private/qdatabuffer_p.h>
     65#include <private/qtriangulatingstroker_p.h>
     66
     67enum EngineMode {
     68    ImageDrawingMode,
     69    TextDrawingMode,
     70    BrushDrawingMode,
     71    ImageArrayDrawingMode
     72};
     73
     74QT_BEGIN_NAMESPACE
    5775
    5876class QGL2PaintEngineExPrivate;
    5977
    6078
    61 class QOpenGLPaintEngineState : public QPainterState
     79class QOpenGL2PaintEngineState : 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    void ensureActive();
    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
     154class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
     155{
     156    Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
     157public:
     158    enum StencilFillMode {
     159        OddEvenFillMode,
     160        WindingFillMode,
     161        TriStripStrokeFillMode
     162    };
     163
     164    QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) :
     165            q(q_ptr),
     166            shaderManager(0),
     167            width(0), height(0),
     168            ctx(0),
     169            useSystemClip(true),
     170            snapToPixelGrid(false),
     171            addOffset(false),
     172            inverseScale(1)
     173    { }
     174
     175    ~QGL2PaintEngineExPrivate();
     176
     177    void updateBrushTexture();
     178    void updateBrushUniforms();
     179    void updateMatrix();
     180    void updateCompositionMode();
     181    void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = -1);
     182
     183    void resetGLState();
     184
     185    // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points,
     186    // however writeClip can also be thought of as en entry point as it does similar things.
     187    void fill(const QVectorPath &path);
     188    void stroke(const QVectorPath &path, const QPen &pen);
     189    void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
     190    void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
     191    void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti);
     192
     193    // draws whatever is in the vertex array:
     194    void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
     195    void drawVertexArrays(QGL2PEXVertexArray &vertexArray, GLenum primitive) {
     196        drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive);
     197    }
     198
     199    // Composites the bounding rect onto dest buffer:
     200    void composite(const QGLRect& boundingRect);
     201
     202    // Calls drawVertexArrays to render into stencil buffer:
     203    void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QGLRect &bounds, StencilFillMode mode);
     204    void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) {
     205        fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(),
     206                                   vertexArray.boundingRect(),
     207                                   useWindingFill ? WindingFillMode : OddEvenFillMode);
     208    }
     209
     210    void setBrush(const QBrush& brush);
     211    void transferMode(EngineMode newMode);
     212    bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed
     213    inline void useSimpleShader();
     214    inline GLuint location(const QGLEngineShaderManager::Uniform uniform) {
     215        return shaderManager->getUniformLocation(uniform);
     216    }
     217
     218    void clearClip(uint value);
     219    void writeClip(const QVectorPath &path, uint value);
     220    void resetClipIfNeeded();
     221
     222    void updateClipScissorTest();
     223    void setScissor(const QRect &rect);
     224    void regenerateClip();
     225    void systemStateChanged();
     226
     227    static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
     228    static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); }
     229    static void cleanupVectorPath(QPaintEngineEx *engine, void *data);
     230
     231
     232    QGL2PaintEngineEx* q;
     233    QGLEngineShaderManager* shaderManager;
     234    QGLPaintDevice* device;
     235    int width, height;
     236    QGLContext *ctx;
     237    EngineMode mode;
     238    QFontEngineGlyphCache::Type glyphCacheType;
     239
     240    // Dirty flags
     241    bool matrixDirty; // Implies matrix uniforms are also dirty
     242    bool compositionModeDirty;
     243    bool brushTextureDirty;
     244    bool brushUniformsDirty;
     245    bool simpleShaderMatrixUniformDirty;
     246    bool shaderMatrixUniformDirty;
     247    bool opacityUniformDirty;
     248
     249    bool stencilClean; // Has the stencil not been used for clipping so far?
     250    bool useSystemClip;
     251    QRegion dirtyStencilRegion;
     252    QRect currentScissorBounds;
     253    uint maxClip;
     254
     255    QBrush currentBrush; // May not be the state's brush!
     256    const QBrush noBrush;
     257
     258    QGL2PEXVertexArray vertexCoordinateArray;
     259    QGL2PEXVertexArray textureCoordinateArray;
     260    QDataBuffer<GLfloat> opacityArray;
     261    GLfloat staticVertexCoordinateArray[8];
     262    GLfloat staticTextureCoordinateArray[8];
     263
     264    bool snapToPixelGrid;
     265    bool addOffset; // When enabled, adds a 0.49,0.49 offset to matrix in updateMatrix
     266    GLfloat pmvMatrix[3][3];
     267    GLfloat inverseScale;
     268
     269    GLuint lastTextureUsed;
     270
     271    bool needsSync;
     272    bool multisamplingAlwaysEnabled;
     273
     274    GLfloat depthRange[2];
     275
     276    float textureInvertedY;
     277
     278    QTriangulatingStroker stroker;
     279    QDashedStrokeProcessor dasher;
     280
     281    QScopedPointer<QPixmapFilter> convolutionFilter;
     282    QScopedPointer<QPixmapFilter> colorizeFilter;
     283    QScopedPointer<QPixmapFilter> blurFilter;
     284    QScopedPointer<QPixmapFilter> dropShadowFilter;
     285
     286    QSet<QVectorPath::CacheEntry *> pathCaches;
     287    QVector<GLuint> unusedVBOSToClean;
     288};
     289
     290QT_END_NAMESPACE
    124291
    125292#endif
Note: See TracChangeset for help on using the changeset viewer.