Qt 4.8
qpaintengineex_opengl2.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 /*
43  When the active program changes, we need to update it's uniforms.
44  We could track state for each program and only update stale uniforms
45  - Could lead to lots of overhead if there's a lot of programs
46  We could update all the uniforms when the program changes
47  - Could end up updating lots of uniforms which don't need updating
48 
49  Updating uniforms should be cheap, so the overhead of updating up-to-date
50  uniforms should be minimal. It's also less complex.
51 
52  Things which _may_ cause a different program to be used:
53  - Change in brush/pen style
54  - Change in painter opacity
55  - Change in composition mode
56 
57  Whenever we set a mode on the shader manager - it needs to tell us if it had
58  to switch to a different program.
59 
60  The shader manager should only switch when we tell it to. E.g. if we set a new
61  brush style and then switch to transparent painter, we only want it to compile
62  and use the correct program when we really need it.
63 */
64 
65 // #define QT_OPENGL_CACHE_AS_VBOS
66 
67 #include "qglgradientcache_p.h"
69 
70 #include <string.h> //for memcpy
71 #include <qmath.h>
72 
73 #include <private/qgl_p.h>
74 #include <private/qmath_p.h>
75 #include <private/qpaintengineex_p.h>
76 #include <QPaintEngine>
77 #include <private/qpainter_p.h>
78 #include <private/qfontengine_p.h>
79 #include <private/qpixmapdata_gl_p.h>
80 #include <private/qdatabuffer_p.h>
81 #include <private/qstatictext_p.h>
82 #include <private/qtriangulator_p.h>
83 
85 #include "qgl2pexvertexarray_p.h"
88 
89 #include <QDebug>
90 
92 
93 inline static bool isPowerOfTwo(uint x)
94 {
95  return x && !(x & (x - 1));
96 }
97 
98 #if defined(Q_WS_WIN)
100 #endif
101 
102 #ifdef Q_WS_MAC
104 #endif
105 
106 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
107 # define QT_MAX_CACHED_GLYPH_SIZE 64
108 #endif
109 
110 Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
111 
113 
115 {
116  delete shaderManager;
117 
118  while (pathCaches.size()) {
120  e->cleanup(e->engine, e->data);
121  e->data = 0;
122  e->engine = 0;
123  }
124 
125  if (elementIndicesVBOId != 0) {
128  }
129 }
130 
131 void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
132 {
133 // glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
134  if (id != GLuint(-1) && id == lastTextureUsed)
135  return;
136 
137  lastTextureUsed = id;
138 
139  if (smoothPixmapTransform) {
140  glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
141  glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
142  } else {
143  glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
144  glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
145  }
146  glTexParameterf(target, GL_TEXTURE_WRAP_S, wrapMode);
147  glTexParameterf(target, GL_TEXTURE_WRAP_T, wrapMode);
148 }
149 
150 
151 inline QColor qt_premultiplyColor(QColor c, GLfloat opacity)
152 {
153  qreal alpha = c.alphaF() * opacity;
154  c.setAlphaF(alpha);
155  c.setRedF(c.redF() * alpha);
156  c.setGreenF(c.greenF() * alpha);
157  c.setBlueF(c.blueF() * alpha);
158  return c;
159 }
160 
161 
163 {
164  if (qbrush_fast_equals(currentBrush, brush))
165  return;
166 
167  const Qt::BrushStyle newStyle = qbrush_style(brush);
168  Q_ASSERT(newStyle != Qt::NoBrush);
169 
170  currentBrush = brush;
171  if (!currentBrushPixmap.isNull())
173  brushUniformsDirty = true; // All brushes have at least one uniform
174 
175  if (newStyle > Qt::SolidPattern)
176  brushTextureDirty = true;
177 
179  && qHasPixmapTexture(brush) && brush.texture().isQBitmap())
180  {
182  } else {
183  shaderManager->setSrcPixelType(newStyle);
184  }
186 }
187 
188 
190 {
192 
193  if (matrixDirty)
194  updateMatrix();
195 }
196 
198 {
200 // qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
202 
203  if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
204  // Get the image data for the pattern
205  QImage texImage = qt_imageForBrush(style, false);
206 
209 #if !defined(QT_NO_DEBUG) && defined(QT_OPENGL_ES_2)
211  bool npotSupported = funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures);
212  bool isNpot = !isPowerOfTwo(texImage.size().width())
213  || !isPowerOfTwo(texImage.size().height());
214  if (isNpot && !npotSupported) {
215  qWarning("GL2 Paint Engine: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
216  }
217 #endif
219  }
220  else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
221  // Gradiant brush: All the gradiants use the same texture
222 
223  const QGradient* g = currentBrush.gradient();
224 
225  // We apply global opacity in the fragment shaders, so we always pass 1.0
226  // for opacity to the cache.
227  GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
228 
230  glBindTexture(GL_TEXTURE_2D, texId);
231 
234  else if (g->spread() == QGradient::ReflectSpread)
236  else
238  }
239  else if (style == Qt::TexturePattern) {
241 
242  int max_texture_size = ctx->d_func()->maxTextureSize();
243  if (currentBrushPixmap.width() > max_texture_size || currentBrushPixmap.height() > max_texture_size)
244  currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
245 
250  GLenum wrapMode = GL_REPEAT;
251 #ifdef QT_OPENGL_ES_2
252  // should check for GL_OES_texture_npot or GL_IMG_texture_npot extension
254  wrapMode = GL_CLAMP_TO_EDGE;
255 #endif
258  }
259  brushTextureDirty = false;
260 }
261 
262 
264 {
265 // qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()");
267 
268  if (style == Qt::NoBrush)
269  return;
270 
271  QTransform brushQTransform = currentBrush.transform();
272 
273  if (style == Qt::SolidPattern) {
274  QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
276  }
277  else {
278  // All other brushes have a transform and thus need the translation point:
279  QPointF translationPoint;
280 
281  if (style <= Qt::DiagCrossPattern) {
282  QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
283 
285 
286  QVector2D halfViewportSize(width*0.5, height*0.5);
288  }
289  else if (style == Qt::LinearGradientPattern) {
290  const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient());
291 
292  QPointF realStart = g->start();
293  QPointF realFinal = g->finalStop();
294  translationPoint = realStart;
295 
296  QPointF l = realFinal - realStart;
297 
298  QVector3D linearData(
299  l.x(),
300  l.y(),
301  1.0f / (l.x() * l.x() + l.y() * l.y())
302  );
303 
305 
306  QVector2D halfViewportSize(width*0.5, height*0.5);
308  }
309  else if (style == Qt::ConicalGradientPattern) {
310  const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient());
311  translationPoint = g->center();
312 
313  GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
314 
316 
317  QVector2D halfViewportSize(width*0.5, height*0.5);
319  }
320  else if (style == Qt::RadialGradientPattern) {
321  const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient());
322  QPointF realCenter = g->center();
323  QPointF realFocal = g->focalPoint();
324  qreal realRadius = g->centerRadius() - g->focalRadius();
325  translationPoint = realFocal;
326 
327  QPointF fmp = realCenter - realFocal;
329 
330  GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius;
333  GLfloat(1.0 / (2.0*fmp2_m_radius2)));
335  GLfloat(g->focalRadius() * g->focalRadius()));
337  GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()),
338  g->focalRadius(),
339  g->centerRadius() - g->focalRadius());
340 
341  QVector2D halfViewportSize(width*0.5, height*0.5);
343  }
344  else if (style == Qt::TexturePattern) {
345  const QPixmap& texPixmap = currentBrush.texture();
346 
348  QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
350  }
351 
352  QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height());
354 
355  QVector2D halfViewportSize(width*0.5, height*0.5);
357  }
358  else
359  qWarning("QGL2PaintEngineEx: Unimplemented fill style");
360 
361  const QPointF &brushOrigin = q->state()->brushOrigin;
362  QTransform matrix = q->state()->matrix;
363  matrix.translate(brushOrigin.x(), brushOrigin.y());
364 
365  QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
366  qreal m22 = -1;
367  qreal dy = height;
368  if (device->isFlipped()) {
369  m22 = 1;
370  dy = 0;
371  }
372  QTransform gl_to_qt(1, 0, 0, m22, 0, dy);
373  QTransform inv_matrix;
374  if (style == Qt::TexturePattern && textureInvertedY == -1)
375  inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate;
376  else
377  inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate;
378 
381  }
382  brushUniformsDirty = false;
383 }
384 
385 
386 // This assumes the shader manager has already setup the correct shader program
388 {
389 // qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
390 
391  const QTransform& transform = q->state()->matrix;
392 
393  // The projection matrix converts from Qt's coordinate system to GL's coordinate system
394  // * GL's viewport is 2x2, Qt's is width x height
395  // * GL has +y -> -y going from bottom -> top, Qt is the other way round
396  // * GL has [0,0] in the center, Qt has it in the top-left
397  //
398  // This results in the Projection matrix below, which is multiplied by the painter's
399  // transformation matrix, as shown below:
400  //
401  // Projection Matrix Painter Transform
402  // ------------------------------------------------ ------------------------
403  // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx |
404  // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy |
405  // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 |
406  // ------------------------------------------------ ------------------------
407  //
408  // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies
409 
410  const GLfloat wfactor = 2.0f / width;
411  GLfloat hfactor = -2.0f / height;
412 
413  GLfloat dx = transform.dx();
414  GLfloat dy = transform.dy();
415 
416  if (device->isFlipped()) {
417  hfactor *= -1;
418  dy -= height;
419  }
420 
421  // Non-integer translates can have strange effects for some rendering operations such as
422  // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid.
423  if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) {
424  // 0.50 needs to rounded down to 0.0 for consistency with raster engine:
425  dx = ceilf(dx - 0.5f);
426  dy = ceilf(dy - 0.5f);
427  }
428  pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13();
429  pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23();
430  pmvMatrix[2][0] = (wfactor * dx) - transform.m33();
431  pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13();
432  pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23();
433  pmvMatrix[2][1] = (hfactor * dy) + transform.m33();
434  pmvMatrix[0][2] = transform.m13();
435  pmvMatrix[1][2] = transform.m23();
436  pmvMatrix[2][2] = transform.m33();
437 
438  // 1/10000 == 0.0001, so we have good enough res to cover curves
439  // that span the entire widget...
440  inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
441  qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
442  qreal(0.0001));
443 
444  matrixDirty = false;
445  matrixUniformDirty = true;
446 
447  // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only
448  // need to do this once for every matrix change and persists across all shader programs.
452 
455 }
456 
457 
459 {
460  // NOTE: The entire paint engine works on pre-multiplied data - which is why some of these
461  // composition modes look odd.
462 // qDebug() << "QGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode;
463  switch(q->state()->composition_mode) {
465  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
466  break;
468  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
469  break;
471  glBlendFunc(GL_ZERO, GL_ZERO);
472  break;
474  glBlendFunc(GL_ONE, GL_ZERO);
475  break;
477  glBlendFunc(GL_ZERO, GL_ONE);
478  break;
480  glBlendFunc(GL_DST_ALPHA, GL_ZERO);
481  break;
483  glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
484  break;
486  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);
487  break;
489  glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
490  break;
492  glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
493  break;
495  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);
496  break;
499  break;
501  glBlendFunc(GL_ONE, GL_ONE);
502  break;
503  default:
504  qWarning("Unsupported composition mode");
505  break;
506  }
507 
508  compositionModeDirty = false;
509 }
510 
511 static inline void setCoords(GLfloat *coords, const QGLRect &rect)
512 {
513  coords[0] = rect.left;
514  coords[1] = rect.top;
515  coords[2] = rect.right;
516  coords[3] = rect.top;
517  coords[4] = rect.right;
518  coords[5] = rect.bottom;
519  coords[6] = rect.left;
520  coords[7] = rect.bottom;
521 }
522 
523 void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern)
524 {
525  // Setup for texture drawing
528 
529  if (snapToPixelGrid) {
530  snapToPixelGrid = false;
531  matrixDirty = true;
532  }
533 
534  if (prepareForDraw(opaque))
536 
537  if (pattern) {
538  QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
540  }
541 
542  GLfloat dx = 1.0 / textureSize.width();
543  GLfloat dy = 1.0 / textureSize.height();
544 
545  QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy);
546 
548  setCoords(staticTextureCoordinateArray, srcTextureRect);
549 
550  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
551 }
552 
554 {
556  ensureActive();
557  d->transferMode(BrushDrawingMode);
558 
559  d->nativePaintingActive = true;
560 
561  QGLContext *ctx = d->ctx;
562  glUseProgram(0);
563 
564  // Disable all the vertex attribute arrays:
565  for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
567 
568 #ifndef QT_OPENGL_ES_2
569  const QGLFormat &fmt = d->device->format();
570  if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1)
571  || (fmt.majorVersion() == 3 && fmt.minorVersion() == 1 && d->hasCompatibilityExtension)
573  {
574  // be nice to people who mix OpenGL 1.x code with QPainter commands
575  // by setting modelview and projection matrices to mirror the GL 1
576  // paint engine
577  const QTransform& mtx = state()->matrix;
578 
579  float mv_matrix[4][4] =
580  {
581  { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) },
582  { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) },
583  { 0, 0, 1, 0 },
584  { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) }
585  };
586 
587  const QSize sz = d->device->size();
588 
589  glMatrixMode(GL_PROJECTION);
590  glLoadIdentity();
591  glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);
592 
593  glMatrixMode(GL_MODELVIEW);
594  glLoadMatrixf(&mv_matrix[0][0]);
595  }
596 #else
597  Q_UNUSED(ctx);
598 #endif
599 
600  d->lastTextureUsed = GLuint(-1);
601  d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
602  d->resetGLState();
603 
604  d->shaderManager->setDirty();
605 
606  d->needsSync = true;
607 }
608 
610 {
611  glDisable(GL_BLEND);
613  glDisable(GL_STENCIL_TEST);
614  glDisable(GL_DEPTH_TEST);
615  glDisable(GL_SCISSOR_TEST);
616  glDepthMask(true);
617  glDepthFunc(GL_LESS);
618  glClearDepth(1);
619  glStencilMask(0xff);
620  glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
621  glStencilFunc(GL_ALWAYS, 0, 0xff);
622  ctx->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
623  ctx->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false);
624  ctx->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
625 #ifndef QT_OPENGL_ES_2
626  // gl_Color, corresponding to vertex attribute 3, may have been changed
627  float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
628  glVertexAttrib4fv(3, color);
629 #endif
630 }
631 
633 {
635  d->needsSync = true;
636  d->nativePaintingActive = false;
637 }
638 
640 {
642  d->needsSync = true;
643 }
644 
646  Q_D(const QGL2PaintEngineEx);
647  return d->nativePaintingActive;
648 }
649 
651 {
652  if (newMode == mode)
653  return;
654 
656  lastTextureUsed = GLuint(-1);
657  }
658 
659  if (newMode == TextDrawingMode) {
661  } else {
663  }
664 
665  imageDrawingMode = false;
666 
667  if (newMode == ImageDrawingMode) {
670  imageDrawingMode = true;
671  }
672 
673  if (newMode == ImageArrayDrawingMode || newMode == ImageArrayWithOpacityDrawingMode) {
676  imageDrawingMode = true;
677  }
678 
679  if (newMode == ImageArrayWithOpacityDrawingMode) {
681  }
682 
683  // This needs to change when we implement high-quality anti-aliasing...
684  if (newMode != TextDrawingMode)
686 
687  mode = newMode;
688 }
689 
691 {
692 #ifdef QT_OPENGL_CACHE_AS_VBOS
693  GLuint vbo;
694  GLuint ibo;
695 #else
696  float *vertices;
697  void *indices;
698 #endif
703 };
704 
706 {
708 #ifdef QT_OPENGL_CACHE_AS_VBOS
709  Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
710  static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
711  if (c->ibo)
712  d->unusedIBOSToClean << c->ibo;
713 #else
714  Q_UNUSED(engine);
715  qFree(c->vertices);
716  qFree(c->indices);
717 #endif
718  delete c;
719 }
720 
721 // Assumes everything is configured for the brush you want to use
723 {
725 
726  if (snapToPixelGrid) {
727  snapToPixelGrid = false;
728  matrixDirty = true;
729  }
730 
731  // Might need to call updateMatrix to re-calculate inverseScale
732  if (matrixDirty)
733  updateMatrix();
734 
735  const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
736 
737  // Check to see if there's any hints
738  if (path.shape() == QVectorPath::RectangleHint) {
739  QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
741  composite(rect);
742  } else if (path.isConvex()) {
743 
744  if (path.isCacheable()) {
746  QGL2PEVectorPathCache *cache;
747 
748  bool updateCache = false;
749 
750  if (data) {
751  cache = (QGL2PEVectorPathCache *) data->data;
752  // Check if scale factor is exceeded for curved paths and generate curves if so...
753  if (path.isCurved()) {
754  qreal scaleFactor = cache->iscale / inverseScale;
755  if (scaleFactor < 0.5 || scaleFactor > 2.0) {
756 #ifdef QT_OPENGL_CACHE_AS_VBOS
757  glDeleteBuffers(1, &cache->vbo);
758  cache->vbo = 0;
759  Q_ASSERT(cache->ibo == 0);
760 #else
761  qFree(cache->vertices);
762  Q_ASSERT(cache->indices == 0);
763 #endif
764  updateCache = true;
765  }
766  }
767  } else {
768  cache = new QGL2PEVectorPathCache;
769  data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
770  updateCache = true;
771  }
772 
773  // Flatten the path at the current scale factor and fill it into the cache struct.
774  if (updateCache) {
777  int vertexCount = vertexCoordinateArray.vertexCount();
778  int floatSizeInBytes = vertexCount * 2 * sizeof(float);
779  cache->vertexCount = vertexCount;
780  cache->indexCount = 0;
782  cache->iscale = inverseScale;
783 #ifdef QT_OPENGL_CACHE_AS_VBOS
784  glGenBuffers(1, &cache->vbo);
785  glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
787  cache->ibo = 0;
788 #else
789  cache->vertices = (float *) qMalloc(floatSizeInBytes);
790  memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
791  cache->indices = 0;
792 #endif
793  }
794 
796 #ifdef QT_OPENGL_CACHE_AS_VBOS
797  glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
799 #else
801 #endif
802  glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
803 
804  } else {
805  // printf(" - Marking path as cachable...\n");
806  // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
807  path.makeCacheable();
812  }
813 
814  } else {
815  bool useCache = path.isCacheable();
816  if (useCache) {
817  QRectF bbox = path.controlPointRect();
818  // If the path doesn't fit within these limits, it is possible that the triangulation will fail.
819  useCache &= (bbox.left() > -0x8000 * inverseScale)
820  && (bbox.right() < 0x8000 * inverseScale)
821  && (bbox.top() > -0x8000 * inverseScale)
822  && (bbox.bottom() < 0x8000 * inverseScale);
823  }
824 
825  if (useCache) {
827  QGL2PEVectorPathCache *cache;
828 
829  bool updateCache = false;
830 
831  if (data) {
832  cache = (QGL2PEVectorPathCache *) data->data;
833  // Check if scale factor is exceeded for curved paths and generate curves if so...
834  if (path.isCurved()) {
835  qreal scaleFactor = cache->iscale / inverseScale;
836  if (scaleFactor < 0.5 || scaleFactor > 2.0) {
837 #ifdef QT_OPENGL_CACHE_AS_VBOS
838  glDeleteBuffers(1, &cache->vbo);
839  glDeleteBuffers(1, &cache->ibo);
840 #else
841  qFree(cache->vertices);
842  qFree(cache->indices);
843 #endif
844  updateCache = true;
845  }
846  }
847  } else {
848  cache = new QGL2PEVectorPathCache;
849  data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
850  updateCache = true;
851  }
852 
853  // Flatten the path at the current scale factor and fill it into the cache struct.
854  if (updateCache) {
855  QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
856  cache->vertexCount = polys.vertices.size() / 2;
857  cache->indexCount = polys.indices.size();
858  cache->primitiveType = GL_TRIANGLES;
859  cache->iscale = inverseScale;
860 #ifdef QT_OPENGL_CACHE_AS_VBOS
861  glGenBuffers(1, &cache->vbo);
862  glGenBuffers(1, &cache->ibo);
863  glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
865 
868  else
870 
871  QVarLengthArray<float> vertices(polys.vertices.size());
872  for (int i = 0; i < polys.vertices.size(); ++i)
873  vertices[i] = float(inverseScale * polys.vertices.at(i));
874  glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
875 #else
876  cache->vertices = (float *) qMalloc(sizeof(float) * polys.vertices.size());
878  cache->indices = (quint32 *) qMalloc(sizeof(quint32) * polys.indices.size());
879  memcpy(cache->indices, polys.indices.data(), sizeof(quint32) * polys.indices.size());
880  } else {
881  cache->indices = (quint16 *) qMalloc(sizeof(quint16) * polys.indices.size());
882  memcpy(cache->indices, polys.indices.data(), sizeof(quint16) * polys.indices.size());
883  }
884  for (int i = 0; i < polys.vertices.size(); ++i)
885  cache->vertices[i] = float(inverseScale * polys.vertices.at(i));
886 #endif
887  }
888 
890 #ifdef QT_OPENGL_CACHE_AS_VBOS
891  glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
895  glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
896  else
897  glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0);
900 #else
903  glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices);
904  else
905  glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices);
906 #endif
907 
908  } else {
909  // printf(" - Marking path as cachable...\n");
910  // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
911  path.makeCacheable();
912 
913  if (!device->format().stencil()) {
914  // If there is no stencil buffer, triangulate the path instead.
915 
916  QRectF bbox = path.controlPointRect();
917  // If the path doesn't fit within these limits, it is possible that the triangulation will fail.
918  bool withinLimits = (bbox.left() > -0x8000 * inverseScale)
919  && (bbox.right() < 0x8000 * inverseScale)
920  && (bbox.top() > -0x8000 * inverseScale)
921  && (bbox.bottom() < 0x8000 * inverseScale);
922  if (withinLimits) {
923  QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
924 
925  QVarLengthArray<float> vertices(polys.vertices.size());
926  for (int i = 0; i < polys.vertices.size(); ++i)
927  vertices[i] = float(inverseScale * polys.vertices.at(i));
928 
930  setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData());
932  glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data());
933  else
934  glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data());
935  } else {
936  // We can't handle big, concave painter paths with OpenGL without stencil buffer.
937  qWarning("Painter path exceeds +/-32767 pixels.");
938  }
939  return;
940  }
941 
942  // The path is too complicated & needs the stencil technique
945 
947 
948  glStencilMask(0xff);
949  glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
950 
951  if (q->state()->clipTestEnabled) {
952  // Pass when high bit is set, replace stencil value with current clip
953  glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
954  } else if (path.hasWindingFill()) {
955  // Pass when any bit is set, replace stencil value with 0
956  glStencilFunc(GL_NOTEQUAL, 0, 0xff);
957  } else {
958  // Pass when high bit is set, replace stencil value with 0
959  glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
960  }
962 
963  // Stencil the brush onto the dest buffer
965  glStencilMask(0);
967  }
968  }
969 }
970 
971 
973  int count,
974  int *stops,
975  int stopCount,
976  const QGLRect &bounds,
978 {
979  Q_ASSERT(count || stops);
980 
981 // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()");
982  glStencilMask(0xff); // Enable stencil writes
983 
986  glClearStencil(0); // Clear to zero
987  for (int i = 0; i < clearRegion.size(); ++i) {
988 #ifndef QT_GL_NO_SCISSOR_TEST
989  setScissor(clearRegion.at(i));
990 #endif
991  glClear(GL_STENCIL_BUFFER_BIT);
992  }
993 
995 
996 #ifndef QT_GL_NO_SCISSOR_TEST
998 #endif
999  }
1000 
1001  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
1002  useSimpleShader();
1003  glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
1004 
1005  if (mode == WindingFillMode) {
1006  Q_ASSERT(stops && !count);
1007  if (q->state()->clipTestEnabled) {
1008  // Flatten clip values higher than current clip, and set high bit to match current clip
1010  glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1011  composite(bounds);
1012 
1014  } else if (!stencilClean) {
1015  // Clear stencil buffer within bounding rect
1016  glStencilFunc(GL_ALWAYS, 0, 0xff);
1017  glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
1018  composite(bounds);
1019  }
1020 
1021  // Inc. for front-facing triangle
1023  // Dec. for back-facing "holes"
1025  glStencilMask(~GL_STENCIL_HIGH_BIT);
1026  drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
1027 
1028  if (q->state()->clipTestEnabled) {
1029  // Clear high bit of stencil outside of path
1030  glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
1031  glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1032  glStencilMask(GL_STENCIL_HIGH_BIT);
1033  composite(bounds);
1034  }
1035  } else if (mode == OddEvenFillMode) {
1036  glStencilMask(GL_STENCIL_HIGH_BIT);
1037  glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
1038  drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN);
1039 
1040  } else { // TriStripStrokeFillMode
1041  Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops
1042  glStencilMask(GL_STENCIL_HIGH_BIT);
1043 #if 0
1044  glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
1046  glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
1047 #else
1048 
1049  glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1050  if (q->state()->clipTestEnabled) {
1051  glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT,
1053  } else {
1054  glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
1055  }
1057  glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
1058 #endif
1059  }
1060 
1061  // Enable color writes & disable stencil writes
1062  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1063 }
1064 
1065 /*
1066  If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1,
1067  restore the stencil buffer to a pristine state. The current clip region
1068  is set to 1, and the rest to 0.
1069 */
1071 {
1072  if (maxClip != (GL_STENCIL_HIGH_BIT - 1))
1073  return;
1074 
1076 
1077  useSimpleShader();
1078  glEnable(GL_STENCIL_TEST);
1079  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1080 
1081  QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height));
1082  QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
1083 
1084  // Set high bit on clip region
1085  glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff);
1086  glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
1087  glStencilMask(GL_STENCIL_HIGH_BIT);
1088  composite(rect);
1089 
1090  // Reset clipping to 1 and everything else to zero
1091  glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT);
1092  glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE);
1093  glStencilMask(0xff);
1094  composite(rect);
1095 
1096  q->state()->currentClip = 1;
1097  q->state()->canRestoreClip = false;
1098 
1099  maxClip = 1;
1100 
1101  glStencilMask(0x0);
1102  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1103 }
1104 
1105 bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
1106 {
1109 
1112 
1113  if (matrixDirty)
1114  updateMatrix();
1115 
1116  const bool stateHasOpacity = q->state()->opacity < 0.99f;
1119  && srcPixelsAreOpaque && !stateHasOpacity))
1120  {
1121  glDisable(GL_BLEND);
1122  } else {
1123  glEnable(GL_BLEND);
1124  }
1125 
1129  } else {
1130  opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity
1132  if (stateHasOpacity && !imageDrawingMode) {
1133  // Using a brush
1134  bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
1136 
1137  if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern)
1138  opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader
1139  }
1140  }
1141  shaderManager->setOpacityMode(opacityMode);
1142 
1143  bool changed = shaderManager->useCorrectShaderProg();
1144  // If the shader program needs changing, we change it and mark all uniforms as dirty
1145  if (changed) {
1146  // The shader program has changed so mark all uniforms as dirty:
1147  brushUniformsDirty = true;
1148  opacityUniformDirty = true;
1149  matrixUniformDirty = true;
1150  }
1151 
1154 
1157  opacityUniformDirty = false;
1158  }
1159 
1162  pmvMatrix);
1163  matrixUniformDirty = false;
1164  }
1165 
1166  return changed;
1167 }
1168 
1170 {
1171  setCoords(staticVertexCoordinateArray, boundingRect);
1173  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1174 }
1175 
1176 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
1177 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
1178  GLenum primitive)
1179 {
1180  // Now setup the pointer to the vertex array:
1182 
1183  int previousStop = 0;
1184  for (int i=0; i<stopCount; ++i) {
1185  int stop = stops[i];
1186 /*
1187  qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
1188  for (int i=previousStop; i<stop; ++i)
1189  qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
1190 */
1191  glDrawArrays(primitive, previousStop, stop - previousStop);
1192  previousStop = stop;
1193  }
1194 }
1195 
1197 
1200 {
1201 }
1202 
1204 {
1205 }
1206 
1207 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
1208 {
1210 
1211  if (qbrush_style(brush) == Qt::NoBrush)
1212  return;
1213  ensureActive();
1214  d->setBrush(brush);
1215  d->fill(path);
1216 }
1217 
1218 Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
1219 
1220 
1221 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
1222 {
1224 
1225  const QBrush &penBrush = qpen_brush(pen);
1226  if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush)
1227  return;
1228 
1230  if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) {
1231  // QTriangulatingStroker class is not meant to support cosmetically sheared strokes.
1232  QPaintEngineEx::stroke(path, pen);
1233  return;
1234  }
1235 
1236  ensureActive();
1237  d->setBrush(penBrush);
1238  d->stroke(path, pen);
1239 }
1240 
1242 {
1243  const QOpenGL2PaintEngineState *s = q->state();
1244  if (snapToPixelGrid) {
1245  snapToPixelGrid = false;
1246  matrixDirty = true;
1247  }
1248 
1249  const Qt::PenStyle penStyle = qpen_style(pen);
1250  const QBrush &penBrush = qpen_brush(pen);
1251  const bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
1252 
1253  transferMode(BrushDrawingMode);
1254 
1255  // updateMatrix() is responsible for setting the inverse scale on
1256  // the strokers, so we need to call it here and not wait for
1257  // prepareForDraw() down below.
1258  updateMatrix();
1259 
1260  QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled
1261  ? q->state()->rectangleClip
1262  : QRectF(0, 0, width, height));
1263 
1264  if (penStyle == Qt::SolidLine) {
1265  stroker.process(path, pen, clip);
1266 
1267  } else { // Some sort of dash
1268  dasher.process(path, pen, clip);
1269 
1270  QVectorPath dashStroke(dasher.points(),
1271  dasher.elementCount(),
1272  dasher.elementTypes());
1273  stroker.process(dashStroke, pen, clip);
1274  }
1275 
1276  if (!stroker.vertexCount())
1277  return;
1278 
1279  if (opaque) {
1280  prepareForDraw(opaque);
1281  setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
1282  glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
1283 
1284 // QBrush b(Qt::green);
1285 // d->setBrush(&b);
1286 // d->prepareForDraw(true);
1287 // glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
1288 
1289  } else {
1290  qreal width = qpen_widthf(pen) / 2;
1291  if (width == 0)
1292  width = 0.5;
1293  qreal extra = pen.joinStyle() == Qt::MiterJoin
1294  ? qMax(pen.miterLimit() * width, width)
1295  : width;
1296 
1297  if (pen.isCosmetic())
1298  extra = extra * inverseScale;
1299 
1300  QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
1301 
1302  fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2,
1304 
1305  glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
1306 
1307  // Pass when any bit is set, replace stencil value with 0
1308  glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
1309  prepareForDraw(false);
1310 
1311  // Stencil the brush onto the dest buffer
1312  composite(bounds);
1313 
1314  glStencilMask(0);
1315 
1316  updateClipScissorTest();
1317  }
1318 }
1319 
1323 
1325 {
1326 // qDebug("QGL2PaintEngineEx::opacityChanged()");
1328  state()->opacityChanged = true;
1329 
1330  Q_ASSERT(d->shaderManager);
1331  d->brushUniformsDirty = true;
1332  d->opacityUniformDirty = true;
1333 }
1334 
1336 {
1337 // qDebug("QGL2PaintEngineEx::compositionModeChanged()");
1339  state()->compositionModeChanged = true;
1340  d->compositionModeDirty = true;
1341 }
1342 
1344 {
1345  state()->renderHintsChanged = true;
1346 
1347 #if !defined(QT_OPENGL_ES_2)
1348  if ((state()->renderHints & QPainter::Antialiasing)
1349  || (state()->renderHints & QPainter::HighQualityAntialiasing))
1350  glEnable(GL_MULTISAMPLE);
1351  else
1352  glDisable(GL_MULTISAMPLE);
1353 #endif
1354 
1356  d->lastTextureUsed = GLuint(-1);
1357  d->brushTextureDirty = true;
1358 // qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
1359 }
1360 
1362 {
1364  d->matrixDirty = true;
1365  state()->matrixChanged = true;
1366 }
1367 
1368 
1369 static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy)
1370 {
1371  return QRectF(r.x() * sx, r.y() * sy, r.width() * sx, r.height() * sy);
1372 }
1373 
1374 void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src)
1375 {
1377  QGLContext *ctx = d->ctx;
1378 
1379  int max_texture_size = ctx->d_func()->maxTextureSize();
1380  if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) {
1381  QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
1382 
1383  const qreal sx = scaled.width() / qreal(pixmap.width());
1384  const qreal sy = scaled.height() / qreal(pixmap.height());
1385 
1386  drawPixmap(dest, scaled, scaleRect(src, sx, sy));
1387  return;
1388  }
1389 
1390  ensureActive();
1391  d->transferMode(ImageDrawingMode);
1392 
1394  QGLTexture *texture =
1395  ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
1398 
1399  GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top();
1400  GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom();
1401  QGLRect srcRect(src.left(), top, src.right(), bottom);
1402 
1403  bool isBitmap = pixmap.isQBitmap();
1404  bool isOpaque = !isBitmap && !pixmap.hasAlpha();
1405 
1406  d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
1407  state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
1408  d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap);
1409 }
1410 
1411 void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src,
1412  Qt::ImageConversionFlags)
1413 {
1415  QGLContext *ctx = d->ctx;
1416 
1417  int max_texture_size = ctx->d_func()->maxTextureSize();
1418  if (image.width() > max_texture_size || image.height() > max_texture_size) {
1419  QImage scaled = image.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
1420 
1421  const qreal sx = scaled.width() / qreal(image.width());
1422  const qreal sy = scaled.height() / qreal(image.height());
1423 
1424  drawImage(dest, scaled, scaleRect(src, sx, sy));
1425  return;
1426  }
1427 
1428  ensureActive();
1429  d->transferMode(ImageDrawingMode);
1430 
1432 
1433  QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
1434  GLuint id = texture->id;
1435 
1436  d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
1437  state()->renderHints & QPainter::SmoothPixmapTransform, id);
1438  d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
1439 }
1440 
1442 {
1444 
1445  ensureActive();
1446 
1447  QPainterState *s = state();
1448  float det = s->matrix.determinant();
1449 
1450  // don't try to cache huge fonts or vastly transformed fonts
1451  QFontEngine *fontEngine = textItem->fontEngine();
1452  const qreal pixelSize = fontEngine->fontDef.pixelSize;
1453  if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE && det >= 0.25f && det <= 4.f) {
1454  QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0
1456  : d->glyphCacheType;
1457  if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
1459  || d->device->alphaRequested() || s->matrix.type() > QTransform::TxTranslate
1462  {
1464  }
1465  }
1466 
1467  d->drawCachedGlyphs(glyphType, textItem);
1468  } else {
1470  }
1471 }
1472 
1473 bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
1474 {
1476  if (!d->shaderManager)
1477  return false;
1478 
1479  ensureActive();
1480  d->transferMode(ImageDrawingMode);
1481 
1482 #ifndef QT_OPENGL_ES_2
1483  QGLContext *ctx = d->ctx;
1484 #endif
1486  glBindTexture(GL_TEXTURE_2D, textureId);
1487 
1488  QGLRect srcRect(src.left(), src.bottom(), src.right(), src.top());
1489 
1490  d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
1491  state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
1492  d->drawTexture(dest, srcRect, size, false);
1493  return true;
1494 }
1495 
1496 void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
1497 {
1499 
1500  ensureActive();
1502 
1503  const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1504 
1506 
1507  float det = s->matrix.determinant();
1508  bool drawCached = txtype < QTransform::TxProject;
1509 
1510  // don't try to cache huge fonts or vastly transformed fonts
1512  if (pixelSize * pixelSize * qAbs(det) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE ||
1513  det < 0.25f || det > 4.f)
1514  drawCached = false;
1515 
1518  : d->glyphCacheType;
1519 
1520 
1521  if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
1523  || d->device->alphaRequested() || txtype > QTransform::TxTranslate
1526  {
1528  }
1529  }
1530 
1531  if (drawCached) {
1533  QVarLengthArray<glyph_t> glyphs;
1534  QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
1535  ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1536 
1537  {
1538  QStaticTextItem staticTextItem;
1539  staticTextItem.chars = const_cast<QChar *>(ti.chars);
1540  staticTextItem.setFontEngine(ti.fontEngine);
1541  staticTextItem.glyphs = glyphs.data();
1542  staticTextItem.numChars = ti.num_chars;
1543  staticTextItem.numGlyphs = glyphs.size();
1544  staticTextItem.glyphPositions = positions.data();
1545 
1546  d->drawCachedGlyphs(glyphType, &staticTextItem);
1547  }
1548  return;
1549  }
1550 
1552 }
1553 
1554 namespace {
1555 
1556  class QOpenGLStaticTextUserData: public QStaticTextUserData
1557  {
1558  public:
1559  QOpenGLStaticTextUserData()
1560  : QStaticTextUserData(OpenGLUserData), cacheSize(0, 0), cacheSerialNumber(0)
1561  {
1562  }
1563 
1564  ~QOpenGLStaticTextUserData()
1565  {
1566  }
1567 
1568  QSize cacheSize;
1569  QGL2PEXVertexArray vertexCoordinateArray;
1570  QGL2PEXVertexArray textureCoordinateArray;
1571  QFontEngineGlyphCache::Type glyphType;
1572  int cacheSerialNumber;
1573  };
1574 
1575 }
1576 
1577 #if defined(Q_WS_WIN)
1579 {
1580  extern Q_GUI_EXPORT qreal qt_fontsmoothing_gamma; // qapplication_win.cpp
1581  return (qAbs(qt_fontsmoothing_gamma - target) < 0.2);
1582 }
1583 #endif
1584 
1586 {
1587  return f > 0.04045 ? qPow((f + 0.055) / 1.055, 2.4) : f / 12.92;
1588 }
1589 
1590 // #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO
1591 
1593  QStaticTextItem *staticTextItem)
1594 {
1596 
1597  QOpenGL2PaintEngineState *s = q->state();
1598 
1599  void *cacheKey = const_cast<QGLContext *>(QGLContextPrivate::contextGroup(ctx)->context());
1600  bool recreateVertexArrays = false;
1601 
1602  QGLTextureGlyphCache *cache =
1603  (QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(cacheKey, glyphType, QTransform());
1604  if (!cache || cache->cacheType() != glyphType || cache->context() == 0) {
1605  cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
1606  staticTextItem->fontEngine()->setGlyphCache(cacheKey, cache);
1607  cache->insert(ctx, cache);
1608  recreateVertexArrays = true;
1609  }
1610 
1611  if (staticTextItem->userDataNeedsUpdate) {
1612  recreateVertexArrays = true;
1613  } else if (staticTextItem->userData() == 0) {
1614  recreateVertexArrays = true;
1615  } else if (staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) {
1616  recreateVertexArrays = true;
1617  } else {
1618  QOpenGLStaticTextUserData *userData = static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData());
1619  if (userData->glyphType != glyphType) {
1620  recreateVertexArrays = true;
1621  } else if (userData->cacheSerialNumber != cache->serialNumber()) {
1622  recreateVertexArrays = true;
1623  }
1624  }
1625 
1626  // We only need to update the cache with new glyphs if we are actually going to recreate the vertex arrays.
1627  // If the cache size has changed, we do need to regenerate the vertices, but we don't need to repopulate the
1628  // cache so this text is performed before we test if the cache size has changed.
1629  if (recreateVertexArrays) {
1630  cache->setPaintEnginePrivate(this);
1631  if (!cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs,
1632  staticTextItem->glyphs, staticTextItem->glyphPositions)) {
1633  // No space for glyphs in cache. We need to reset it and try again.
1634  cache->clear();
1635  cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs,
1636  staticTextItem->glyphs, staticTextItem->glyphPositions);
1637  }
1638  cache->fillInPendingGlyphs();
1639  }
1640 
1641  if (cache->width() == 0 || cache->height() == 0)
1642  return;
1643 
1644  transferMode(TextDrawingMode);
1645 
1646  int margin = cache->glyphMargin();
1647 
1648  GLfloat dx = 1.0 / cache->width();
1649  GLfloat dy = 1.0 / cache->height();
1650 
1651  // Use global arrays by default
1652  QGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray;
1653  QGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray;
1654 
1655  if (staticTextItem->useBackendOptimizations) {
1656  QOpenGLStaticTextUserData *userData = 0;
1657 
1658  if (staticTextItem->userData() == 0
1659  || staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) {
1660 
1661  userData = new QOpenGLStaticTextUserData();
1662  staticTextItem->setUserData(userData);
1663 
1664  } else {
1665  userData = static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData());
1666  }
1667 
1668  userData->glyphType = glyphType;
1669  userData->cacheSerialNumber = cache->serialNumber();
1670 
1671  // Use cache if backend optimizations is turned on
1672  vertexCoordinates = &userData->vertexCoordinateArray;
1673  textureCoordinates = &userData->textureCoordinateArray;
1674 
1675  QSize size(cache->width(), cache->height());
1676  if (userData->cacheSize != size) {
1677  recreateVertexArrays = true;
1678  userData->cacheSize = size;
1679  }
1680  }
1681 
1682  if (recreateVertexArrays) {
1683  vertexCoordinates->clear();
1684  textureCoordinates->clear();
1685 
1686  bool supportsSubPixelPositions = staticTextItem->fontEngine()->supportsSubPixelPositions();
1687  for (int i=0; i<staticTextItem->numGlyphs; ++i) {
1688  QFixed subPixelPosition;
1689  if (supportsSubPixelPositions)
1690  subPixelPosition = cache->subPixelPositionForX(staticTextItem->glyphPositions[i].x);
1691 
1692  QTextureGlyphCache::GlyphAndSubPixelPosition glyph(staticTextItem->glyphs[i], subPixelPosition);
1693 
1694  const QTextureGlyphCache::Coord &c = cache->coords[glyph];
1695  if (c.isNull())
1696  continue;
1697 
1698  int x = qFloor(staticTextItem->glyphPositions[i].x) + c.baseLineX - margin;
1699  int y = qFloor(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin;
1700 
1701  vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
1702  textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
1703  }
1704 
1705  staticTextItem->userDataNeedsUpdate = false;
1706  }
1707 
1708  int numGlyphs = vertexCoordinates->vertexCount() / 4;
1709  if (numGlyphs == 0)
1710  return;
1711 
1712  if (elementIndices.size() < numGlyphs*6) {
1713  Q_ASSERT(elementIndices.size() % 6 == 0);
1714  int j = elementIndices.size() / 6 * 4;
1715  while (j < numGlyphs*4) {
1716  elementIndices.append(j + 0);
1717  elementIndices.append(j + 0);
1718  elementIndices.append(j + 1);
1719  elementIndices.append(j + 2);
1720  elementIndices.append(j + 3);
1721  elementIndices.append(j + 3);
1722 
1723  j += 4;
1724  }
1725 
1726 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
1727  if (elementIndicesVBOId == 0)
1728  glGenBuffers(1, &elementIndicesVBOId);
1729 
1730  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
1731  glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort),
1732  elementIndices.constData(), GL_STATIC_DRAW);
1733 #endif
1734  } else {
1735 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
1736  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
1737 #endif
1738  }
1739 
1740  setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
1741  setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
1742 
1743  if (!snapToPixelGrid) {
1744  snapToPixelGrid = true;
1745  matrixDirty = true;
1746  }
1747 
1748  QBrush pensBrush = q->state()->pen.brush();
1749 
1750  bool srgbFrameBufferEnabled = false;
1751  if (pensBrush.style() == Qt::SolidPattern &&
1752  (ctx->d_ptr->extension_flags & QGLExtensions::SRGBFrameBuffer)) {
1753 #if defined(Q_WS_MAC)
1754  if (glyphType == QFontEngineGlyphCache::Raster_RGBMask)
1755 #elif defined(Q_WS_WIN)
1757 #else
1758  if (false)
1759 #endif
1760  {
1761  QColor c = pensBrush.color();
1765  c = QColor::fromRgbF(red, green, blue, c.alphaF());
1766  pensBrush.setColor(c);
1767 
1768  glEnable(FRAMEBUFFER_SRGB_EXT);
1769  srgbFrameBufferEnabled = true;
1770  }
1771  }
1772 
1773  setBrush(pensBrush);
1774 
1775  if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
1776  // Subpixel antialiasing with gamma correction
1777  QPainter::CompositionMode compMode = q->state()->composition_mode;
1779  || compMode == QPainter::CompositionMode_SourceOver);
1780 
1781  shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass1);
1782 
1783  if (pensBrush.style() == Qt::SolidPattern) {
1784  // Solid patterns can get away with only one pass.
1785  QColor c = pensBrush.color();
1786  qreal oldOpacity = q->state()->opacity;
1787  if (compMode == QPainter::CompositionMode_Source) {
1788  c = qt_premultiplyColor(c, q->state()->opacity);
1789  q->state()->opacity = 1;
1790  opacityUniformDirty = true;
1791  }
1792 
1793  compositionModeDirty = false; // I can handle this myself, thank you very much
1794  prepareForDraw(false); // Text always causes src pixels to be transparent
1795 
1796  // prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset.
1797  if (compMode == QPainter::CompositionMode_Source) {
1798  q->state()->opacity = oldOpacity;
1799  opacityUniformDirty = true;
1800  }
1801 
1802  glEnable(GL_BLEND);
1804  glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
1805  } else {
1806  // Other brush styles need two passes.
1807 
1808  qreal oldOpacity = q->state()->opacity;
1809  if (compMode == QPainter::CompositionMode_Source) {
1810  q->state()->opacity = 1;
1811  opacityUniformDirty = true;
1812  pensBrush = Qt::white;
1813  setBrush(pensBrush);
1814  }
1815 
1816  compositionModeDirty = false; // I can handle this myself, thank you very much
1817  prepareForDraw(false); // Text always causes src pixels to be transparent
1818  glEnable(GL_BLEND);
1819  glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
1820 
1822  glBindTexture(GL_TEXTURE_2D, cache->texture());
1823 #if !defined(QT_NO_DEBUG) && defined(QT_OPENGL_ES_2)
1825  bool npotSupported = funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures);
1826  bool isNpot = !isPowerOfTwo(cache->width())
1827  || !isPowerOfTwo(cache->height());
1828  if (isNpot && !npotSupported) {
1829  qWarning("GL2 Paint Engine: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
1830  }
1831 #endif
1833 
1834 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
1835  glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
1836 #else
1837  glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
1838 #endif
1839 
1840  shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
1841 
1842  if (compMode == QPainter::CompositionMode_Source) {
1843  q->state()->opacity = oldOpacity;
1844  opacityUniformDirty = true;
1845  pensBrush = q->state()->pen.brush();
1846  setBrush(pensBrush);
1847  }
1848 
1849  compositionModeDirty = false;
1850  prepareForDraw(false); // Text always causes src pixels to be transparent
1851  glEnable(GL_BLEND);
1852  glBlendFunc(GL_ONE, GL_ONE);
1853  }
1854  compositionModeDirty = true;
1855  } else {
1856  // Greyscale/mono glyphs
1857 
1858  shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
1859  prepareForDraw(false); // Text always causes src pixels to be transparent
1860  }
1861 
1863  if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) {
1864 
1866  if (lastMaskTextureUsed != cache->texture()) {
1867  glBindTexture(GL_TEXTURE_2D, cache->texture());
1868  lastMaskTextureUsed = cache->texture();
1869  }
1870 
1871  if (cache->filterMode() != filterMode) {
1872  if (filterMode == QGLTextureGlyphCache::Linear) {
1873  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1874  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1875  } else {
1876  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1877  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1878  }
1879  cache->setFilterMode(filterMode);
1880  }
1881  }
1882 
1883 #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
1884  glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
1886 #else
1887  glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
1888 #endif
1889 
1890  if (srgbFrameBufferEnabled)
1891  glDisable(FRAMEBUFFER_SRGB_EXT);
1892 
1893 }
1894 
1895 void QGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
1896  QPainter::PixmapFragmentHints hints)
1897 {
1899  // Use fallback for extended composition modes.
1900  if (state()->composition_mode > QPainter::CompositionMode_Plus) {
1901  QPaintEngineEx::drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
1902  return;
1903  }
1904 
1905  QSize size = pixmap.size();
1906 
1907  ensureActive();
1908  int max_texture_size = d->ctx->d_func()->maxTextureSize();
1909  if (size.width() > max_texture_size || size.height() > max_texture_size) {
1910  QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
1911  d->drawPixmapFragments(fragments, fragmentCount, scaled, size, hints);
1912  } else {
1913  d->drawPixmapFragments(fragments, fragmentCount, pixmap, size, hints);
1914  }
1915 }
1916 
1917 void QGL2PaintEngineEx::drawPixmapFragments(const QRectF *targetRects, const QRectF *sourceRects, int fragmentCount, const QPixmap &pixmap,
1918  QPainter::PixmapFragmentHints hints)
1919 {
1921  // Use fallback for extended composition modes.
1922  if (state()->composition_mode > QPainter::CompositionMode_Plus) {
1923  QPaintEngineEx::drawPixmapFragments(targetRects, sourceRects, fragmentCount, pixmap, hints);
1924  return;
1925  }
1926 
1927  QSize size = pixmap.size();
1928 
1929  ensureActive();
1930  int max_texture_size = d->ctx->d_func()->maxTextureSize();
1931  if (size.width() > max_texture_size || size.height() > max_texture_size) {
1932  QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
1933  d->drawPixmapFragments(targetRects, sourceRects, fragmentCount, scaled, size, hints);
1934  } else {
1935  d->drawPixmapFragments(targetRects, sourceRects, fragmentCount, pixmap, size, hints);
1936  }
1937 }
1938 
1940  int fragmentCount, const QPixmap &pixmap,
1941  const QSize &size, QPainter::PixmapFragmentHints hints)
1942 {
1943  GLfloat dx = 1.0f / size.width();
1944  GLfloat dy = 1.0f / size.height();
1945 
1946  vertexCoordinateArray.clear();
1947  textureCoordinateArray.clear();
1948  opacityArray.reset();
1949 
1950  if (snapToPixelGrid) {
1951  snapToPixelGrid = false;
1952  matrixDirty = true;
1953  }
1954 
1955  bool allOpaque = true;
1956 
1957  for (int i = 0; i < fragmentCount; ++i) {
1958  qreal s = 0;
1959  qreal c = 1;
1960  if (fragments[i].rotation != 0) {
1961  s = qFastSin(fragments[i].rotation * Q_PI / 180);
1962  c = qFastCos(fragments[i].rotation * Q_PI / 180);
1963  }
1964 
1965  qreal right = 0.5 * fragments[i].scaleX * fragments[i].width;
1966  qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height;
1967  QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
1968  QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
1969 
1970  vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
1971  vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y);
1972  vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
1973  vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
1974  vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y);
1975  vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
1976 
1977  QGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy,
1978  (fragments[i].sourceLeft + fragments[i].width) * dx,
1979  (fragments[i].sourceTop + fragments[i].height) * dy);
1980 
1981  textureCoordinateArray.addVertex(src.right, src.bottom);
1982  textureCoordinateArray.addVertex(src.right, src.top);
1983  textureCoordinateArray.addVertex(src.left, src.top);
1984  textureCoordinateArray.addVertex(src.left, src.top);
1985  textureCoordinateArray.addVertex(src.left, src.bottom);
1986  textureCoordinateArray.addVertex(src.right, src.bottom);
1987 
1988  qreal opacity = fragments[i].opacity * q->state()->opacity;
1989  opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
1990  allOpaque &= (opacity >= 0.99f);
1991  }
1992 
1994  QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
1997 
1998  if (texture->options & QGLContext::InvertedYBindOption) {
1999  // Flip texture y-coordinate.
2000  QGLPoint *data = textureCoordinateArray.data();
2001  for (int i = 0; i < 6 * fragmentCount; ++i)
2002  data[i].y = 1 - data[i].y;
2003  }
2004 
2005  transferMode(allOpaque ? ImageArrayDrawingMode : ImageArrayWithOpacityDrawingMode);
2006 
2007  bool isBitmap = pixmap.isQBitmap();
2008  bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque;
2009 
2011  q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
2012 
2013  // Setup for texture drawing
2014  currentBrush = noBrush;
2015  shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc
2017  if (prepareForDraw(isOpaque))
2018  shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
2019 
2020  if (isBitmap) {
2021  QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
2022  shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
2023  }
2024 
2025  glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount);
2026 }
2027 
2028 void QGL2PaintEngineExPrivate::drawPixmapFragments(const QRectF *targetRects, const QRectF *sourceRects, int fragmentCount,
2029  const QPixmap &pixmap, const QSize &size,
2030  QPainter::PixmapFragmentHints hints)
2031 {
2032  GLfloat dx = 1.0f / size.width();
2033  GLfloat dy = 1.0f / size.height();
2034 
2035  vertexCoordinateArray.clear();
2036  textureCoordinateArray.clear();
2037 
2038  if (snapToPixelGrid) {
2039  snapToPixelGrid = false;
2040  matrixDirty = true;
2041  }
2042 
2043  for (int i = 0; i < fragmentCount; ++i) {
2044  vertexCoordinateArray.addVertex(targetRects[i].right(), targetRects[i].bottom());
2045  vertexCoordinateArray.addVertex(targetRects[i].right(), targetRects[i].top());
2046  vertexCoordinateArray.addVertex(targetRects[i].left(), targetRects[i].top());
2047  vertexCoordinateArray.addVertex(targetRects[i].left(), targetRects[i].top());
2048  vertexCoordinateArray.addVertex(targetRects[i].left(), targetRects[i].bottom());
2049  vertexCoordinateArray.addVertex(targetRects[i].right(), targetRects[i].bottom());
2050 
2051  QRectF sourceRect = sourceRects ? sourceRects[i] : QRectF(0, 0, size.width(), size.height());
2052 
2053  QGLRect src(sourceRect.left() * dx, sourceRect.top() * dy,
2054  sourceRect.right() * dx, sourceRect.bottom() * dy);
2055 
2056  textureCoordinateArray.addVertex(src.right, src.bottom);
2057  textureCoordinateArray.addVertex(src.right, src.top);
2058  textureCoordinateArray.addVertex(src.left, src.top);
2059  textureCoordinateArray.addVertex(src.left, src.top);
2060  textureCoordinateArray.addVertex(src.left, src.bottom);
2061  textureCoordinateArray.addVertex(src.right, src.bottom);
2062  }
2063 
2065  QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
2068 
2069  if (texture->options & QGLContext::InvertedYBindOption) {
2070  // Flip texture y-coordinate.
2071  QGLPoint *data = textureCoordinateArray.data();
2072  for (int i = 0; i < 6 * fragmentCount; ++i)
2073  data[i].y = 1 - data[i].y;
2074  }
2075 
2076  transferMode(ImageArrayDrawingMode);
2077 
2078  bool isBitmap = pixmap.isQBitmap();
2079  bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint));
2080 
2082  q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
2083 
2084  // Setup for texture drawing
2085  currentBrush = noBrush;
2086  shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc
2088  if (prepareForDraw(isOpaque))
2089  shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
2090 
2091  if (isBitmap) {
2092  QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
2093  shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
2094  }
2095 
2096  glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount);
2097 }
2098 
2100 {
2102 
2103 // qDebug("QGL2PaintEngineEx::begin()");
2104  if (pdev->devType() == QInternal::OpenGL)
2105  d->device = static_cast<QGLPaintDevice*>(pdev);
2106  else
2107  d->device = QGLPaintDevice::getDevice(pdev);
2108 
2109  if (!d->device)
2110  return false;
2111 
2112  d->ctx = d->device->context();
2113 #ifdef Q_OS_SYMBIAN
2114  if (!d->ctx)
2115  return false;
2116 #endif
2117  d->ctx->d_ptr->active_engine = this;
2118 
2119  const QSize sz = d->device->size();
2120  d->width = sz.width();
2121  d->height = sz.height();
2122  d->mode = BrushDrawingMode;
2123  d->imageDrawingMode = false;
2124  d->brushTextureDirty = true;
2125  d->brushUniformsDirty = true;
2126  d->matrixUniformDirty = true;
2127  d->matrixDirty = true;
2128  d->compositionModeDirty = true;
2129  d->opacityUniformDirty = true;
2130  d->needsSync = true;
2131  d->useSystemClip = !systemClip().isEmpty();
2132  d->currentBrush = QBrush();
2133 
2134  d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
2135  d->stencilClean = true;
2136 
2137  // Calling begin paint should make the correct context current. So, any
2138  // code which calls into GL or otherwise needs a current context *must*
2139  // go after beginPaint:
2140  d->device->beginPaint();
2141 
2142 #if !defined(QT_OPENGL_ES_2)
2144  d->hasCompatibilityExtension = extensions.match("GL_ARB_compatibility");
2145 
2146  bool success = qt_resolve_version_2_0_functions(d->ctx)
2150  Q_ASSERT(success);
2151  Q_UNUSED(success);
2152 #endif
2153 
2154  d->shaderManager = new QGLEngineShaderManager(d->ctx);
2155 
2156  glDisable(GL_STENCIL_TEST);
2157  glDisable(GL_DEPTH_TEST);
2158  glDisable(GL_SCISSOR_TEST);
2159 
2160 #if !defined(QT_OPENGL_ES_2)
2161  glDisable(GL_MULTISAMPLE);
2162 #endif
2163 
2164  d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
2165 
2166 #if !defined(QT_OPENGL_ES_2)
2167 #if defined(Q_WS_WIN)
2170 #endif
2171 #if defined(Q_WS_MAC)
2173 #endif
2174  d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
2175 #endif
2176 
2177 #if defined(QT_OPENGL_ES_2)
2178  // OpenGL ES can't switch MSAA off, so if the gl paint device is
2179  // multisampled, it's always multisampled.
2180  d->multisamplingAlwaysEnabled = d->device->format().sampleBuffers();
2181 #else
2182  d->multisamplingAlwaysEnabled = false;
2183 #endif
2184 
2185  return true;
2186 }
2187 
2189 {
2191  QGLContext *ctx = d->ctx;
2192 
2193  glUseProgram(0);
2194  d->transferMode(BrushDrawingMode);
2195  d->device->endPaint();
2196 
2197 #if defined(Q_WS_X11)
2198  // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture
2199  // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes
2200  // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we
2201  // reference all QPixmaps which have been bound to stop them being deleted and only deref
2202  // them here, after swapBuffers, where they can be safely deleted.
2203  ctx->d_func()->boundPixmaps.clear();
2204 #endif
2205  d->ctx->d_ptr->active_engine = 0;
2206 
2207  d->resetGLState();
2208 
2209  delete d->shaderManager;
2210  d->shaderManager = 0;
2211  d->currentBrush = QBrush();
2212 
2213 #ifdef QT_OPENGL_CACHE_AS_VBOS
2214  if (!d->unusedVBOSToClean.isEmpty()) {
2215  glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
2216  d->unusedVBOSToClean.clear();
2217  }
2218  if (!d->unusedIBOSToClean.isEmpty()) {
2219  glDeleteBuffers(d->unusedIBOSToClean.size(), d->unusedIBOSToClean.constData());
2220  d->unusedIBOSToClean.clear();
2221  }
2222 #endif
2223 
2224  return false;
2225 }
2226 
2228 {
2230  QGLContext *ctx = d->ctx;
2231 
2232  if (isActive() && ctx->d_ptr->active_engine != this) {
2233  ctx->d_ptr->active_engine = this;
2234  d->needsSync = true;
2235  }
2236 
2237  d->device->ensureActiveTarget();
2238 
2239  if (d->needsSync) {
2240  d->transferMode(BrushDrawingMode);
2241  glViewport(0, 0, d->width, d->height);
2242  d->needsSync = false;
2243  d->lastMaskTextureUsed = 0;
2244  d->shaderManager->setDirty();
2245  d->ctx->d_func()->syncGlState();
2246  for (int i = 0; i < 3; ++i)
2247  d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered
2248  setState(state());
2249  }
2250 }
2251 
2253 {
2255  if (q->state()->clipTestEnabled) {
2256  glEnable(GL_STENCIL_TEST);
2257  glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
2258  } else {
2259  glDisable(GL_STENCIL_TEST);
2260  glStencilFunc(GL_ALWAYS, 0, 0xff);
2261  }
2262 
2263 #ifdef QT_GL_NO_SCISSOR_TEST
2264  currentScissorBounds = QRect(0, 0, width, height);
2265 #else
2266  QRect bounds = q->state()->rectangleClip;
2267  if (!q->state()->clipEnabled) {
2268  if (useSystemClip)
2269  bounds = systemClip.boundingRect();
2270  else
2271  bounds = QRect(0, 0, width, height);
2272  } else {
2273  if (useSystemClip)
2274  bounds = bounds.intersected(systemClip.boundingRect());
2275  else
2276  bounds = bounds.intersected(QRect(0, 0, width, height));
2277  }
2278 
2279  currentScissorBounds = bounds;
2280 
2281  if (bounds == QRect(0, 0, width, height)) {
2282  if (ctx->d_func()->workaround_brokenScissor)
2283  clearClip(0);
2284  glDisable(GL_SCISSOR_TEST);
2285  } else {
2286  glEnable(GL_SCISSOR_TEST);
2287  setScissor(bounds);
2288  }
2289 #endif
2290 }
2291 
2293 {
2294  const int left = rect.left();
2295  const int width = rect.width();
2296  int bottom = height - (rect.top() + rect.height());
2297  if (device->isFlipped()) {
2298  bottom = rect.top();
2299  }
2300  const int height = rect.height();
2301 
2302  glScissor(left, bottom, width, height);
2303 }
2304 
2306 {
2308 
2309  state()->clipChanged = true;
2310 
2311  if (painter()->hasClipping())
2312  d->regenerateClip();
2313  else
2314  d->systemStateChanged();
2315 }
2316 
2318 {
2319  dirtyStencilRegion -= currentScissorBounds;
2320 
2321  glStencilMask(0xff);
2322  glClearStencil(value);
2323  glClear(GL_STENCIL_BUFFER_BIT);
2324  glStencilMask(0x0);
2325 
2326  q->state()->needsClipBufferClear = false;
2327 }
2328 
2330 {
2331  transferMode(BrushDrawingMode);
2332 
2333  if (snapToPixelGrid) {
2334  snapToPixelGrid = false;
2335  matrixDirty = true;
2336  }
2337 
2338  if (matrixDirty)
2339  updateMatrix();
2340 
2341  stencilClean = false;
2342 
2343  const bool singlePass = !path.hasWindingFill()
2344  && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled)
2345  || q->state()->needsClipBufferClear);
2346  const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip;
2347 
2348  if (q->state()->needsClipBufferClear)
2349  clearClip(1);
2350 
2351  if (path.isEmpty()) {
2352  glEnable(GL_STENCIL_TEST);
2353  glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
2354  return;
2355  }
2356 
2357  if (q->state()->clipTestEnabled)
2358  glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT);
2359  else
2360  glStencilFunc(GL_ALWAYS, 0, 0xff);
2361 
2362  vertexCoordinateArray.clear();
2363  vertexCoordinateArray.addPath(path, inverseScale, false);
2364 
2365  if (!singlePass)
2366  fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
2367 
2368  glColorMask(false, false, false, false);
2369  glEnable(GL_STENCIL_TEST);
2370  useSimpleShader();
2371 
2372  if (singlePass) {
2373  // Under these conditions we can set the new stencil value in a single
2374  // pass, by using the current value and the "new value" as the toggles
2375 
2376  glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT);
2377  glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
2378  glStencilMask(value ^ referenceClipValue);
2379 
2380  drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
2381  } else {
2382  glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
2383  glStencilMask(0xff);
2384 
2385  if (!q->state()->clipTestEnabled && path.hasWindingFill()) {
2386  // Pass when any clip bit is set, set high bit
2388  composite(vertexCoordinateArray.boundingRect());
2389  }
2390 
2391  // Pass when high bit is set, replace stencil value with new clip value
2392  glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT);
2393 
2394  composite(vertexCoordinateArray.boundingRect());
2395  }
2396 
2397  glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT);
2398  glStencilMask(0);
2399 
2400  glColorMask(true, true, true, true);
2401 }
2402 
2404 {
2405 // qDebug("QGL2PaintEngineEx::clip()");
2407 
2408  state()->clipChanged = true;
2409 
2410  ensureActive();
2411 
2412  if (op == Qt::ReplaceClip) {
2413  op = Qt::IntersectClip;
2414  if (d->hasClipOperations()) {
2415  d->systemStateChanged();
2416  state()->canRestoreClip = false;
2417  }
2418  }
2419 
2420 #ifndef QT_GL_NO_SCISSOR_TEST
2421  if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) {
2422  const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
2423  QRectF rect(points[0], points[2]);
2424 
2425  if (state()->matrix.type() <= QTransform::TxScale
2427  && qFuzzyIsNull(state()->matrix.m11())
2428  && qFuzzyIsNull(state()->matrix.m22())))
2429  {
2430  state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
2431  d->updateClipScissorTest();
2432  return;
2433  }
2434  }
2435 #endif
2436 
2437  const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
2438 
2439  switch (op) {
2440  case Qt::NoClip:
2441  if (d->useSystemClip) {
2442  state()->clipTestEnabled = true;
2443  state()->currentClip = 1;
2444  } else {
2445  state()->clipTestEnabled = false;
2446  }
2447  state()->rectangleClip = QRect(0, 0, d->width, d->height);
2448  state()->canRestoreClip = false;
2449  d->updateClipScissorTest();
2450  break;
2451  case Qt::IntersectClip:
2453  d->updateClipScissorTest();
2454  d->resetClipIfNeeded();
2455  ++d->maxClip;
2456  d->writeClip(path, d->maxClip);
2457  state()->currentClip = d->maxClip;
2458  state()->clipTestEnabled = true;
2459  break;
2460  case Qt::UniteClip: {
2461  d->resetClipIfNeeded();
2462  ++d->maxClip;
2463  if (state()->rectangleClip.isValid()) {
2464  QPainterPath path;
2465  path.addRect(state()->rectangleClip);
2466 
2467  // flush the existing clip rectangle to the depth buffer
2468  d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), d->maxClip);
2469  }
2470 
2471  state()->clipTestEnabled = false;
2472 #ifndef QT_GL_NO_SCISSOR_TEST
2473  QRect oldRectangleClip = state()->rectangleClip;
2474 
2475  state()->rectangleClip = state()->rectangleClip.united(pathRect);
2476  d->updateClipScissorTest();
2477 
2478  QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip;
2479 
2480  if (!extendRegion.isEmpty()) {
2481  QPainterPath extendPath;
2482  extendPath.addRegion(extendRegion);
2483 
2484  // first clear the depth buffer in the extended region
2485  d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0);
2486  }
2487 #endif
2488  // now write the clip path
2489  d->writeClip(path, d->maxClip);
2490  state()->canRestoreClip = false;
2491  state()->currentClip = d->maxClip;
2492  state()->clipTestEnabled = true;
2493  break;
2494  }
2495  default:
2496  break;
2497  }
2498 }
2499 
2501 {
2502  systemStateChanged();
2503  replayClipOperations();
2504 }
2505 
2507 {
2509 
2510  q->state()->clipChanged = true;
2511 
2512  if (systemClip.isEmpty()) {
2513  useSystemClip = false;
2514  } else {
2515  if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
2516  QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
2517  useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
2518  } else {
2519  useSystemClip = true;
2520  }
2521  }
2522 
2523  q->state()->clipTestEnabled = false;
2524  q->state()->needsClipBufferClear = true;
2525 
2526  q->state()->currentClip = 1;
2527  maxClip = 1;
2528 
2529  q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height);
2530  updateClipScissorTest();
2531 
2532  if (systemClip.rectCount() == 1) {
2533  if (systemClip.boundingRect() == QRect(0, 0, width, height))
2534  useSystemClip = false;
2535 #ifndef QT_GL_NO_SCISSOR_TEST
2536  // scissoring takes care of the system clip
2537  return;
2538 #endif
2539  }
2540 
2541  if (useSystemClip) {
2542  clearClip(0);
2543 
2544  QPainterPath path;
2545  path.addRegion(systemClip);
2546 
2547  q->state()->currentClip = 0;
2548  writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1);
2549  q->state()->currentClip = 1;
2550  q->state()->clipTestEnabled = true;
2551  }
2552 }
2553 
2555 {
2556  // qDebug("QGL2PaintEngineEx::setState()");
2557 
2559 
2560  QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state);
2561  QOpenGL2PaintEngineState *old_state = state();
2562 
2564 
2565  if (s->isNew) {
2566  // Newly created state object. The call to setState()
2567  // will either be followed by a call to begin(), or we are
2568  // setting the state as part of a save().
2569  s->isNew = false;
2570  return;
2571  }
2572 
2573  // Setting the state as part of a restore().
2574 
2575  if (old_state == s || old_state->renderHintsChanged)
2577 
2578  if (old_state == s || old_state->matrixChanged)
2579  d->matrixDirty = true;
2580 
2581  if (old_state == s || old_state->compositionModeChanged)
2582  d->compositionModeDirty = true;
2583 
2584  if (old_state == s || old_state->opacityChanged)
2585  d->opacityUniformDirty = true;
2586 
2587  if (old_state == s || old_state->clipChanged) {
2588  if (old_state && old_state != s && old_state->canRestoreClip) {
2589  d->updateClipScissorTest();
2590  glDepthFunc(GL_LEQUAL);
2591  } else {
2592  d->regenerateClip();
2593  }
2594  }
2595 }
2596 
2598 {
2599  if (orig)
2600  const_cast<QGL2PaintEngineEx *>(this)->ensureActive();
2601 
2603  if (!orig)
2604  s = new QOpenGL2PaintEngineState();
2605  else
2606  s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig));
2607 
2608  s->matrixChanged = false;
2609  s->compositionModeChanged = false;
2610  s->opacityChanged = false;
2611  s->renderHintsChanged = false;
2612  s->clipChanged = false;
2613 
2614  return s;
2615 }
2616 
2618  : QPainterState(other)
2619 {
2620  isNew = true;
2623  currentClip = other.currentClip;
2625  rectangleClip = other.rectangleClip;
2626 }
2627 
2629 {
2630  isNew = true;
2631  needsClipBufferClear = true;
2632  clipTestEnabled = false;
2633  canRestoreClip = true;
2634 }
2635 
2637 {
2638 }
2639 
virtual QGLFormat format() const
qreal focalRadius() const
Returns the focal radius of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2211
#define GL_ELEMENT_ARRAY_BUFFER
#define GL_ONE_MINUS_SRC_ALPHA
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
QPointF focalPoint() const
Returns the focal point of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2251
static bool hasOpenGLFramebufferObjects()
Returns true if the OpenGL GL_EXT_framebuffer_object extension is present on this system; otherwise r...
QFontEngine * fontEngine
QPaintEngine::DirtyFlags state() const
Returns a combination of flags identifying the set of properties that need to be updated when updatin...
Definition: qpaintengine.h:292
QSet< QVectorPath::CacheEntry * > pathCaches
qreal scaleY
the vertical scale of the target rectangle.
Definition: qpainter.h:112
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
qreal dy() const
Returns the vertical translation factor.
Definition: qtransform.h:277
QScopedPointer< QGLContextPrivate > d_ptr
Definition: qgl.h:430
void setUserData(QStaticTextUserData *newUserData)
void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer)
qreal right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:527
qreal alphaF() const
Returns the alpha color component of this color.
Definition: qcolor.cpp:1106
The QVector3D class represents a vector or vertex in 3D space.
Definition: qvector3d.h:60
BrushStyle
Definition: qnamespace.h:1162
static const GLuint QT_PMV_MATRIX_3_ATTR
QRegion intersected(const QRegion &r) const
Returns a region which is the intersection of this region and r.
Definition: qregion.h:112
#define GL_CLAMP_TO_EDGE
Definition: glfunctions.h:62
qreal width
the width of the source rectangle and is used to calculate the width of the target rectangle...
Definition: qpainter.h:109
#define GL_TEXTURE_MIN_FILTER
#define glUseProgram
double qreal
Definition: qglobal.h:1193
qreal determinant() const
Returns the matrix&#39;s determinant.
Definition: qtransform.h:228
#define GL_UNSIGNED_INT
unsigned char c[8]
Definition: qnumeric_p.h:62
virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, QPainter::PixmapFragmentHints hints)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const QColor & color() const
Returns the brush color.
Definition: qbrush.h:183
int qint32
Definition: qglobal.h:937
void addRegion(const QRegion &region)
Adds the given region to the path by adding each rectangle in the region as a separate closed subpath...
QHash< GlyphAndSubPixelPosition, Coord > coords
QFontEngine * fontEngine() const
int width() const
Returns the width of the pixmap.
Definition: qpixmap.cpp:630
QSize size() const
Returns the size of the pixmap.
Definition: qpixmap.cpp:661
virtual void stroke(const QVectorPath &path, const QPen &pen)
#define GL_TRUE
#define glStencilOpSeparate
CompositionMode
Defines the modes supported for digital image compositing.
Definition: qpainter.h:138
#define GL_CONSTANT_COLOR
QVertexIndexVector indices
void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id=-1)
QPainter::RenderHints renderHints
Definition: qpainter_p.h:158
bool isEmpty() const
qreal greenF() const
Returns the green color component of this color.
Definition: qcolor.cpp:1241
QGLEngineShaderManager * shaderManager
const QGradient * gradient() const
Returns the gradient describing this brush.
Definition: qbrush.cpp:871
bool isCurved() const
#define GL_DEPTH_TEST
QPainter::CompositionMode composition_mode
Definition: qpainter_p.h:174
#define QT_IMAGE_TEXTURE_UNIT
Qt::BrushStyle qbrush_style(const QBrush &b)
Definition: qpainter_p.h:96
const QChar * chars
Type * data() const
Definition: qdatabuffer_p.h:84
QFixedPoint * glyphPositions
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
QFixed subPixelPositionForX(QFixed x) const
#define GL_DECR_WRAP
#define GL_INVERT
#define GL_SRC_ALPHA
bool qbrush_fast_equals(const QBrush &a, const QBrush &b)
Definition: qpainter_p.h:95
int qFloor(qreal v)
Definition: qmath.h:73
#define GL_ONE_MINUS_SRC_COLOR
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
Q_CORE_EXPORT void qFree(void *ptr)
Definition: qmalloc.cpp:58
#define GL_STENCIL_BUFFER_BIT
qreal m21() const
Returns the horizontal shearing factor.
Definition: qtransform.h:249
QGL2PEXVertexArray textureCoordinateArray
QRect united(const QRect &other) const
Returns the bounding rectangle of this rectangle and the given rectangle.
Definition: qrect.h:491
RenderFlags flags
The QConicalGradient class is used in combination with QBrush to specify a conical gradient brush...
Definition: qbrush.h:329
QTransform transform() const
Returns the matrix in the current paint engine state.
Definition: qpainter.cpp:9377
virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, QPainter::PixmapFragmentHints hints)
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
qreal left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:525
void setSrcPixelType(Qt::BrushStyle)
#define GL_INCR_WRAP
qreal m22() const
Returns the vertical scaling factor.
Definition: qtransform.h:253
int left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:240
QPixmap scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qpixmap.h:132
QColor color() const
Returns the color of this pen&#39;s brush.
Definition: qpen.cpp:771
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
bool qt_resolve_framebufferobject_extensions(QGLContext *ctx)
#define GL_ARRAY_BUFFER
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Reimplement this function to draw the part of the image specified by the sr rectangle in the given re...
#define GL_TEXTURE_WRAP_S
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false...
Definition: qimage.cpp:6495
void setFilterMode(FilterMode m)
#define glVertexAttrib3fv
qreal qFastSin(qreal x)
Definition: qmath.h:264
Q_CORE_EXPORT void * qMalloc(size_t size)
Definition: qmalloc.cpp:53
QRect intersected(const QRect &other) const
Returns the intersection of this rectangle and the given rectangle.
Definition: qrect.h:481
QRect boundingRect() const
Returns the bounding rectangle of this region.
Definition: qregion.cpp:4363
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem)
QTransform matrix
Definition: qpainter_p.h:161
void setGreenF(qreal green)
Sets the green color component of this color to green.
Definition: qcolor.cpp:1255
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
Definition: qtransform.cpp:417
int height() const
Returns the height of the rectangle.
Definition: qrect.h:306
The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush...
Definition: qbrush.h:297
qreal opacity
the opacity of the target rectangle, where 0.0 is fully transparent and 1.0 is fully opaque...
Definition: qpainter.h:114
int majorVersion() const
Returns the OpenGL major version.
Definition: qgl.cpp:1223
bool isCacheable() const
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
void setRedF(qreal red)
Sets the red color component of this color to red.
Definition: qcolor.cpp:1227
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
TransformationType type() const
Returns the transformation type of this matrix.
#define GL_STENCIL_TEST
Q_GUI_EXPORT QString extensions()
Definition: qegl.cpp:785
#define Q_D(Class)
Definition: qglobal.h:2482
QTransform transform() const
Returns the current transformation matrix for the brush.
Definition: qbrush.h:185
qreal angle() const
Returns the start angle of the conical gradient in logical coordinates.
Definition: qbrush.cpp:2433
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:64
GLuint bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
Generates and binds a 2D GL texture to the current context, based on image.
Definition: qgl.cpp:2854
static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy)
virtual int devType() const
Definition: qpaintdevice.h:167
The QSizeF class defines the size of a two-dimensional object using floating point precision...
Definition: qsize.h:202
virtual void clip(const QVectorPath &path, Qt::ClipOperation op)
QGLContext::BindOptions options
Definition: qgl_p.h:611
#define GL_TEXTURE_2D
void setScissor(const QRect &rect)
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
OpenGLContextProfile profile() const
Returns the OpenGL context profile.
Definition: qgl.cpp:1286
int rectCount() const
Returns the number of rectangles that will be returned in rects().
Definition: qregion.cpp:4461
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
void setFontEngine(QFontEngine *fe)
PenStyle
Definition: qnamespace.h:1134
static qreal qt_sRGB_to_linear_RGB(qreal f)
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
QTransform inverted(bool *invertible=0) const
Returns an inverted copy of this matrix.
Definition: qtransform.cpp:364
#define glVertexAttrib4fv
GLuint location(const QGLEngineShaderManager::Uniform uniform)
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
void makeCacheable() const
QPointF center() const
Returns the center of the conical gradient in logical coordinates.
Definition: qbrush.cpp:2391
#define GL_SCISSOR_TEST
static const QGLContext * currentContext()
Returns the current context, i.e.
Definition: qgl.cpp:3545
#define Q_Q(Class)
Definition: qglobal.h:2483
static const GLuint QT_OPACITY_ATTR
The QGLFunctions class provides cross-platform access to the OpenGL/ES 2.0 API.
Definition: qglfunctions.h:178
#define GL_REPEAT
bool qt_resolve_buffer_extensions(QGLContext *ctx)
int size() const
Definition: qset.h:75
bool hasOpenGLFeature(QGLFunctions::OpenGLFeature feature) const
Returns true if feature is present on this system&#39;s OpenGL implementation; false otherwise.
const QGLContext * context() const
static const QRectF boundingRect(const QPointF *points, int pointCount)
#define GL_ONE_MINUS_DST_ALPHA
void stroke(const QVectorPath &path, const QPen &pen)
QRectF controlPointRect() const
virtual void stroke(const QVectorPath &path, const QPen &pen)
void setBrush(const QBrush &brush)
QGlyphLayout glyphs
qreal m12() const
Returns the vertical shearing factor.
Definition: qtransform.h:241
#define GL_FALSE
#define GL_TEXTURE0
Definition: glfunctions.h:61
int width() const
Returns the width.
Definition: qsize.h:126
QRect mapRect(const QRect &) const
Creates and returns a QRect object that is a copy of the given rectangle, mapped into the coordinate ...
TransformationType
Definition: qtransform.h:68
#define FRAMEBUFFER_SRGB_EXT
FilterMode filterMode() const
QPaintEngineEx * engine
#define glGenBuffers
QPainter * painter() const
Returns the paint engine&#39;s painter.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static void setCoords(GLfloat *coords, const QGLRect &rect)
void fill(const QVectorPath &path)
#define GL_MIRRORED_REPEAT_IBM
bool isActive() const
Returns true if the paint engine is actively drawing; otherwise returns false.
Definition: qpaintengine.h:154
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QFixed y
Definition: qfixed_p.h:191
#define GL_TRIANGLE_STRIP
#define GL_MULTISAMPLE
bool end()
Reimplement this function to finish painting on the current paint device.
#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT
Definition: qgl_p.h:343
qreal y
the y coordinate of the center point in the target rectangle.
Definition: qpainter.h:106
bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush &brush)
Definition: qbrush.cpp:223
QDataBuffer< GLfloat > opacityArray
static float pixelSize(const QFontDef &request, int dpi)
Definition: qfont_win.cpp:80
GLuint id
Definition: qgl_p.h:608
The QGLFormat class specifies the display format of an OpenGL rendering context.
Definition: qgl.h:175
QVector< qreal > vertices
char useBackendOptimizations
QBrush qpen_brush(const QPen &p)
Definition: qpainter_p.h:87
bool isCosmetic() const
Returns true if the pen is cosmetic; otherwise returns false.
Definition: qpen.cpp:840
The QGLContext class encapsulates an OpenGL rendering context.
Definition: qgl.h:310
const void * data() const
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
Definition: qregion.cpp:4098
void insert(const QGLContext *context, void *value)
Definition: qgl.cpp:5910
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
QGLRect boundingRect() const
Qt::PenJoinStyle joinStyle() const
Returns the pen&#39;s join style.
Definition: qpen.cpp:736
QColor qt_premultiplyColor(QColor c, GLfloat opacity)
void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, const QSize &size, QPainter::PixmapFragmentHints hints)
CacheEntry * lookupCacheData(QPaintEngineEx *engine) const
void setBlueF(qreal blue)
Sets the blue color component of this color to blue.
Definition: qcolor.cpp:1282
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
qreal x
the x coordinate of center point in the target rectangle.
Definition: qpainter.h:105
QGL2PEXVertexArray vertexCoordinateArray
virtual Type type() const =0
Reimplement this function to return the paint engine Type.
qreal qpen_widthf(const QPen &p)
Definition: qpainter_p.h:88
short qint16
Definition: qglobal.h:935
static const GLuint QT_PMV_MATRIX_2_ATTR
#define GL_UNSIGNED_SHORT
bool qt_resolve_version_2_0_functions(QGLContext *ctx)
bool stencil() const
Returns true if the stencil buffer is enabled; otherwise returns false.
Definition: qgl.h:638
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
Internal QTextItem.
Q_GUI_EXPORT bool qt_cleartype_enabled
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p)
void composite(const QGLRect &boundingRect)
The QVector2D class represents a vector or vertex in 2D space.
Definition: qvector2d.h:60
static const char * data(const QByteArray &arr)
bool isQBitmap() const
Returns true if this is a QBitmap; otherwise returns false.
Definition: qpixmap.cpp:599
unsigned int uint
Definition: qglobal.h:996
#define GL_TRIANGLE_FAN
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
#define GL_NOTEQUAL
uint inRenderWithPainter
Definition: qwidget_p.h:277
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
Q_GUI_EXPORT qreal qt_fontsmoothing_gamma
#define glBlendColor
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:68
void setInvScale(qreal invScale)
virtual void setState(QPainterState *s)
#define QT_MAX_CACHED_GLYPH_SIZE
Qt::BrushStyle style() const
Returns the brush style.
Definition: qbrush.h:182
QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition: qrect.h:781
QPixmap texture() const
Returns the custom brush pattern, or a null pixmap if no custom brush pattern has been set...
Definition: qbrush.cpp:785
static QColor fromRgbF(qreal r, qreal g, qreal b, qreal a=1.0)
Static convenience function that returns a QColor constructed from the RGB color values, r (red), g (green), b (blue), and a (alpha-channel, i.e.
Definition: qcolor.cpp:2017
#define GL_ZERO
bool isOpaque() const
Returns true if the brush is fully opaque otherwise false.
Definition: qbrush.cpp:910
#define GL_LEQUAL
virtual void setState(QPainterState *s)
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
Reimplement this function to draw the part of the pm specified by the sr rectangle in the given r...
qreal qPow(qreal x, qreal y)
Definition: qmath.h:244
QPointF start() const
Returns the start point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1796
void drawTexture(const QGLRect &dest, const QGLRect &src, const QSize &textureSize, bool opaque, bool pattern=false)
#define GL_FRONT
#define glDeleteBuffers
bool hasWindingFill() const
QOpenGL2PaintEngineState * state()
GLuint getBuffer(const QGradient &gradient, qreal opacity)
#define glActiveTexture
Definition: glfunctions.h:69
qreal pixelSize
Definition: qfont_p.h:90
void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline=true)
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
static bool fontSmoothingApproximately(qreal target)
#define GL_STENCIL_HIGH_BIT
QSize size() const
Returns the size of the image, i.
Definition: qimage.cpp:1587
void setHasComplexGeometry(bool hasComplexGeometry)
#define GL_BLEND
void setColor(const QColor &color)
Sets the brush color to the given color.
Definition: qbrush.cpp:725
virtual bool isFlipped() const
qvectorpath_cache_cleanup cleanup
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:76
QFixed x
Definition: qfixed_p.h:190
#define GL_TEXTURE_WRAP_T
#define GL_LINEAR
static QGLContextGroup * contextGroup(const QGLContext *ctx)
Definition: qgl_p.h:464
int top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:243
qreal angle(const QPointF &p1, const QPointF &p2)
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
#define GL_TRIANGLES
bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr)
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem)
This function draws the text item textItem at position p.
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
Definition: qbrush.cpp:167
#define GL_BACK
void setUniformValue(int location, GLfloat value)
Sets the uniform variable at location in the current context to value.
virtual int glyphMargin() const
void setGlyphCache(void *key, QFontEngineGlyphCache *data)
void setAlphaF(qreal alpha)
Sets the alpha of this color to alpha.
Definition: qcolor.cpp:1117
#define GL_DST_ALPHA
unsigned int GLenum
Definition: main.cpp:50
Type type() const
Returns the type of gradient.
Definition: qbrush.h:232
static QGL2GradientCache * cacheForContext(const QGLContext *context)
The QLinearGradient class is used in combination with QBrush to specify a linear gradient brush...
Definition: qbrush.h:280
void writeClip(const QVectorPath &path, uint value)
The QGradient class is used in combination with QBrush to specify gradient fills. ...
Definition: qbrush.h:201
bool hasAlpha() const
Returns true if this pixmap has an alpha channel, or has a mask, otherwise returns false...
Definition: qpixmap.cpp:1938
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
This class is used in conjunction with the QPainter::drawPixmapFragments() function to specify how a ...
Definition: qpainter.h:103
static const GLuint QT_PMV_MATRIX_1_ATTR
qreal scaleX
the horizontal scale of the target rectangle.
Definition: qpainter.h:111
#define glDisableVertexAttribArray
int minorVersion() const
Returns the OpenGL minor version.
Definition: qgl.cpp:1238
qreal miterLimit() const
Returns the miter limit of the pen.
Definition: qpen.cpp:589
static void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform)
qreal redF() const
Returns the red color component of this color.
Definition: qcolor.cpp:1213
bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions)
#define ctx
Definition: qgl.cpp:6094
static QTestResult::TestLocation location
Definition: qtestresult.cpp:63
virtual void drawStaticTextItem(QStaticTextItem *)
QVector< QRect > rects() const
Returns an array of non-overlapping rectangles that make up the region.
Definition: qregion.cpp:4412
qreal qFastCos(qreal x)
Definition: qmath.h:274
unsigned int quint32
Definition: qglobal.h:938
#define QT_BRUSH_TEXTURE_UNIT
const qreal * points() const
qreal m23() const
Returns the vertical projection factor.
Definition: qtransform.h:257
virtual QPainterState * createState(QPainterState *orig) const
QPointF brushOrigin
Definition: qpainter_p.h:149
int height() const
Returns the height.
Definition: qsize.h:129
static const GLuint QT_TEXTURE_COORDS_ATTR
if(void) toggleToolbarShown
qreal blueF() const
Returns the blue color component of this color.
Definition: qcolor.cpp:1269
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QFactoryLoader * l
bool isConvex() const
QGLShaderProgram * currentProgram()
const_iterator constBegin() const
Definition: qset.h:168
Spread spread() const
Returns the spread method use by this gradient.
Definition: qbrush.h:235
QWExtra * extra
Definition: qwidget_p.h:700
bool match(const char *str) const
Definition: qgl_p.h:906
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
virtual void fill(const QVectorPath &path, const QBrush &brush)
qreal dx() const
Returns the horizontal translation factor.
Definition: qtransform.h:273
virtual void drawStaticTextItem(QStaticTextItem *textItem)
static Extensions glExtensions()
Definition: qgl.cpp:5781
QTriangleSet qTriangulate(const qreal *polygon, int count, uint hint, const QTransform &matrix)
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
QPointF center() const
Returns the center of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2102
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
bool intersects(const QRegion &r) const
Returns true if this region intersects with region, otherwise returns false.
Definition: qregion.cpp:766
#define GL_EQUAL
#define GL_RGBA
qreal top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:526
void transferMode(EngineMode newMode)
int height() const
Returns the height of the pixmap.
Definition: qpixmap.cpp:645
static bool isPowerOfTwo(uint x)
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
void optimiseForBrushTransform(QTransform::TransformationType transformType)
bool begin(QPaintDevice *device)
Reimplement this function to initialise your paint engine when painting is to start on the paint devi...
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
static QTransform fromTranslate(qreal dx, qreal dy)
Creates a matrix which corresponds to a translation of dx along the x axis and dy along the y axis...
Definition: qtransform.cpp:462
static QGLPaintDevice * getDevice(QPaintDevice *)
QStaticTextUserData * userData() const
#define QT_MASK_TEXTURE_UNIT
QFontEngineGlyphCache * glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const
Q_GUI_EXPORT QWidgetPrivate * qt_widget_private(QWidget *widget)
Definition: qwidget.cpp:12920
qreal m13() const
Returns the horizontal projection factor.
Definition: qtransform.h:245
qreal bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:528
QFontDef fontDef
#define GL_TEXTURE_MAG_FILTER
static const GLuint QT_VERTEX_COORDS_ATTR
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition: qpixmap.cpp:615
The QTextItem class provides all the information required to draw text in a custom paint engine...
Definition: qpaintengine.h:68
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.h:232
#define GL_STATIC_DRAW
virtual void compositionModeChanged()
#define glBindBuffer
qreal centerRadius() const
Returns the center radius of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2182
QPaintEngine * active_engine
Definition: qgl_p.h:458
Qt::PenStyle qpen_style(const QPen &p)
Definition: qpainter_p.h:89
#define GL_ALWAYS
bool prepareForDraw(bool srcPixelsAreOpaque)
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
qreal height
the height of the source rectangle and is used to calculate the height of the target rectangle...
Definition: qpainter.h:110
static void cleanupVectorPath(QPaintEngineEx *engine, void *data)
QRegion systemClip() const
Returns the system clip.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
bool qt_applefontsmoothing_enabled
void setInvScale(qreal invScale)
#define GL_REPLACE
#define GL_LESS
void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive)
qreal m11() const
Returns the horizontal scaling factor.
Definition: qtransform.h:237
void addQuad(const QRectF &rect)
void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QGLRect &bounds, StencilFillMode mode)
qreal m33() const
Returns the division factor.
Definition: qtransform.h:269
#define GL_ONE
#define GL_KEEP
#define glBufferData
int size() const
const QGLContext * context() const
Definition: qgl_p.h:252
virtual bool supportsSubPixelPositions() const
QPointF finalStop() const
Returns the final stop point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1856
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
ClipOperation
Definition: qnamespace.h:1495
#define GL_NEAREST
glyph_t * glyphs
Hint shape() const
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem)
This function draws the text item textItem at position p.
static const qreal Q_PI
Definition: qmath_p.h:61