Qt 4.8
qpaintengine_opengl.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 #include <qdebug.h>
43 #include <private/qfontengine_p.h>
44 #include <qmath.h>
45 #include <private/qmath_p.h>
46 #include <private/qdrawhelper_p.h>
47 #include <private/qpaintengine_p.h>
48 #include "qapplication.h"
49 #include "qbrush.h"
50 #include "qgl.h"
51 #include <private/qgl_p.h>
52 #include <private/qglpaintdevice_p.h>
53 #include <private/qpainter_p.h>
54 #include "qmap.h"
55 #include <private/qpaintengine_opengl_p.h>
56 #include <private/qdatabuffer_p.h>
57 #include "qpen.h"
58 #include "qvarlengtharray.h"
59 #include <private/qpainter_p.h>
60 #include <private/qglpixelbuffer_p.h>
61 #include <private/qbezier_p.h>
62 #include <qglframebufferobject.h>
63 #include <private/qstatictext_p.h>
64 
65 #include "private/qtessellator_p.h"
66 
68 
69 #ifdef Q_WS_QWS
70 #include "private/qglwindowsurface_qws_p.h"
71 #include "qwsmanager_qws.h"
72 #include "private/qwsmanager_p.h"
73 #endif
74 
75 #define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(device->context());
76 
77 #include <stdlib.h>
78 #include "qpaintengine_opengl_p.h"
79 
81 
82 Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
83 #ifdef QT_MAC_USE_COCOA
84 extern void *qt_current_nsopengl_context(); // qgl_mac.mm
85 #endif
86 
87 #define QREAL_MAX 9e100
88 #define QREAL_MIN -9e100
89 
90 extern int qt_next_power_of_two(int v);
91 
92 #define DISABLE_DEBUG_ONCE
93 
94 //#define DEBUG_DISPLAY_MASK_TEXTURE
95 
96 #ifdef DISABLE_DEBUG_ONCE
97 #define DEBUG_OVERRIDE(state) ;
98 #define DEBUG_ONCE_STR(str) ;
99 #define DEBUG_ONCE if (0)
100 #else
101 static int DEBUG_OVERRIDE_FLAG = 0;
102 static bool DEBUG_TEMP_FLAG;
103 #define DEBUG_OVERRIDE(state) { state ? ++DEBUG_OVERRIDE_FLAG : --DEBUG_OVERRIDE_FLAG; }
104 #define DEBUG_ONCE if ((DEBUG_TEMP_FLAG = DEBUG_OVERRIDE_FLAG) && 0) ; else for (static int DEBUG_ONCE_FLAG = false; !DEBUG_ONCE_FLAG || DEBUG_TEMP_FLAG; DEBUG_ONCE_FLAG = true, DEBUG_TEMP_FLAG = false)
105 #define DEBUG_ONCE_STR(str) DEBUG_ONCE qDebug() << (str);
106 #endif
107 
108 #ifdef Q_WS_X11
109 static bool qt_nvidiaFboNeedsFinish = false;
110 #endif
111 
112 static inline void qt_glColor4ubv(unsigned char *col)
113 {
114  glColor4f(col[0]/255.0f, col[1]/255.0f, col[2]/255.0f, col[3]/255.0f);
115 }
116 
117 struct QT_PointF {
118  qreal x;
119  qreal y;
120 };
121 
123 {
125  {}
126 
127  QGLTrapezoid(qreal top_, qreal bottom_, qreal topLeftX_, qreal topRightX_, qreal bottomLeftX_, qreal bottomRightX_)
128  : top(top_),
129  bottom(bottom_),
130  topLeftX(topLeftX_),
131  topRightX(topRightX_),
132  bottomLeftX(bottomLeftX_),
133  bottomRightX(bottomRightX_)
134  {}
135 
136  const QGLTrapezoid translated(const QPointF &delta) const;
137 
144 };
145 
147 {
148  QGLTrapezoid trap(*this);
149  trap.top += delta.y();
150  trap.bottom += delta.y();
151  trap.topLeftX += delta.x();
152  trap.topRightX += delta.x();
153  trap.bottomLeftX += delta.x();
154  trap.bottomRightX += delta.x();
155  return trap;
156 }
157 
158 
160 class QGLMaskGenerator;
161 class QGLOffscreen;
162 
164 {
165 public:
166  void setOffscreenSize(const QSize &offscreenSize);
167  void setDrawableSize(const QSize &drawableSize);
168 
169  struct CacheLocation {
171  int channel;
172 
174  };
175 
176  struct CacheInfo {
177  inline CacheInfo(const QPainterPath &p, const QTransform &m, qreal w = -1) :
178  path(p), matrix(m), stroke_width(w), age(0) {}
179 
183 
185 
186  int age;
187  };
188 
189  struct QuadTreeNode {
191 
194  };
195 
196  CacheLocation getMask(QGLMaskGenerator &maskGenerator, QOpenGLPaintEnginePrivate *engine);
197 
199 
200  enum {block_size = 64};
201 
202  // throw out keys that are too old
203  void maintainCache();
204  void clearCache();
205 
206 private:
207  quint64 hash(const QPainterPath &p, const QTransform &m, qreal w);
208 
209  void createMask(quint64 key, CacheInfo &info, QGLMaskGenerator &maskGenerator);
210 
213 
214  QGLTextureCacheHash cache;
215 
216  QVector<QuadTreeNode> occupied_quadtree[4];
217 
218  void quadtreeUpdate(int channel, int node, int current_block_size);
219  void quadtreeAllocate(quint64 key, const QSize &size, QRect *rect, int *channel);
220 
221  bool quadtreeFindAvailableLocation(const QSize &size, QRect *rect, int *channel);
222  void quadtreeFindExistingLocation(const QSize &size, QRect *rect, int *channel);
223 
224  void quadtreeInsert(int channel, quint64 key, const QRect &rect, int node = 0);
225  void quadtreeClear(int channel, const QRect &rect, int node = 0);
226 
227  int quadtreeBlocksize(int node);
228  QPoint quadtreeLocation(int node);
229 
231 };
232 
233 Q_GLOBAL_STATIC(QGLMaskTextureCache, qt_mask_texture_cache)
234 
236 {
237  Q_OBJECT
238 public:
240  : QObject(),
241  offscreen(0),
242  ctx(0),
243  mask_dim(0),
244  activated(false),
245  bound(false)
246  {
247  connect(QGLSignalProxy::instance(),
248  SIGNAL(aboutToDestroyContext(const QGLContext*)),
249  SLOT(cleanupGLContextRefs(const QGLContext*)));
250  }
251 
252  inline void setDevice(QPaintDevice *pdev);
253 
254  void begin();
255  void end();
256 
257  inline void bind();
258  inline void release();
259 
260  inline bool isBound() const;
261 
262  inline QSize drawableSize() const;
263  inline QSize offscreenSize() const;
264 
265  inline GLuint offscreenTexture() const;
266 
267  QGLContext *context() const;
268 
269  static bool isSupported();
270 
271  inline void initialize();
272 
273  inline bool isValid() const;
274 
275 public Q_SLOTS:
276  void cleanupGLContextRefs(const QGLContext *context) {
277  if (context == ctx) {
278  delete offscreen;
279  ctx = 0;
280  offscreen = 0;
281  mask_dim = 0;
282  }
283  }
284 
285 private:
287 
290 
291  // dimensions of mask texture (square)
292  int mask_dim;
294 
296 
297  bool activated;
299 
300  bool bound;
301 };
302 
304 {
305  if (pdev->devType() == QInternal::OpenGL)
306  device = static_cast<QGLPaintDevice*>(pdev);
307  else
308  device = QGLPaintDevice::getDevice(pdev);
309 
310  if (!device)
311  return;
312 
313  drawable_fbo = (pdev->devType() == QInternal::FramebufferObject);
314 }
315 
317 {
318 #ifndef QT_OPENGL_ES
319  initialized = false;
320 
321  if (activated)
322  initialize();
323 #endif
324 }
325 
327 {
328 #ifndef QT_OPENGL_ES
329  if (initialized)
330  return;
331 
332  activated = true;
333  initialized = true;
334 
335  int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(device->size().width(), device->size().height()))));
336 
337  bool shared_context = QGLContext::areSharing(device->context(), ctx);
338  bool would_fail = last_failed_size.isValid() &&
339  (device->size().width() >= last_failed_size.width() ||
340  device->size().height() >= last_failed_size.height());
341  bool needs_refresh = dim > mask_dim || !shared_context;
342 
343  if (needs_refresh && !would_fail) {
344  DEBUG_ONCE qDebug() << "QGLOffscreen::initialize(): creating offscreen of size" << dim;
345  delete offscreen;
346  offscreen = new QGLFramebufferObject(dim, dim, GLenum(GL_TEXTURE_2D));
347  mask_dim = dim;
348 
349  if (!offscreen->isValid()) {
350  qWarning("QGLOffscreen: Invalid offscreen fbo (size %dx%d)", mask_dim, mask_dim);
351  delete offscreen;
352  offscreen = 0;
353  mask_dim = 0;
354  last_failed_size = device->size();
355  }
356  }
357 
358  qt_mask_texture_cache()->setOffscreenSize(offscreenSize());
359  qt_mask_texture_cache()->setDrawableSize(device->size());
360  ctx = device->context();
361 #endif
362 }
363 
364 inline bool QGLOffscreen::isValid() const
365 {
366  return offscreen;
367 }
368 
370 {
371  if (bound)
372  release();
373 #ifdef DEBUG_DISPLAY_MASK_TEXTURE
374  glReadBuffer(GL_BACK);
375  glDrawBuffer(GL_BACK);
376  glMatrixMode(GL_MODELVIEW);
377  glLoadIdentity();
378  glColor4f(1, 1, 1, 1);
379  glDisable(GL_DEPTH_TEST);
380  glBlendFunc(GL_ONE, GL_ZERO);
381  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
382  glEnable(GL_TEXTURE_2D);
383  glBindTexture(GL_TEXTURE_2D, offscreen->texture());
384 
385  glBegin(GL_QUADS);
386  glTexCoord2f(0.0, 1.0); glVertex2f(0.0, 0.0);
387  glTexCoord2f(1.0, 1.0); glVertex2f(drawable.size().width(), 0.0);
388  glTexCoord2f(1.0, 0.0); glVertex2f(drawable.size().width(), drawable.size().height());
389  glTexCoord2f(0.0, 0.0); glVertex2f(0.0, drawable.size().height());
390  glEnd();
391 
392  glBindTexture(GL_TEXTURE_2D, 0);
393  glDisable(GL_TEXTURE_2D);
394 #endif
395 }
396 
397 inline void QGLOffscreen::bind()
398 {
399 #ifndef QT_OPENGL_ES
400  Q_ASSERT(initialized);
401 
402  if (!offscreen || bound)
403  return;
404 
405  DEBUG_ONCE qDebug() << "QGLOffscreen: binding offscreen";
406  offscreen->bind();
407 
408  bound = true;
409 
410  glViewport(0, 0, offscreenSize().width(), offscreenSize().height());
411 
412  glMatrixMode(GL_PROJECTION);
413  glLoadIdentity();
414  glOrtho(0, offscreenSize().width(), offscreenSize().height(), 0, -999999, 999999);
415  glMatrixMode(GL_MODELVIEW);
416 #endif
417 }
418 
420 {
421 #ifndef QT_OPENGL_ES
422  if (!offscreen || !bound)
423  return;
424 
425 #ifdef Q_WS_X11
426  // workaround for bug in nvidia driver versions 9x.xx
428  glFinish();
429 #endif
430 
431  DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen");
432 
433  if (drawable_fbo)
434  device->ensureActiveTarget(); //###
435  else
436  offscreen->release();
437 
438  QSize sz(device->size());
439  glViewport(0, 0, sz.width(), sz.height());
440 
441  glMatrixMode(GL_PROJECTION);
442  glLoadIdentity();
443 #ifndef QT_OPENGL_ES
444  glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);
445 #else
446  glOrthof(0, sz.width(), sz.height(), 0, -999999, 999999);
447 #endif
448  glMatrixMode(GL_MODELVIEW);
449 
450  bound = false;
451 #endif
452 }
453 
454 inline bool QGLOffscreen::isBound() const
455 {
456  return bound;
457 }
458 
460 {
461  return device->size();
462 }
463 
465 {
466  return QSize(mask_dim, mask_dim);
467 }
468 
469 inline GLuint QGLOffscreen::offscreenTexture() const
470 {
471  return offscreen ? offscreen->texture() : 0;
472 }
473 
475 {
476  return ctx;
477 }
478 
480 {
482 }
483 
485 {
487  QBrush _brush,
488  const QPointF &_brush_origion,
489  QPainter::CompositionMode _composition_mode,
490  const QTransform &_matrix,
492  : opacity(_opacity),
493  brush(_brush),
494  brush_origin(_brush_origion),
495  composition_mode(_composition_mode),
496  matrix(_matrix),
497  location(_location) {}
502 
505 };
506 
508 
509 struct GLProgram {
510  int brush; // brush index or mask index
511  int mode; // composition mode index
512  bool mask;
513  GLuint program;
514 };
515 
517 
518 class QGLProgramCache : public QObject
519 {
520  Q_OBJECT
521 public:
523  // we have to know when a context is deleted so we can free
524  // any program handles it holds
525  connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
526  SLOT(cleanupPrograms(const QGLContext*)));
527 
528  }
530  // at this point the cache should contain 0 elements
531  // Q_ASSERT(program.size() == 0);
532  }
533 
534  GLuint getProgram(const QGLContext *ctx, int brush, int mode, bool mask_mode)
535  {
536  // 1. see if we have an entry for the ctx context
537  QList<GLProgram> progs = programs.values(ctx);
538  for (int i=0; i<progs.size(); ++i) {
539  const GLProgram &prg = progs.at(i);
540  if (mask_mode) {
541  if (prg.mask && prg.brush == brush)
542  return prg.program;
543  } else {
544  if (!prg.mask && prg.brush == brush && prg.mode == mode)
545  return prg.program;
546  }
547  }
548 
549  // 2. try to find a match in a shared context, and update the
550  // hash with the entry found
551  QList<const QGLContext *> contexts = programs.uniqueKeys();
552  for (int i=0; i<contexts.size(); ++i) {
553  const QGLContext *cx = contexts.at(i);
554  if (cx != ctx && QGLContext::areSharing(cx, ctx)) {
555  QList<GLProgram> progs = programs.values(cx);
556  for (int k=0; k<progs.size(); ++k) {
557  const GLProgram &prg = progs.at(k);
558  if (mask_mode) {
559  if (prg.mask && prg.brush == brush) {
560  programs.insert(ctx, prg);
561  return prg.program;
562  }
563  } else {
564  if (!prg.mask && prg.brush == brush && prg.mode == mode) {
565  programs.insert(ctx, prg);
566  return prg.program;
567  }
568  }
569  }
570  }
571  }
572 
573  // 3. compile a new program and place it into the cache
574  // NB! assumes ctx is the current GL context
575  GLProgram prg;
576  prg.brush = brush;
577  prg.mode = mode;
578  prg.mask = mask_mode;
579  glGenProgramsARB(1, &prg.program);
581  const char *src = mask_mode
583  : painter_fragment_program_sources[brush][mode];
584  // necessary for .NET 2002, apparently
585  const GLbyte *gl_src = reinterpret_cast<const GLbyte *>(src);
586 
587  while (glGetError() != GL_NO_ERROR) {} // reset error state
589  int(strlen(src)), gl_src);
590  if (glGetError() != GL_NO_ERROR) {
591 // qDebug() << "QGLProgramCache: Unable to compile fragment program.";
592  glDeleteProgramsARB(1, &prg.program);
593  return 0;
594  }
595 
596 // qDebug() << "QGLProgramCache: Creating GL program:" << prg.program << hex << ctx;
597  programs.insert(ctx, prg);
598  return prg.program;
599  }
600 
601 public Q_SLOTS:
602  void cleanupPrograms(const QGLContext *context)
603  {
604  QGLProgramHash::iterator it = programs.begin();
605  while (it != programs.end()) {
606  if (it.key() == context) {
607  if (!context->isSharing()) {
608  // the ctx variable below is needed for the glDeleteProgramARB call
609  // since it is resolved from our extension system
610  // NB! assumes context is the current GL context
611  const QGLContext *ctx = context;
612  // qDebug() << "QGLProgramHash: Deleting GL program:" << it.value().program << hex << it.key();
613  glDeleteProgramsARB(1, &it.value().program);
614  }
615  it = programs.erase(it);
616  } else {
617  ++it;
618  }
619  }
620  }
621 
622 private:
624 };
625 
626 Q_GLOBAL_STATIC(QGLProgramCache, qt_gl_program_cache)
627 
628 
632 {
633  Q_OBJECT
634 public:
636  : p(priv)
637  {
638  connect(QGLSignalProxy::instance(),
639  SIGNAL(aboutToDestroyContext(const QGLContext*)),
640  SLOT(cleanupGLContextRefs(const QGLContext*)));
641  }
642 
643 public Q_SLOTS:
644  void cleanupGLContextRefs(const QGLContext *context);
645 
646 private:
648 };
649 
651 {
653 public:
655  : opacity(1)
656  , composition_mode(QPainter::CompositionMode_SourceOver)
657  , has_pen(false)
658  , has_brush(false)
659  , has_fast_pen(false)
660  , use_stencil_method(false)
661  , dirty_drawable_texture(false)
662  , has_stencil_face_ext(false)
663  , use_fragment_programs(false)
664  , high_quality_antialiasing(false)
665  , use_smooth_pixmap_transform(false)
666  , use_emulation(false)
667  , txop(QTransform::TxNone)
668  , inverseScale(1)
669  , moveToCount(0)
670  , last_created_state(0)
671  , shader_ctx(0)
672  , grad_palette(0)
673  , tess_points(0)
674  , drawable_texture(0)
675  , ref_cleaner(this)
676  {}
677 
678  inline void setGLPen(const QColor &c) {
679  uint alpha = qRound(c.alpha() * opacity);
680  pen_color[0] = qt_div_255(c.red() * alpha);
681  pen_color[1] = qt_div_255(c.green() * alpha);
682  pen_color[2] = qt_div_255(c.blue() * alpha);
683  pen_color[3] = alpha;
684  }
685 
686  inline void setGLBrush(const QColor &c) {
687  uint alpha = qRound(c.alpha() * opacity);
688  brush_color[0] = qt_div_255(c.red() * alpha);
689  brush_color[1] = qt_div_255(c.green() * alpha);
690  brush_color[2] = qt_div_255(c.blue() * alpha);
691  brush_color[3] = alpha;
692  }
693 
694  inline void setGradientOps(const QBrush &brush, const QRectF &bounds);
695  void createGradientPaletteTexture(const QGradient& g);
696 
697  void updateGradient(const QBrush &brush, const QRectF &bounds);
698 
699  inline void lineToStencil(qreal x, qreal y);
700  inline void curveToStencil(const QPointF &cp1, const QPointF &cp2, const QPointF &ep);
701  void pathToVertexArrays(const QPainterPath &path);
702  void fillVertexArray(Qt::FillRule fillRule);
703  void drawVertexArrays();
704  void fillPath(const QPainterPath &path);
705  void fillPolygon_dev(const QPointF *polygonPoints, int pointCount,
706  Qt::FillRule fill);
707 
708  void drawFastRect(const QRectF &rect);
709  void strokePath(const QPainterPath &path, bool use_cache);
710  void strokePathFastPen(const QPainterPath &path, bool needsResolving);
711  void strokeLines(const QPainterPath &path);
712 
713  void updateDepthClip();
714  void systemStateChanged();
715 
716  void cleanupGLContextRefs(const QGLContext *context) {
717  if (context == shader_ctx)
718  shader_ctx = 0;
719  }
720 
721  inline void updateFastPen() {
722  qreal pen_width = cpen.widthF();
723  has_fast_pen =
724  ((pen_width == 0 || (pen_width <= 1 && matrix.type() <= QTransform::TxTranslate))
725  || cpen.isCosmetic())
726  && cpen.style() == Qt::SolidLine
727  && cpen.isSolid();
728 
729  }
730 
731  void disableClipping();
732  void enableClipping();
733  void ensureDrawableTexture();
734 
742 
744 
758 
760 
761  void updateUseEmulation();
762 
764  GLubyte pen_color[4];
765  GLubyte brush_color[4];
769 
771 
774 
775  bool isFastRect(const QRectF &r);
776 
777  void drawImageAsPath(const QRectF &r, const QImage &img, const QRectF &sr);
778  void drawTiledImageAsPath(const QRectF &r, const QImage &img, qreal sx, qreal sy, const QPointF &offset);
779 
780  void drawOffscreenPath(const QPainterPath &path);
781 
782  void composite(const QRectF &rect, const QPoint &maskOffset = QPoint());
783  void composite(GLuint primitive, const GLfloat *vertexArray, int vertexCount, const QPoint &maskOffset = QPoint());
784 
785  bool createFragmentPrograms();
786  void deleteFragmentPrograms();
787  void updateFragmentProgramData(int locations[]);
788 
789  void cacheItemErased(int channel, const QRect &rect);
790 
791  void addItem(const QGLMaskTextureCache::CacheLocation &location);
792  void drawItem(const QDrawQueueItem &item);
793  void flushDrawQueue();
794 
795  void copyDrawable(const QRectF &rect);
796 
797  void updateGLMatrix() const;
798 
800 
802  GLuint grad_palette;
803 
804  GLuint painter_fragment_programs[num_fragment_brushes][num_fragment_composition_modes];
805  GLuint mask_fragment_programs[num_fragment_masks];
806 
807  float inv_matrix_data[3][4];
808  float fmp_data[4];
809  float fmp2_m_radius2_data[4];
810  float angle_data[4];
811  float linear_data[4];
812 
813  float porterduff_ab_data[4];
814  float porterduff_xyz_data[4];
815 
816  float mask_offset_data[4];
817  float mask_channel_data[4];
818 
821 
822  void setPorterDuffData(float a, float b, float x, float y, float z);
823  void setInvMatrixData(const QTransform &inv_matrix);
824 
829 
832 
833  GLdouble projection_matrix[4][4];
834 
835 #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_2)
836  GLfloat mv_matrix[4][4];
837 #else
838  GLdouble mv_matrix[4][4];
839 #endif
840 
842 
845 
847 
849  friend class QGLMaskTextureCache;
850 };
851 
853 {
854 public:
857 
858  static void enableOffset(QOpenGLPaintEnginePrivate *d);
859  static void disableOffset(QOpenGLPaintEnginePrivate *d);
860 
861 private:
863 };
864 
866  : d(d_)
867 {
868  enableOffset(d);
869 }
870 
872 {
873  if (!d->has_antialiasing) {
874  glMatrixMode(GL_MODELVIEW);
875  glPushMatrix();
876  d->mv_matrix[3][0] += 0.5;
877  d->mv_matrix[3][1] += 0.5;
878  d->updateGLMatrix();
879  }
880 }
881 
883 {
884  disableOffset(d);
885 }
886 
888 {
889  if (!d->has_antialiasing) {
890  glMatrixMode(GL_MODELVIEW);
891  glPopMatrix();
892  d->mv_matrix[3][0] -= 0.5;
893  d->mv_matrix[3][1] -= 0.5;
894  }
895 }
896 
898 {
899  p->cleanupGLContextRefs(context);
900 }
901 
902 
903 static inline void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform)
904 {
905  if (smoothPixmapTransform) {
906  glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
907  glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
908  } else {
909  glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
910  glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
911  }
912  glTexParameterf(target, GL_TEXTURE_WRAP_S, wrapMode);
913  glTexParameterf(target, GL_TEXTURE_WRAP_T, wrapMode);
914 }
915 
916 static inline QPainterPath strokeForPath(const QPainterPath &path, const QPen &cpen) {
917  QPainterPathStroker stroker;
918  if (cpen.style() == Qt::CustomDashLine)
919  stroker.setDashPattern(cpen.dashPattern());
920  else
921  stroker.setDashPattern(cpen.style());
922 
923  stroker.setCapStyle(cpen.capStyle());
924  stroker.setJoinStyle(cpen.joinStyle());
925  stroker.setMiterLimit(cpen.miterLimit());
926  stroker.setDashOffset(cpen.dashOffset());
927 
928  qreal width = cpen.widthF();
929  if (width == 0)
930  stroker.setWidth(1);
931  else
932  stroker.setWidth(width);
933 
934  QPainterPath stroke = stroker.createStroke(path);
936  return stroke;
937 }
938 
940 {
941  struct CacheInfo
942  {
943  inline CacheInfo(QPainterPath p, QPainterPath sp, QPen stroke_pen) :
944  path(p), stroked_path(sp), pen(stroke_pen) {}
948  };
949 
951 
952 public:
953  inline QPainterPath getStrokedPath(const QPainterPath &path, const QPen &pen) {
954  quint64 hash_val = 0;
955 
956  for (int i = 0; i < path.elementCount() && i <= 2; i++) {
957  hash_val += quint64(path.elementAt(i).x);
958  hash_val += quint64(path.elementAt(i).y);
959  }
960 
961  QGLStrokeTableHash::const_iterator it = cache.constFind(hash_val);
962 
963  if (it == cache.constEnd())
964  return addCacheElement(hash_val, path, pen);
965  else {
966  do {
967  const CacheInfo &cache_info = it.value();
968  if (cache_info.path == path && cache_info.pen == pen)
969  return cache_info.stroked_path;
970  ++it;
971  } while (it != cache.constEnd() && it.key() == hash_val);
972  // an exact match for this path was not found, create new cache element
973  return addCacheElement(hash_val, path, pen);
974  }
975  }
976 
977 protected:
978  inline int maxCacheSize() const { return 500; }
979  QPainterPath addCacheElement(quint64 hash_val, QPainterPath path, const QPen &pen) {
980  if (cache.size() == maxCacheSize()) {
981  int elem_to_remove = qrand() % maxCacheSize();
982  cache.remove(cache.keys()[elem_to_remove]); // may remove more than 1, but OK
983  }
984  QPainterPath stroke = strokeForPath(path, pen);
985  CacheInfo cache_entry(path, stroke, pen);
986  return cache.insert(hash_val, cache_entry).value().stroked_path;
987  }
988 
989  QGLStrokeTableHash cache;
990 };
991 
992 Q_GLOBAL_STATIC(QGLStrokeCache, qt_opengl_stroke_cache)
993 
995 {
996  Q_OBJECT
997  struct CacheInfo
998  {
1000  stops(s), opacity(op), interpolationMode(mode) {}
1001 
1002  GLuint texId;
1006  };
1007 
1009 
1010 public:
1011  QGLGradientCache() : QObject(), buffer_ctx(0)
1012  {
1013  connect(QGLSignalProxy::instance(),
1014  SIGNAL(aboutToDestroyContext(const QGLContext*)),
1015  SLOT(cleanupGLContextRefs(const QGLContext*)));
1016  }
1017 
1018  inline GLuint getBuffer(const QGradient &gradient, qreal opacity, QGLContext *ctx) {
1019  if (buffer_ctx && !QGLContext::areSharing(buffer_ctx, ctx))
1020  cleanCache();
1021 
1022  buffer_ctx = ctx;
1023 
1024  quint64 hash_val = 0;
1025 
1026  QGradientStops stops = gradient.stops();
1027  for (int i = 0; i < stops.size() && i <= 2; i++)
1028  hash_val += stops[i].second.rgba();
1029 
1030  QGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
1031 
1032  if (it == cache.constEnd())
1033  return addCacheElement(hash_val, gradient, opacity);
1034  else {
1035  do {
1036  const CacheInfo &cache_info = it.value();
1037  if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode()) {
1038  return cache_info.texId;
1039  }
1040  ++it;
1041  } while (it != cache.constEnd() && it.key() == hash_val);
1042  // an exact match for these stops and opacity was not found, create new cache
1043  return addCacheElement(hash_val, gradient, opacity);
1044  }
1045  }
1046 
1047  inline int paletteSize() const { return 1024; }
1048 
1049 protected:
1050  inline int maxCacheSize() const { return 60; }
1051  inline void generateGradientColorTable(const QGradient& g,
1052  uint *colorTable,
1053  int size, qreal opacity) const;
1054  GLuint addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) {
1055  if (cache.size() == maxCacheSize()) {
1056  int elem_to_remove = qrand() % maxCacheSize();
1057  quint64 key = cache.keys()[elem_to_remove];
1058 
1059  // need to call glDeleteTextures on each removed cache entry:
1060  QGLGradientColorTableHash::const_iterator it = cache.constFind(key);
1061  do {
1062  glDeleteTextures(1, &it.value().texId);
1063  } while (++it != cache.constEnd() && it.key() == key);
1064  cache.remove(key); // may remove more than 1, but OK
1065  }
1066  CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
1067  uint buffer[1024];
1068  generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
1069  glGenTextures(1, &cache_entry.texId);
1070 #ifndef QT_OPENGL_ES
1071  glBindTexture(GL_TEXTURE_1D, cache_entry.texId);
1072  glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, paletteSize(),
1073  0, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
1074 #else
1075  // create 2D one-line texture instead. This requires an impl of manual GL_TEXGEN for all primitives
1076 #endif
1077  return cache.insert(hash_val, cache_entry).value().texId;
1078  }
1079 
1080  void cleanCache() {
1081  QGLShareContextScope scope(buffer_ctx);
1082  QGLGradientColorTableHash::const_iterator it = cache.constBegin();
1083  for (; it != cache.constEnd(); ++it) {
1084  const CacheInfo &cache_info = it.value();
1085  glDeleteTextures(1, &cache_info.texId);
1086  }
1087  cache.clear();
1088  }
1089 
1090  QGLGradientColorTableHash cache;
1091 
1093 
1094 public Q_SLOTS:
1095  void cleanupGLContextRefs(const QGLContext *context) {
1096  if (context == buffer_ctx) {
1097  cleanCache();
1098  buffer_ctx = 0;
1099  }
1100  }
1101 };
1102 
1103 static inline uint endianColor(uint c)
1104 {
1105 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1106  return c;
1107 #else
1108  return ( (c << 24) & 0xff000000)
1109  | ((c >> 24) & 0x000000ff)
1110  | ((c << 8) & 0x00ff0000)
1111  | ((c >> 8) & 0x0000ff00);
1112 #endif // Q_BYTE_ORDER
1113 }
1114 
1115 void QGLGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
1116 {
1117  int pos = 0;
1118  QGradientStops s = gradient.stops();
1119  QVector<uint> colors(s.size());
1120 
1121  for (int i = 0; i < s.size(); ++i)
1122  colors[i] = s[i].second.rgba();
1123 
1124  bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
1125 
1126  uint alpha = qRound(opacity * 256);
1127  uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha);
1128  qreal incr = 1.0 / qreal(size);
1129  qreal fpos = 1.5 * incr;
1130  colorTable[pos++] = endianColor(PREMUL(current_color));
1131 
1132  while (fpos <= s.first().first) {
1133  colorTable[pos] = colorTable[pos - 1];
1134  pos++;
1135  fpos += incr;
1136  }
1137 
1138  if (colorInterpolation)
1139  current_color = PREMUL(current_color);
1140 
1141  for (int i = 0; i < s.size() - 1; ++i) {
1142  qreal delta = 1/(s[i+1].first - s[i].first);
1143  uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha);
1144  if (colorInterpolation)
1145  next_color = PREMUL(next_color);
1146 
1147  while (fpos < s[i+1].first && pos < size) {
1148  int dist = int(256 * ((fpos - s[i].first) * delta));
1149  int idist = 256 - dist;
1150  if (colorInterpolation)
1151  colorTable[pos] = endianColor(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
1152  else
1153  colorTable[pos] = endianColor(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
1154  ++pos;
1155  fpos += incr;
1156  }
1157  current_color = next_color;
1158  }
1159 
1160  Q_ASSERT(s.size() > 0);
1161 
1162  uint last_color = endianColor(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha)));
1163  for (;pos < size; ++pos)
1164  colorTable[pos] = last_color;
1165 
1166  // Make sure the last color stop is represented at the end of the table
1167  colorTable[size-1] = last_color;
1168 }
1169 
1170 #ifndef Q_WS_QWS
1171 Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache)
1172 #endif
1173 
1175 {
1176 #ifdef QT_OPENGL_ES //###
1177  Q_UNUSED(g);
1178 #else
1179  GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, device->context());
1180  glBindTexture(GL_TEXTURE_1D, texId);
1181  grad_palette = texId;
1183  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1184  else if (g.spread() == QGradient::ReflectSpread)
1185  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT_IBM);
1186  else
1187  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1188 
1189  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1190  glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1191 
1192 #endif
1193 }
1194 
1195 
1196 inline void QOpenGLPaintEnginePrivate::setGradientOps(const QBrush &brush, const QRectF &bounds)
1197 {
1198  current_style = brush.style();
1199 
1200  if (current_style < Qt::LinearGradientPattern || current_style > Qt::ConicalGradientPattern) {
1201  setGLBrush(brush.color());
1202  qt_glColor4ubv(brush_color);
1203  }
1204 
1205  updateGradient(brush, bounds);
1206 
1207 #ifndef QT_OPENGL_ES //### GLES does not have GL_TEXTURE_GEN_ so we are falling back for gradients
1208  glDisable(GL_TEXTURE_GEN_S);
1209  glDisable(GL_TEXTURE_1D);
1210 
1211  if (current_style == Qt::LinearGradientPattern) {
1212  if (high_quality_antialiasing || !has_fast_composition_mode) {
1213  fragment_brush = FRAGMENT_PROGRAM_BRUSH_LINEAR;
1214  } else {
1215  glEnable(GL_TEXTURE_GEN_S);
1216  glEnable(GL_TEXTURE_1D);
1217  }
1218  } else {
1219  if (use_fragment_programs) {
1220  if (current_style == Qt::RadialGradientPattern)
1221  fragment_brush = FRAGMENT_PROGRAM_BRUSH_RADIAL;
1222  else if (current_style == Qt::ConicalGradientPattern)
1223  fragment_brush = FRAGMENT_PROGRAM_BRUSH_CONICAL;
1224  else if (current_style == Qt::SolidPattern)
1225  fragment_brush = FRAGMENT_PROGRAM_BRUSH_SOLID;
1226  else if (current_style == Qt::TexturePattern && !brush.texture().isQBitmap())
1227  fragment_brush = FRAGMENT_PROGRAM_BRUSH_TEXTURE;
1228  else
1229  fragment_brush = FRAGMENT_PROGRAM_BRUSH_PATTERN;
1230  }
1231  }
1232 #endif
1233 }
1234 
1237 {
1238 }
1239 
1241 {
1242 }
1243 
1245 {
1247 
1248  if (pdev->devType() == QInternal::OpenGL)
1249  d->device = static_cast<QGLPaintDevice*>(pdev);
1250  else
1251  d->device = QGLPaintDevice::getDevice(pdev);
1252 
1253  if (!d->device)
1254  return false;
1255 
1256  d->offscreen.setDevice(pdev);
1257  d->has_fast_pen = false;
1258  d->inverseScale = 1;
1259  d->opacity = 1;
1260  d->device->beginPaint();
1261  d->matrix = QTransform();
1262  d->has_antialiasing = false;
1263  d->high_quality_antialiasing = false;
1264 
1265  QSize sz(d->device->size());
1266  d->dirty_stencil = QRect(0, 0, sz.width(), sz.height());
1267 
1268  d->use_emulation = false;
1269 
1270  for (int i = 0; i < 4; ++i)
1271  for (int j = 0; j < 4; ++j)
1272  d->mv_matrix[i][j] = (i == j ? qreal(1) : qreal(0));
1273 
1274  bool has_frag_program = (QGLExtensions::glExtensions() & QGLExtensions::FragmentProgram)
1275  && (pdev->devType() != QInternal::Pixmap);
1276 
1277  QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
1278  if (!ctx) {
1279  qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context.";
1280  return false;
1281  }
1282 
1283  if (has_frag_program)
1285 
1286  d->use_stencil_method = d->device->format().stencil()
1288  if (d->device->format().directRendering()
1289  && (d->use_stencil_method && QGLExtensions::glExtensions() & QGLExtensions::StencilTwoSide))
1290  d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx);
1291 
1292 #ifdef Q_WS_X11
1293  static bool nvidia_workaround_needs_init = true;
1294  if (nvidia_workaround_needs_init) {
1295  // nvidia 9x.xx unix drivers contain a bug which requires us to
1296  // call glFinish before releasing an fbo to avoid painting
1297  // artifacts
1298  const QByteArray versionString(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
1299  const int pos = versionString.indexOf("NVIDIA");
1300  if (pos >= 0) {
1301  const float nvidiaDriverVersion = versionString.mid(pos + strlen("NVIDIA")).toFloat();
1302  qt_nvidiaFboNeedsFinish = nvidiaDriverVersion >= 90.0 && nvidiaDriverVersion < 100.0;
1303  }
1304  nvidia_workaround_needs_init = false;
1305  }
1306 #endif
1307 
1308 #ifndef QT_OPENGL_ES
1309  if (!ctx->d_ptr->internal_context) {
1310  glGetDoublev(GL_PROJECTION_MATRIX, &d->projection_matrix[0][0]);
1311  glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
1312  glPushAttrib(GL_ALL_ATTRIB_BITS);
1313 
1314  glDisableClientState(GL_EDGE_FLAG_ARRAY);
1315  glDisableClientState(GL_INDEX_ARRAY);
1316  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1317  glDisable(GL_TEXTURE_1D);
1318  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1319  glPixelTransferi(GL_MAP_COLOR, false);
1320  glPixelTransferi(GL_MAP_STENCIL, false);
1321  glDisable(GL_TEXTURE_GEN_S);
1322 
1323  glPixelStorei(GL_PACK_SWAP_BYTES, false);
1324  glPixelStorei(GL_PACK_LSB_FIRST, false);
1325  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1326  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
1327  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
1328  glPixelStorei(GL_PACK_ALIGNMENT, 4);
1329 
1330  glPixelStorei(GL_UNPACK_SWAP_BYTES, false);
1331  glPixelStorei(GL_UNPACK_LSB_FIRST, false);
1332  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1333  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1334  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1335  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1336 
1338  glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
1339  glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
1340  glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
1341  glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
1342  }
1343  }
1344 #endif
1345 
1346  if (!ctx->d_ptr->internal_context) {
1347  glMatrixMode(GL_MODELVIEW);
1348  glPushMatrix();
1349  glMatrixMode(GL_TEXTURE);
1350  glPushMatrix();
1351  glLoadIdentity();
1352  glDisableClientState(GL_COLOR_ARRAY);
1353  glDisableClientState(GL_NORMAL_ARRAY);
1354  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1355  glDisableClientState(GL_VERTEX_ARRAY);
1356 
1358  glDisable(GL_MULTISAMPLE);
1359  glDisable(GL_TEXTURE_2D);
1361  glDisable(GL_TEXTURE_RECTANGLE_NV);
1362  glDisable(GL_STENCIL_TEST);
1363  glDisable(GL_CULL_FACE);
1364  glDisable(GL_LIGHTING);
1365  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1366  }
1367 
1368  d->offscreen.begin();
1369 
1370  glViewport(0, 0, sz.width(), sz.height()); // XXX (Embedded): We need a solution for GLWidgets that draw in a part or a bigger surface...
1371  glMatrixMode(GL_PROJECTION);
1372  glLoadIdentity();
1373 #ifdef QT_OPENGL_ES
1374  glOrthof(0, sz.width(), sz.height(), 0, -999999, 999999);
1375 #else
1376  glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);
1377 #endif
1378  glMatrixMode(GL_MODELVIEW);
1379  glLoadIdentity();
1380  glEnable(GL_BLEND);
1381  d->composition_mode = QPainter::CompositionMode_SourceOver;
1382 
1383 #ifdef QT_OPENGL_ES
1384  d->max_texture_size = ctx->d_func()->maxTextureSize();
1385 #else
1386  bool shared_ctx = QGLContext::areSharing(d->device->context(), d->shader_ctx);
1387 
1388  if (shared_ctx) {
1389  d->max_texture_size = d->shader_ctx->d_func()->maxTextureSize();
1390  } else {
1391  d->max_texture_size = ctx->d_func()->maxTextureSize();
1392 
1393  if (d->shader_ctx) {
1394  d->shader_ctx->makeCurrent();
1395  glBindTexture(GL_TEXTURE_1D, 0);
1396  glDeleteTextures(1, &d->grad_palette);
1397 
1398  if (has_frag_program && d->use_fragment_programs)
1399  glDeleteTextures(1, &d->drawable_texture);
1400  ctx->makeCurrent();
1401  }
1402  d->shader_ctx = d->device->context();
1403  glGenTextures(1, &d->grad_palette);
1404 
1405  qt_mask_texture_cache()->clearCache();
1406  d->use_fragment_programs = has_frag_program;
1407  }
1408 
1409  if (d->use_fragment_programs && (!shared_ctx || sz.width() > d->drawable_texture_size.width()
1410  || sz.height() > d->drawable_texture_size.height()))
1411  {
1412  // delete old texture if size has increased, otherwise it was deleted earlier
1413  if (shared_ctx)
1414  glDeleteTextures(1, &d->drawable_texture);
1415 
1416  d->dirty_drawable_texture = true;
1417  d->drawable_texture_size = QSize(qt_next_power_of_two(sz.width()),
1418  qt_next_power_of_two(sz.height()));
1419  }
1420 #endif
1421 
1423  penChanged();
1424  brushChanged();
1425  opacityChanged();
1428  transformChanged();
1429  return true;
1430 }
1431 
1433 {
1435  d->flushDrawQueue();
1436  d->offscreen.end();
1437  QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
1438  if (!ctx->d_ptr->internal_context) {
1439  glMatrixMode(GL_TEXTURE);
1440  glPopMatrix();
1441  glMatrixMode(GL_MODELVIEW);
1442  glPopMatrix();
1443  }
1444 #ifndef QT_OPENGL_ES
1445  if (ctx->d_ptr->internal_context) {
1446  glDisable(GL_SCISSOR_TEST);
1447  } else {
1448  glMatrixMode(GL_PROJECTION);
1449  glLoadMatrixd(&d->projection_matrix[0][0]);
1450  glPopAttrib();
1451  glPopClientAttrib();
1452  }
1453 #endif
1454  d->device->endPaint();
1455  qt_mask_texture_cache()->maintainCache();
1456 
1457 #if defined(Q_WS_X11)
1458  // clear out the references we hold for textures bound with the
1459  // texture_from_pixmap extension
1460  ctx->d_func()->boundPixmaps.clear();
1461 #endif
1462  return true;
1463 }
1464 
1466 {
1468  QPaintEngine::DirtyFlags flags = state.state();
1469 
1470  bool update_fast_pen = false;
1471 
1472  if (flags & DirtyOpacity) {
1473  update_fast_pen = true;
1474  d->opacity = state.opacity();
1475  if (d->opacity > 1.0f)
1476  d->opacity = 1.0f;
1477  if (d->opacity < 0.f)
1478  d->opacity = 0.f;
1479  // force update
1480  flags |= DirtyPen;
1481  flags |= DirtyBrush;
1482  }
1483 
1484  if (flags & DirtyTransform) {
1485  update_fast_pen = true;
1486  updateMatrix(state.transform());
1487  // brush setup depends on transform state
1488  if (state.brush().style() != Qt::NoBrush)
1489  flags |= DirtyBrush;
1490  }
1491 
1492  if (flags & DirtyPen) {
1493  update_fast_pen = true;
1494  updatePen(state.pen());
1495  }
1496 
1497  if (flags & (DirtyBrush | DirtyBrushOrigin)) {
1498  updateBrush(state.brush(), state.brushOrigin());
1499  }
1500 
1501  if (flags & DirtyFont) {
1502  updateFont(state.font());
1503  }
1504 
1505  if (state.state() & DirtyClipEnabled) {
1506  if (state.isClipEnabled())
1508  else
1510  }
1511 
1512  if (flags & DirtyClipPath) {
1514  state.clipPath().fillRule()),
1515  state.clipOperation());
1516  }
1517 
1518  if (flags & DirtyClipRegion) {
1519  updateClipRegion(state.clipRegion(), state.clipOperation());
1520  }
1521 
1522  if (flags & DirtyHints) {
1523  updateRenderHints(state.renderHints());
1524  }
1525 
1526  if (flags & DirtyCompositionMode) {
1528  }
1529 
1530  if (update_fast_pen) {
1532  qreal pen_width = d->cpen.widthF();
1533  d->has_fast_pen =
1534  ((pen_width == 0 || (pen_width <= 1 && d->txop <= QTransform::TxTranslate))
1535  || d->cpen.isCosmetic())
1536  && d->cpen.style() == Qt::SolidLine
1537  && d->cpen.isSolid();
1538  }
1539 }
1540 
1541 
1543 {
1544  inv_matrix_data[0][0] = inv_matrix.m11();
1545  inv_matrix_data[1][0] = inv_matrix.m21();
1546  inv_matrix_data[2][0] = inv_matrix.m31();
1547 
1548  inv_matrix_data[0][1] = inv_matrix.m12();
1549  inv_matrix_data[1][1] = inv_matrix.m22();
1550  inv_matrix_data[2][1] = inv_matrix.m32();
1551 
1552  inv_matrix_data[0][2] = inv_matrix.m13();
1553  inv_matrix_data[1][2] = inv_matrix.m23();
1554  inv_matrix_data[2][2] = inv_matrix.m33();
1555 }
1556 
1557 
1559 {
1560 #ifdef QT_OPENGL_ES
1561  Q_UNUSED(brush);
1562 #else
1563  bool has_mirrored_repeat = QGLExtensions::glExtensions() & QGLExtensions::MirroredRepeat;
1564  Qt::BrushStyle style = brush.style();
1565 
1566  if (has_mirrored_repeat && style == Qt::LinearGradientPattern) {
1567  const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
1568  QTransform m = brush.transform();
1569  QPointF realStart = g->start();
1570  QPointF realFinal = g->finalStop();
1571  QPointF start = m.map(realStart);
1572  QPointF stop;
1573 
1574  if (qFuzzyCompare(m.m11(), m.m22()) && m.m12() == 0.0 && m.m21() == 0.0) {
1575  // It is a simple uniform scale and/or translation
1576  stop = m.map(realFinal);
1577  } else {
1578  // It is not enough to just transform the endpoints.
1579  // We have to make sure the _pattern_ is transformed correctly.
1580 
1581  qreal odx = realFinal.x() - realStart.x();
1582  qreal ody = realFinal.y() - realStart.y();
1583 
1584  // nx, ny and dx, dy are normal and gradient direction after transform:
1585  qreal nx = m.m11()*ody - m.m21()*odx;
1586  qreal ny = m.m12()*ody - m.m22()*odx;
1587 
1588  qreal dx = m.m11()*odx + m.m21()*ody;
1589  qreal dy = m.m12()*odx + m.m22()*ody;
1590 
1591  qreal lx = 1 / (dx - dy*nx/ny);
1592  qreal ly = 1 / (dy - dx*ny/nx);
1593  qreal l = 1 / qSqrt(lx*lx+ly*ly);
1594 
1595  stop = start + QPointF(-ny, nx) * l/qSqrt(nx*nx+ny*ny);
1596  }
1597 
1598  float tr[4], f;
1599  tr[0] = stop.x() - start.x();
1600  tr[1] = stop.y() - start.y();
1601  f = 1.0 / (tr[0]*tr[0] + tr[1]*tr[1]);
1602  tr[0] *= f;
1603  tr[1] *= f;
1604  tr[2] = 0;
1605  tr[3] = -(start.x()*tr[0] + start.y()*tr[1]);
1606  brush_color[0] = brush_color[1] = brush_color[2] = brush_color[3] = 255;
1607  qt_glColor4ubv(brush_color);
1608  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1609  glTexGenfv(GL_S, GL_OBJECT_PLANE, tr);
1610  }
1611 
1612  if (use_fragment_programs) {
1613  if (style == Qt::RadialGradientPattern) {
1614  const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
1615  QPointF realCenter = g->center();
1616  QPointF realFocal = g->focalPoint();
1617  qreal realRadius = g->radius();
1618  QTransform translate(1, 0, 0, 1, -realFocal.x(), -realFocal.y());
1619  QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
1620  QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
1621  QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
1622 
1623  setInvMatrixData(inv_matrix);
1624 
1625  fmp_data[0] = realCenter.x() - realFocal.x();
1626  fmp_data[1] = realCenter.y() - realFocal.y();
1627 
1628  fmp2_m_radius2_data[0] = -fmp_data[0] * fmp_data[0] - fmp_data[1] * fmp_data[1] + realRadius * realRadius;
1629  } else if (style == Qt::ConicalGradientPattern) {
1630  const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
1631  QPointF realCenter = g->center();
1632  QTransform translate(1, 0, 0, 1, -realCenter.x(), -realCenter.y());
1633  QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
1634  QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
1635  QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
1636 
1637  setInvMatrixData(inv_matrix);
1638 
1639  angle_data[0] = -(g->angle() * 2 * Q_PI) / 360.0;
1640  } else if (style == Qt::LinearGradientPattern) {
1641  const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
1642 
1643  QPointF realStart = g->start();
1644  QPointF realFinal = g->finalStop();
1645  QTransform translate(1, 0, 0, 1, -realStart.x(), -realStart.y());
1646  QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
1647  QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
1648  QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
1649 
1650  setInvMatrixData(inv_matrix);
1651 
1652  QPointF l = realFinal - realStart;
1653 
1654  linear_data[0] = l.x();
1655  linear_data[1] = l.y();
1656 
1657  linear_data[2] = 1.0f / (l.x() * l.x() + l.y() * l.y());
1658  } else if (style != Qt::SolidPattern) {
1659  QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
1660  QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
1661  QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted();
1662 
1663  setInvMatrixData(inv_matrix);
1664  }
1665  }
1666 
1667  if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
1668  createGradientPaletteTexture(*brush.gradient());
1669  }
1670 #endif
1671 }
1672 
1673 
1675 {
1676 public:
1679  QGLTrapezoid toGLTrapezoid(const Trapezoid &trap);
1680 };
1681 
1683 {
1684  QGLTrapezoid t;
1685 
1686  t.top = Q27Dot5ToDouble(trap.top);
1687  t.bottom = Q27Dot5ToDouble(trap.bottom);
1688 
1689  Q27Dot5 y = trap.topLeft->y - trap.bottomLeft->y;
1690 
1691  qreal topLeftY = Q27Dot5ToDouble(trap.topLeft->y);
1692 
1693  qreal tx = Q27Dot5ToDouble(trap.topLeft->x);
1694  qreal m = (-tx + Q27Dot5ToDouble(trap.bottomLeft->x)) / Q27Dot5ToDouble(y);
1695  t.topLeftX = tx + m * (topLeftY - t.top);
1696  t.bottomLeftX = tx + m * (topLeftY - t.bottom);
1697 
1698  y = trap.topRight->y - trap.bottomRight->y;
1699 
1700  qreal topRightY = Q27Dot5ToDouble(trap.topRight->y);
1701 
1702  tx = Q27Dot5ToDouble(trap.topRight->x);
1703  m = (-tx + Q27Dot5ToDouble(trap.bottomRight->x)) / Q27Dot5ToDouble(y);
1704 
1705  t.topRightX = tx + m * (topRightY - Q27Dot5ToDouble(trap.top));
1706  t.bottomRightX = tx + m * (topRightY - Q27Dot5ToDouble(trap.bottom));
1707 
1708  return t;
1709 }
1710 
1712 {
1713 public:
1714  void addTrap(const Trapezoid &trap);
1715  void tessellate(const QPointF *points, int nPoints, bool winding) {
1716  trapezoids.reserve(trapezoids.size() + nPoints);
1717  setWinding(winding);
1718  QTessellator::tessellate(points, nPoints);
1719  }
1720 
1722 };
1723 
1725 {
1726  trapezoids.append(toGLTrapezoid(trap));
1727 }
1728 
1729 #ifndef QT_OPENGL_ES
1730 static void drawTrapezoid(const QGLTrapezoid &trap, const qreal offscreenHeight, QGLContext *ctx)
1731 {
1732  qreal minX = qMin(trap.topLeftX, trap.bottomLeftX);
1733  qreal maxX = qMax(trap.topRightX, trap.bottomRightX);
1734 
1735  if (qFuzzyCompare(trap.top, trap.bottom) || qFuzzyCompare(minX, maxX) ||
1737  return;
1738 
1739  const qreal xpadding = 1.0;
1740  const qreal ypadding = 1.0;
1741 
1742  qreal topDist = offscreenHeight - trap.top;
1743  qreal bottomDist = offscreenHeight - trap.bottom;
1744 
1745  qreal reciprocal = bottomDist / (bottomDist - topDist);
1746 
1747  qreal leftB = trap.bottomLeftX + (trap.topLeftX - trap.bottomLeftX) * reciprocal;
1748  qreal rightB = trap.bottomRightX + (trap.topRightX - trap.bottomRightX) * reciprocal;
1749 
1750  const bool topZero = qFuzzyIsNull(topDist);
1751 
1752  reciprocal = topZero ? 1.0 / bottomDist : 1.0 / topDist;
1753 
1754  qreal leftA = topZero ? (trap.bottomLeftX - leftB) * reciprocal : (trap.topLeftX - leftB) * reciprocal;
1755  qreal rightA = topZero ? (trap.bottomRightX - rightB) * reciprocal : (trap.topRightX - rightB) * reciprocal;
1756 
1757  qreal invLeftA = qFuzzyIsNull(leftA) ? 0.0 : 1.0 / leftA;
1758  qreal invRightA = qFuzzyIsNull(rightA) ? 0.0 : 1.0 / rightA;
1759 
1760  // fragment program needs the negative of invRightA as it mirrors the line
1761  glTexCoord4f(topDist, bottomDist, invLeftA, -invRightA);
1762  glMultiTexCoord4f(GL_TEXTURE1, leftA, leftB, rightA, rightB);
1763 
1764  qreal topY = trap.top - ypadding;
1765  qreal bottomY = trap.bottom + ypadding;
1766 
1767  qreal bounds_bottomLeftX = leftA * (offscreenHeight - bottomY) + leftB;
1768  qreal bounds_bottomRightX = rightA * (offscreenHeight - bottomY) + rightB;
1769  qreal bounds_topLeftX = leftA * (offscreenHeight - topY) + leftB;
1770  qreal bounds_topRightX = rightA * (offscreenHeight - topY) + rightB;
1771 
1772  QPointF leftNormal(1, -leftA);
1773  leftNormal /= qSqrt(leftNormal.x() * leftNormal.x() + leftNormal.y() * leftNormal.y());
1774  QPointF rightNormal(1, -rightA);
1775  rightNormal /= qSqrt(rightNormal.x() * rightNormal.x() + rightNormal.y() * rightNormal.y());
1776 
1777  qreal left_padding = xpadding / qAbs(leftNormal.x());
1778  qreal right_padding = xpadding / qAbs(rightNormal.x());
1779 
1780  glVertex2d(bounds_topLeftX - left_padding, topY);
1781  glVertex2d(bounds_topRightX + right_padding, topY);
1782  glVertex2d(bounds_bottomRightX + right_padding, bottomY);
1783  glVertex2d(bounds_bottomLeftX - left_padding, bottomY);
1784 
1785  glTexCoord4f(0.0f, 0.0f, 0.0f, 1.0f);
1786 }
1787 #endif // !Q_WS_QWS
1788 
1790 {
1791 public:
1792  QOpenGLTrapezoidToArrayTessellator() : vertices(0), allocated(0), size(0) {}
1794  GLfloat *vertices;
1796  int size;
1798  void addTrap(const Trapezoid &trap);
1799  void tessellate(const QPointF *points, int nPoints, bool winding) {
1800  size = 0;
1801  setWinding(winding);
1802  bounds = QTessellator::tessellate(points, nPoints);
1803  }
1804 };
1805 
1807 {
1808  // On OpenGL ES we convert the trap to 2 triangles
1809 #ifndef QT_OPENGL_ES
1810  if (size > allocated - 8) {
1811 #else
1812  if (size > allocated - 12) {
1813 #endif
1814  allocated = qMax(2*allocated, 512);
1815  vertices = (GLfloat *)realloc(vertices, allocated * sizeof(GLfloat));
1816  }
1817 
1818  QGLTrapezoid t = toGLTrapezoid(trap);
1819 
1820 #ifndef QT_OPENGL_ES
1821  vertices[size++] = t.topLeftX;
1822  vertices[size++] = t.top;
1823  vertices[size++] = t.topRightX;
1824  vertices[size++] = t.top;
1825  vertices[size++] = t.bottomRightX;
1826  vertices[size++] = t.bottom;
1827  vertices[size++] = t.bottomLeftX;
1828  vertices[size++] = t.bottom;
1829 #else
1830  // First triangle
1831  vertices[size++] = t.topLeftX;
1832  vertices[size++] = t.top;
1833  vertices[size++] = t.topRightX;
1834  vertices[size++] = t.top;
1835  vertices[size++] = t.bottomRightX;
1836  vertices[size++] = t.bottom;
1837 
1838  // Second triangle
1839  vertices[size++] = t.bottomLeftX;
1840  vertices[size++] = t.bottom;
1841  vertices[size++] = t.topLeftX;
1842  vertices[size++] = t.top;
1843  vertices[size++] = t.bottomRightX;
1844  vertices[size++] = t.bottom;
1845 #endif
1846 }
1847 
1848 
1849 void QOpenGLPaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int pointCount,
1850  Qt::FillRule fill)
1851 {
1853  tessellator.tessellate(polygonPoints, pointCount, fill == Qt::WindingFill);
1854 
1855  DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon with" << pointCount << "points using fillPolygon_dev";
1856 
1857  setGradientOps(cbrush, tessellator.bounds);
1858 
1859  bool fast_style = current_style == Qt::LinearGradientPattern
1860  || current_style == Qt::SolidPattern;
1861 
1862 #ifndef QT_OPENGL_ES
1863  GLenum geometry_mode = GL_QUADS;
1864 #else
1865  GLenum geometry_mode = GL_TRIANGLES;
1866 #endif
1867 
1868  if (use_fragment_programs && !(fast_style && has_fast_composition_mode)) {
1869  composite(geometry_mode, tessellator.vertices, tessellator.size / 2);
1870  } else {
1871  glVertexPointer(2, GL_FLOAT, 0, tessellator.vertices);
1872  glEnableClientState(GL_VERTEX_ARRAY);
1873  glDrawArrays(geometry_mode, 0, tessellator.size/2);
1874  glDisableClientState(GL_VERTEX_ARRAY);
1875  }
1876 }
1877 
1878 
1880 {
1881  tess_points.add(QPointF(x, y));
1882 
1883  if (x > max_x)
1884  max_x = x;
1885  else if (x < min_x)
1886  min_x = x;
1887  if (y > max_y)
1888  max_y = y;
1889  else if (y < min_y)
1890  min_y = y;
1891 }
1892 
1893 inline void QOpenGLPaintEnginePrivate::curveToStencil(const QPointF &cp1, const QPointF &cp2, const QPointF &ep)
1894 {
1895  qreal inverseScaleHalf = inverseScale / 2;
1896 
1897  QBezier beziers[32];
1898  beziers[0] = QBezier::fromPoints(tess_points.last(), cp1, cp2, ep);
1899  QBezier *b = beziers;
1900  while (b >= beziers) {
1901  // check if we can pop the top bezier curve from the stack
1902  qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1);
1903  qreal d;
1904  if (l > inverseScale) {
1905  d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2) - (b->y4 - b->y1)*(b->x1 - b->x2) )
1906  + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3) - (b->y4 - b->y1)*(b->x1 - b->x3) );
1907  d /= l;
1908  } else {
1909  d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) +
1910  qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
1911  }
1912  if (d < inverseScaleHalf || b == beziers + 31) {
1913  // good enough, we pop it off and add the endpoint
1914  lineToStencil(b->x4, b->y4);
1915  --b;
1916  } else {
1917  // split, second half of the polygon goes lower into the stack
1918  b->split(b+1, b);
1919  ++b;
1920  }
1921  }
1922 }
1923 
1924 
1926 {
1927  const QPainterPath::Element &first = path.elementAt(0);
1928  min_x = max_x = first.x;
1929  min_y = max_y = first.y;
1930 
1931  tess_points.reset();
1932  tess_points_stops.clear();
1933  lineToStencil(first.x, first.y);
1934 
1935  for (int i=1; i<path.elementCount(); ++i) {
1936  const QPainterPath::Element &e = path.elementAt(i);
1937  switch (e.type) {
1939  tess_points_stops.append(tess_points.size());
1940  lineToStencil(e.x, e.y);
1941  break;
1943  lineToStencil(e.x, e.y);
1944  break;
1946  curveToStencil(e, path.elementAt(i+1), path.elementAt(i+2));
1947  i+=2;
1948  break;
1949  default:
1950  break;
1951  }
1952  }
1953  lineToStencil(first.x, first.y);
1954  tess_points_stops.append(tess_points.size());
1955 }
1956 
1957 
1959 {
1960  if (tess_points_stops.count() == 0)
1961  return;
1962  glEnableClientState(GL_VERTEX_ARRAY);
1963  glVertexPointer(2, GL_DOUBLE, 0, tess_points.data());
1964  int previous_stop = 0;
1965  foreach(int stop, tess_points_stops) {
1966  glDrawArrays(GL_TRIANGLE_FAN, previous_stop, stop-previous_stop);
1967  previous_stop = stop;
1968  }
1969  glDisableClientState(GL_VERTEX_ARRAY);
1970 }
1971 
1973 {
1975 
1976  QRect rect = dirty_stencil.boundingRect();
1977 
1978  if (use_system_clip)
1979  rect = q->systemClip().intersected(dirty_stencil).boundingRect();
1980 
1981  glStencilMask(~0);
1982 
1983  if (!rect.isEmpty()) {
1984  disableClipping();
1985 
1986  glEnable(GL_SCISSOR_TEST);
1987 
1988  const int left = rect.left();
1989  const int width = rect.width();
1990  const int bottom = device->size().height() - (rect.bottom() + 1);
1991  const int height = rect.height();
1992 
1993  glScissor(left, bottom, width, height);
1994 
1995  glClearStencil(0);
1996  glClear(GL_STENCIL_BUFFER_BIT);
1997  dirty_stencil -= rect;
1998 
1999  glDisable(GL_SCISSOR_TEST);
2000 
2001  enableClipping();
2002  }
2003 
2004  // Enable stencil.
2005  glEnable(GL_STENCIL_TEST);
2006 
2007  // Disable color writes.
2008  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2009 
2010  GLuint stencilMask = 0;
2011 
2012  if (fillRule == Qt::OddEvenFill) {
2013  stencilMask = 1;
2014 
2015  // Enable stencil writes.
2016  glStencilMask(stencilMask);
2017 
2018  // Set stencil xor mode.
2019  glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
2020 
2021  // Disable stencil func.
2022  glStencilFunc(GL_ALWAYS, 0, ~0);
2023 
2024  drawVertexArrays();
2025  } else if (fillRule == Qt::WindingFill) {
2026  stencilMask = ~0;
2027 
2028  if (has_stencil_face_ext) {
2030  glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
2031 
2033  glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT);
2034  glStencilFunc(GL_ALWAYS, 0, ~0);
2035 
2037  glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT);
2038  glStencilFunc(GL_ALWAYS, 0, ~0);
2039 
2040  drawVertexArrays();
2041 
2042  glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
2043  } else {
2044  glStencilFunc(GL_ALWAYS, 0, ~0);
2045  glEnable(GL_CULL_FACE);
2046 
2047  glCullFace(GL_BACK);
2048  glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT);
2049  drawVertexArrays();
2050 
2051  glCullFace(GL_FRONT);
2052  glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT);
2053  drawVertexArrays();
2054 
2055  glDisable(GL_CULL_FACE);
2056  }
2057  }
2058 
2059  // Enable color writes.
2060  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2061  glStencilMask(stencilMask);
2062 
2063  setGradientOps(cbrush, QRectF(QPointF(min_x, min_y), QSizeF(max_x - min_x, max_y - min_y)));
2064 
2065  bool fast_fill = has_fast_composition_mode && (current_style == Qt::LinearGradientPattern || current_style == Qt::SolidPattern);
2066 
2067  if (use_fragment_programs && !fast_fill) {
2068  DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon using stencil method (fragment programs)";
2069  QRectF rect(QPointF(min_x, min_y), QSizeF(max_x - min_x, max_y - min_y));
2070 
2071  // Enable stencil func.
2072  glStencilFunc(GL_NOTEQUAL, 0, stencilMask);
2073  glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
2074  composite(rect);
2075  } else {
2076  DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon using stencil method (no fragment programs)";
2077 
2078  // Enable stencil func.
2079  glStencilFunc(GL_NOTEQUAL, 0, stencilMask);
2080  glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
2081 #ifndef QT_OPENGL_ES
2082  glBegin(GL_QUADS);
2083  glVertex2f(min_x, min_y);
2084  glVertex2f(max_x, min_y);
2085  glVertex2f(max_x, max_y);
2086  glVertex2f(min_x, max_y);
2087  glEnd();
2088 #endif
2089  }
2090 
2091  // Disable stencil writes.
2092  glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2093  glStencilMask(0);
2094  glDisable(GL_STENCIL_TEST);
2095 }
2096 
2098 {
2099  if (path.isEmpty())
2100  return;
2101 
2102  if (use_stencil_method && !high_quality_antialiasing) {
2103  pathToVertexArrays(path);
2104  fillVertexArray(path.fillRule());
2105  return;
2106  }
2107 
2108  glMatrixMode(GL_MODELVIEW);
2109  glLoadIdentity();
2110 
2111  if (high_quality_antialiasing)
2112  drawOffscreenPath(path);
2113  else {
2114  QPolygonF poly = path.toFillPolygon(matrix);
2115  fillPolygon_dev(poly.data(), poly.count(),
2116  path.fillRule());
2117  }
2118 
2119  updateGLMatrix();
2120 }
2121 
2123 
2124 static inline bool needsEmulation(Qt::BrushStyle style)
2125 {
2126  return !(style == Qt::SolidPattern
2127  || (style == Qt::LinearGradientPattern
2129 }
2130 
2132 {
2133  use_emulation = (!use_fragment_programs
2134  && ((has_pen && needsEmulation(pen_brush_style))
2135  || (has_brush && needsEmulation(brush_style))))
2136  || (has_pen && qt_isExtendedRadialGradient(cpen.brush()))
2137  || (has_brush && qt_isExtendedRadialGradient(cbrush));
2138 }
2139 
2141 {
2143  Qt::PenStyle pen_style = pen.style();
2144  d->pen_brush_style = pen.brush().style();
2145  d->cpen = pen;
2146  d->has_pen = (pen_style != Qt::NoPen) && (d->pen_brush_style != Qt::NoBrush);
2147  d->updateUseEmulation();
2148 
2149  if (pen.isCosmetic()) {
2150  GLfloat width = pen.widthF() == 0.0f ? 1.0f : pen.widthF();
2151  glLineWidth(width);
2152  glPointSize(width);
2153  }
2154 
2155  if (d->pen_brush_style >= Qt::LinearGradientPattern
2156  && d->pen_brush_style <= Qt::ConicalGradientPattern)
2157  {
2158  d->setGLPen(Qt::white);
2159  } else {
2160  d->setGLPen(pen.color());
2161  }
2162 
2163  d->updateFastPen();
2164 }
2165 
2166 void QOpenGLPaintEngine::updateBrush(const QBrush &brush, const QPointF &origin)
2167 {
2169  d->cbrush = brush;
2170  d->brush_style = brush.style();
2171  d->brush_origin = origin;
2172  d->has_brush = (d->brush_style != Qt::NoBrush);
2173  d->updateUseEmulation();
2174 }
2175 
2177 {
2178 }
2179 
2181 {
2183 
2184  d->matrix = mtx;
2185 
2186  d->mv_matrix[0][0] = mtx.m11();
2187  d->mv_matrix[0][1] = mtx.m12();
2188  d->mv_matrix[0][2] = 0;
2189  d->mv_matrix[0][3] = mtx.m13();
2190 
2191  d->mv_matrix[1][0] = mtx.m21();
2192  d->mv_matrix[1][1] = mtx.m22();
2193  d->mv_matrix[1][2] = 0;
2194  d->mv_matrix[1][3] = mtx.m23();
2195 
2196  d->mv_matrix[2][0] = 0;
2197  d->mv_matrix[2][1] = 0;
2198  d->mv_matrix[2][2] = 1;
2199  d->mv_matrix[2][3] = 0;
2200 
2201  d->mv_matrix[3][0] = mtx.dx();
2202  d->mv_matrix[3][1] = mtx.dy();
2203  d->mv_matrix[3][2] = 0;
2204  d->mv_matrix[3][3] = mtx.m33();
2205 
2206  d->txop = mtx.type();
2207 
2208  // 1/10000 == 0.0001, so we have good enough res to cover curves
2209  // that span the entire widget...
2210  d->inverseScale = qMax(1 / qMax( qMax(qAbs(mtx.m11()), qAbs(mtx.m22())),
2211  qMax(qAbs(mtx.m12()), qAbs(mtx.m21())) ),
2212  qreal(0.0001));
2213 
2214  d->updateGLMatrix();
2215  d->updateFastPen();
2216 }
2217 
2219 {
2220  glMatrixMode(GL_MODELVIEW);
2221 #ifndef QT_OPENGL_ES
2222  glLoadMatrixd(&mv_matrix[0][0]);
2223 #else
2224  glLoadMatrixf(&mv_matrix[0][0]);
2225 #endif
2226 }
2227 
2229 {
2230  glDisable(GL_DEPTH_TEST);
2231  glDisable(GL_SCISSOR_TEST);
2232 }
2233 
2235 {
2237  if (!q->state()->hasClipping)
2238  return;
2239 
2240  if (q->state()->fastClip.isEmpty())
2241  glEnable(GL_DEPTH_TEST);
2242  else
2243  updateDepthClip(); // this will enable the scissor test
2244 }
2245 
2247 {
2249 
2250  ++q->state()->depthClipId;
2251 
2252  glDisable(GL_DEPTH_TEST);
2253  glDisable(GL_SCISSOR_TEST);
2254 
2255  if (!q->state()->hasClipping)
2256  return;
2257 
2258  QRect fastClip;
2259  if (q->state()->clipEnabled) {
2260  fastClip = q->state()->fastClip;
2261  } else if (use_system_clip && q->systemClip().rects().count() == 1) {
2262  fastClip = q->systemClip().rects().at(0);
2263  }
2264 
2265  if (!fastClip.isEmpty()) {
2266  glEnable(GL_SCISSOR_TEST);
2267 
2268  const int left = fastClip.left();
2269  const int width = fastClip.width();
2270  const int bottom = device->size().height() - (fastClip.bottom() + 1);
2271  const int height = fastClip.height();
2272 
2273  glScissor(left, bottom, width, height);
2274  return;
2275  }
2276 
2277 #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_2)
2278  glClearDepthf(0.0f);
2279 #else
2280  glClearDepth(0.0f);
2281 #endif
2282 
2283  glEnable(GL_DEPTH_TEST);
2284  glDepthMask(GL_TRUE);
2285  glClear(GL_DEPTH_BUFFER_BIT);
2286 
2287  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2288  glDepthFunc(GL_ALWAYS);
2289 
2290  const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects();
2291 
2292  // rectangle count * 2 (triangles) * vertex count * component count (Z omitted)
2293  QDataBuffer<GLfloat> clipVertex(rects.size()*2*3*2);
2294  for (int i = 0; i < rects.size(); ++i) {
2295  GLfloat x = GLfloat(rects.at(i).left());
2296  GLfloat w = GLfloat(rects.at(i).width());
2297  GLfloat h = GLfloat(rects.at(i).height());
2298  GLfloat y = GLfloat(rects.at(i).top());
2299 
2300  // First triangle
2301  clipVertex.add(x);
2302  clipVertex.add(y);
2303 
2304  clipVertex.add(x);
2305  clipVertex.add(y + h);
2306 
2307  clipVertex.add(x + w);
2308  clipVertex.add(y);
2309 
2310  // Second triangle
2311  clipVertex.add(x);
2312  clipVertex.add(y + h);
2313 
2314  clipVertex.add(x + w);
2315  clipVertex.add(y + h);
2316 
2317  clipVertex.add (x + w);
2318  clipVertex.add(y);
2319  }
2320 
2321  if (rects.size()) {
2322  glMatrixMode(GL_MODELVIEW);
2323  glLoadIdentity();
2324 
2325  glEnableClientState(GL_VERTEX_ARRAY);
2326  glVertexPointer(2, GL_FLOAT, 0, clipVertex.data());
2327 
2328  glDrawArrays(GL_TRIANGLES, 0, rects.size()*2*3);
2329  glDisableClientState(GL_VERTEX_ARRAY);
2330  updateGLMatrix();
2331  }
2332 
2333  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2334  glDepthMask(GL_FALSE);
2335  glDepthFunc(GL_LEQUAL);
2336 }
2337 
2339 {
2341  if (q->painter()->hasClipping())
2342  q->updateClipRegion(q->painter()->clipRegion(), Qt::ReplaceClip);
2343  else
2344  q->updateClipRegion(QRegion(), Qt::NoClip);
2345 }
2346 
2348 {
2350 
2351  // clipping is only supported when a stencil or depth buffer is
2352  // available
2353  if (!d->device->format().depth())
2354  return;
2355 
2356  d->use_system_clip = false;
2357  QRegion sysClip = systemClip();
2358  if (!sysClip.isEmpty()) {
2359  if (d->pdev->devType() != QInternal::Widget) {
2360  d->use_system_clip = true;
2361  } else {
2362 #ifndef Q_WS_QWS
2363  // Only use the system clip if we're currently rendering a widget with a GL painter.
2364  if (d->currentClipWidget) {
2365  QWidgetPrivate *widgetPrivate = qt_widget_private(d->currentClipWidget->window());
2366  d->use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
2367  }
2368 #endif
2369  }
2370  }
2371 
2372  d->flushDrawQueue();
2373 
2374  if (op == Qt::NoClip && !d->use_system_clip) {
2375  state()->hasClipping = false;
2376  state()->clipRegion = QRegion();
2377  d->updateDepthClip();
2378  return;
2379  }
2380 
2381  bool isScreenClip = false;
2382  if (!d->use_system_clip) {
2383  QVector<QRect> untransformedRects = clipRegion.rects();
2384 
2385  if (untransformedRects.size() == 1) {
2386  QPainterPath path;
2387  path.addRect(untransformedRects[0]);
2388  path = d->matrix.map(path);
2389 
2390  if (path.contains(QRectF(QPointF(), d->device->size())))
2391  isScreenClip = true;
2392  }
2393  }
2394 
2395  QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix;
2396  switch (op) {
2397  case Qt::NoClip:
2398  if (!d->use_system_clip)
2399  break;
2400  state()->clipRegion = sysClip;
2401  break;
2402  case Qt::IntersectClip:
2403  if (isScreenClip)
2404  return;
2405  if (state()->hasClipping) {
2406  state()->clipRegion &= region;
2407  break;
2408  }
2409  // fall through
2410  case Qt::ReplaceClip:
2411  if (d->use_system_clip)
2412  state()->clipRegion = region & sysClip;
2413  else
2414  state()->clipRegion = region;
2415  break;
2416  case Qt::UniteClip:
2417  state()->clipRegion |= region;
2418  if (d->use_system_clip)
2419  state()->clipRegion &= sysClip;
2420  break;
2421  default:
2422  break;
2423  }
2424 
2425  if (isScreenClip) {
2426  state()->hasClipping = false;
2427  state()->clipRegion = QRegion();
2428  } else {
2429  state()->hasClipping = op != Qt::NoClip || d->use_system_clip;
2430  }
2431 
2432  if (state()->hasClipping && state()->clipRegion.rects().size() == 1)
2433  state()->fastClip = state()->clipRegion.rects().at(0);
2434  else
2435  state()->fastClip = QRect();
2436 
2437  d->updateDepthClip();
2438 }
2439 
2440 void QOpenGLPaintEngine::updateRenderHints(QPainter::RenderHints hints)
2441 {
2443 
2444  d->flushDrawQueue();
2445  d->use_smooth_pixmap_transform = bool(hints & QPainter::SmoothPixmapTransform);
2446  if ((hints & QPainter::Antialiasing) || (hints & QPainter::HighQualityAntialiasing)) {
2447  if (d->use_fragment_programs && QGLOffscreen::isSupported()
2448  && (hints & QPainter::HighQualityAntialiasing)) {
2449  d->high_quality_antialiasing = true;
2450  } else {
2451  d->high_quality_antialiasing = false;
2453  glEnable(GL_MULTISAMPLE);
2454  }
2455  } else {
2456  d->high_quality_antialiasing = false;
2458  glDisable(GL_MULTISAMPLE);
2459  }
2460 
2461  if (d->high_quality_antialiasing) {
2462  d->offscreen.initialize();
2463 
2464  if (!d->offscreen.isValid()) {
2465  DEBUG_ONCE_STR("Unable to initialize offscreen, disabling high quality antialiasing");
2466  d->high_quality_antialiasing = false;
2468  glEnable(GL_MULTISAMPLE);
2469  }
2470  }
2471 
2472  d->has_antialiasing = d->high_quality_antialiasing
2473  || ((hints & QPainter::Antialiasing)
2475 }
2476 
2477 
2478 void QOpenGLPaintEnginePrivate::setPorterDuffData(float a, float b, float x, float y, float z)
2479 {
2480  porterduff_ab_data[0] = a;
2481  porterduff_ab_data[1] = b;
2482 
2483  porterduff_xyz_data[0] = x;
2484  porterduff_xyz_data[1] = y;
2485  porterduff_xyz_data[2] = z;
2486 }
2487 
2488 
2490 {
2492 
2493  if (!d->use_fragment_programs && composition_mode > QPainter::CompositionMode_Plus)
2494  composition_mode = QPainter::CompositionMode_SourceOver;
2495 
2496  d->composition_mode = composition_mode;
2497 
2498  d->has_fast_composition_mode = (!d->high_quality_antialiasing && composition_mode <= QPainter::CompositionMode_Plus)
2499  || composition_mode == QPainter::CompositionMode_SourceOver
2500  || composition_mode == QPainter::CompositionMode_Destination
2501  || composition_mode == QPainter::CompositionMode_DestinationOver
2502  || composition_mode == QPainter::CompositionMode_DestinationOut
2503  || composition_mode == QPainter::CompositionMode_SourceAtop
2504  || composition_mode == QPainter::CompositionMode_Xor
2505  || composition_mode == QPainter::CompositionMode_Plus;
2506 
2507  if (d->has_fast_composition_mode)
2508  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODE_BLEND_MODE_MASK : COMPOSITION_MODE_BLEND_MODE_NOMASK;
2509  else if (composition_mode <= QPainter::CompositionMode_Plus)
2510  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_SIMPLE_PORTER_DUFF : COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK;
2511  else
2512  switch (composition_mode) {
2514  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_MULTIPLY : COMPOSITION_MODES_MULTIPLY_NOMASK;
2515  break;
2517  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_SCREEN : COMPOSITION_MODES_SCREEN_NOMASK;
2518  break;
2520  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_OVERLAY : COMPOSITION_MODES_OVERLAY_NOMASK;
2521  break;
2523  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_DARKEN : COMPOSITION_MODES_DARKEN_NOMASK;
2524  break;
2526  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_LIGHTEN : COMPOSITION_MODES_LIGHTEN_NOMASK;
2527  break;
2529  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_COLORDODGE : COMPOSITION_MODES_COLORDODGE_NOMASK;
2530  break;
2532  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_COLORBURN : COMPOSITION_MODES_COLORBURN_NOMASK;
2533  break;
2535  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_HARDLIGHT : COMPOSITION_MODES_HARDLIGHT_NOMASK;
2536  break;
2538  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_SOFTLIGHT : COMPOSITION_MODES_SOFTLIGHT_NOMASK;
2539  break;
2541  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_DIFFERENCE : COMPOSITION_MODES_DIFFERENCE_NOMASK;
2542  break;
2544  d->fragment_composition_mode = d->high_quality_antialiasing ? COMPOSITION_MODES_EXCLUSION : COMPOSITION_MODES_EXCLUSION_NOMASK;
2545  break;
2546  default:
2547  Q_ASSERT(false);
2548  }
2549 
2550  switch(composition_mode) {
2552  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
2553  d->setPorterDuffData(0, 1, 1, 1, 1);
2554  break;
2556  glBlendFunc(GL_ZERO, GL_ZERO);
2557  d->setPorterDuffData(0, 0, 0, 0, 0);
2558  break;
2560  glBlendFunc(GL_ONE, GL_ZERO);
2561  d->setPorterDuffData(1, 0, 1, 1, 0);
2562  break;
2564  glBlendFunc(GL_ZERO, GL_ONE);
2565  d->setPorterDuffData(0, 1, 1, 0, 1);
2566  break;
2568  glBlendFunc(GL_DST_ALPHA, GL_ZERO);
2569  d->setPorterDuffData(1, 0, 1, 0, 0);
2570  break;
2572  glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
2573  d->setPorterDuffData(0, 1, 1, 0, 0);
2574  break;
2576  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);
2577  d->setPorterDuffData(0, 0, 0, 1, 0);
2578  break;
2580  glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
2581  d->setPorterDuffData(0, 0, 0, 0, 1);
2582  break;
2584  glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2585  d->setPorterDuffData(1, 0, 1, 0, 1);
2586  break;
2588  glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);
2589  d->setPorterDuffData(0, 1, 1, 1, 0);
2590  break;
2593  d->setPorterDuffData(0, 0, 0, 1, 1);
2594  break;
2596  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2597  d->setPorterDuffData(1, 0, 1, 1, 1);
2598  break;
2600  glBlendFunc(GL_ONE, GL_ONE);
2601  d->setPorterDuffData(1, 1, 1, 1, 1);
2602  break;
2603  default:
2604  break;
2605  }
2606 }
2607 
2609 {
2610 public:
2611  QGLMaskGenerator(const QPainterPath &path, const QTransform &matrix, qreal stroke_width = -1)
2612  : p(path),
2613  m(matrix),
2614  w(stroke_width)
2615  {
2616  }
2617 
2618  virtual QRect screenRect() = 0;
2619  virtual void drawMask(const QRect &rect) = 0;
2620 
2621  QPainterPath path() const { return p; }
2622  QTransform matrix() const { return m; }
2623  qreal strokeWidth() const { return w; }
2624 
2625  virtual ~QGLMaskGenerator() {}
2626 
2627 private:
2631 };
2632 
2634 {
2635  Q_ASSERT(sz.width() == sz.height());
2636 
2637  if (offscreenSize != sz) {
2638  offscreenSize = sz;
2639  clearCache();
2640  }
2641 }
2642 
2644 {
2645  cache.clear();
2646 
2647  int quad_tree_size = 1;
2648 
2649  for (int i = block_size; i < offscreenSize.width(); i *= 2)
2650  quad_tree_size += quad_tree_size * 4;
2651 
2652  for (int i = 0; i < 4; ++i) {
2653  occupied_quadtree[i].resize(quad_tree_size);
2654 
2655  occupied_quadtree[i][0].key = 0;
2656  occupied_quadtree[i][0].largest_available_block = offscreenSize.width();
2657  occupied_quadtree[i][0].largest_used_block = 0;
2658 
2659  DEBUG_ONCE qDebug() << "QGLMaskTextureCache:: created quad tree of size" << quad_tree_size;
2660  }
2661 }
2662 
2664 {
2665  drawableSize = sz;
2666 }
2667 
2669 {
2670  QGLTextureCacheHash::iterator it = cache.begin();
2671  QGLTextureCacheHash::iterator end = cache.end();
2672 
2673  while (it != end) {
2674  CacheInfo &cache_info = it.value();
2675  ++cache_info.age;
2676 
2677  if (cache_info.age > 1) {
2678  quadtreeInsert(cache_info.loc.channel, 0, cache_info.loc.rect);
2679  it = cache.erase(it);
2680  } else {
2681  ++it;
2682  }
2683  }
2684 }
2685 
2686 //#define DISABLE_MASK_CACHE
2687 
2689 {
2690 #ifndef DISABLE_MASK_CACHE
2691  engine = e;
2692 
2693  quint64 key = hash(maskGenerator.path(), maskGenerator.matrix(), maskGenerator.strokeWidth());
2694 
2695  if (key == 0)
2696  key = 1;
2697 
2698  CacheInfo info(maskGenerator.path(), maskGenerator.matrix(), maskGenerator.strokeWidth());
2699 
2700  QGLTextureCacheHash::iterator it = cache.find(key);
2701 
2702  while (it != cache.end() && it.key() == key) {
2703  CacheInfo &cache_info = it.value();
2704  if (info.stroke_width == cache_info.stroke_width && info.matrix == cache_info.matrix && info.path == cache_info.path) {
2705  DEBUG_ONCE_STR("QGLMaskTextureCache::getMask(): Using cached mask");
2706 
2707  cache_info.age = 0;
2708  return cache_info.loc;
2709  }
2710  ++it;
2711  }
2712 
2713  // mask was not found, create new mask
2714 
2715  DEBUG_ONCE_STR("QGLMaskTextureCache::getMask(): Creating new mask...");
2716 
2717  createMask(key, info, maskGenerator);
2718 
2719  cache.insert(key, info);
2720 
2721  return info.loc;
2722 #else
2723  CacheInfo info(maskGenerator.path(), maskGenerator.matrix());
2724  createMask(0, info, maskGenerator);
2725  return info.loc;
2726 #endif
2727 }
2728 
2729 #ifndef FloatToQuint64
2730 #define FloatToQuint64(i) (quint64)((i) * 32)
2731 #endif
2732 
2734 {
2735  Q_ASSERT(sizeof(quint64) == 8);
2736 
2737  quint64 h = 0;
2738 
2739  for (int i = 0; i < p.elementCount(); ++i) {
2740  h += FloatToQuint64(p.elementAt(i).x) << 32;
2741  h += FloatToQuint64(p.elementAt(i).y);
2742  h += p.elementAt(i).type;
2743  }
2744 
2745  h += FloatToQuint64(m.m11());
2746 #ifndef Q_OS_WINCE // ###
2747  //Compiler crashes for arm on WinCE
2748  h += FloatToQuint64(m.m12()) << 4;
2749  h += FloatToQuint64(m.m13()) << 8;
2750  h += FloatToQuint64(m.m21()) << 12;
2751  h += FloatToQuint64(m.m22()) << 16;
2752  h += FloatToQuint64(m.m23()) << 20;
2753  h += FloatToQuint64(m.m31()) << 24;
2754  h += FloatToQuint64(m.m32()) << 28;
2755 #endif
2756  h += FloatToQuint64(m.m33()) << 32;
2757 
2758  h += FloatToQuint64(w);
2759 
2760  return h;
2761 }
2762 
2764 {
2765  info.loc.screen_rect = maskGenerator.screenRect();
2766 
2767  if (info.loc.screen_rect.isEmpty()) {
2768  info.loc.channel = 0;
2769  info.loc.rect = QRect();
2770  return;
2771  }
2772 
2773  quadtreeAllocate(key, info.loc.screen_rect.size(), &info.loc.rect, &info.loc.channel);
2774 
2775  int ch = info.loc.channel;
2776  glColorMask(ch == 0, ch == 1, ch == 2, ch == 3);
2777 
2778  maskGenerator.drawMask(info.loc.rect);
2779 
2780  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2781 }
2782 
2784 {
2785  DEBUG_ONCE qDebug() << "Offscreen size:" << offscreenSize.width();
2786 
2787  int blocksize = offscreenSize.width();
2788 
2789  while (node) {
2790  node = (node - 1) / 4;
2791  blocksize /= 2;
2792  }
2793 
2794  return blocksize;
2795 }
2796 
2798 {
2799  QPoint location;
2800  int blocksize = quadtreeBlocksize(node);
2801 
2802  while (node) {
2803  --node;
2804 
2805  if (node & 1)
2806  location.setX(location.x() + blocksize);
2807 
2808  if (node & 2)
2809  location.setY(location.y() + blocksize);
2810 
2811  node /= 4;
2812  blocksize *= 2;
2813  }
2814 
2815  return location;
2816 }
2817 
2818 void QGLMaskTextureCache::quadtreeUpdate(int channel, int node, int current_block_size)
2819 {
2820  while (node) {
2821  node = (node - 1) / 4;
2822 
2823  int first_child = node * 4 + 1;
2824 
2825  int largest_available = 0;
2826  int largest_used = 0;
2827 
2828  bool all_empty = true;
2829 
2830  for (int i = 0; i < 4; ++i) {
2831  largest_available = qMax(largest_available, occupied_quadtree[channel][first_child + i].largest_available_block);
2832  largest_used = qMax(largest_used, occupied_quadtree[channel][first_child + i].largest_used_block);
2833 
2834  if (occupied_quadtree[channel][first_child + i].largest_available_block < current_block_size)
2835  all_empty = false;
2836  }
2837 
2838  current_block_size *= 2;
2839 
2840  if (all_empty) {
2841  occupied_quadtree[channel][node].largest_available_block = current_block_size;
2842  occupied_quadtree[channel][node].largest_used_block = 0;
2843  } else {
2844  occupied_quadtree[channel][node].largest_available_block = largest_available;
2845  occupied_quadtree[channel][node].largest_used_block = largest_used;
2846  }
2847  }
2848 }
2849 
2850 void QGLMaskTextureCache::quadtreeInsert(int channel, quint64 key, const QRect &rect, int node)
2851 {
2852  int current_block_size = quadtreeBlocksize(node);
2853  QPoint location = quadtreeLocation(node);
2854  QRect relative = rect.translated(-location);
2855 
2856  if (relative.left() >= current_block_size || relative.top() >= current_block_size
2857  || relative.right() < 0 || relative.bottom() < 0)
2858  return;
2859 
2860  if (current_block_size == block_size // no more refining possible
2861  || (relative.top() < block_size && relative.bottom() >= (current_block_size - block_size)
2862  && relative.left() < block_size && relative.right() >= (current_block_size - block_size)))
2863  {
2864  if (key != 0) {
2865  occupied_quadtree[channel][node].largest_available_block = 0;
2866  occupied_quadtree[channel][node].largest_used_block = rect.width() * rect.height();
2867  } else {
2868  occupied_quadtree[channel][node].largest_available_block = current_block_size;
2869  occupied_quadtree[channel][node].largest_used_block = 0;
2870  }
2871 
2872  occupied_quadtree[channel][node].key = key;
2873 
2874  quadtreeUpdate(channel, node, current_block_size);
2875  } else {
2876  if (key && occupied_quadtree[channel][node].largest_available_block == current_block_size) {
2877  // refining the quad tree, initialize child nodes
2878  int half_block_size = current_block_size / 2;
2879 
2880  int temp = node * 4 + 1;
2881  for (int sibling = 0; sibling < 4; ++sibling) {
2882  occupied_quadtree[channel][temp + sibling].largest_available_block = half_block_size;
2883  occupied_quadtree[channel][temp + sibling].largest_used_block = 0;
2884  occupied_quadtree[channel][temp + sibling].key = 0;
2885  }
2886  }
2887 
2888  node = node * 4 + 1;
2889 
2890  for (int sibling = 0; sibling < 4; ++sibling)
2891  quadtreeInsert(channel, key, rect, node + sibling);
2892  }
2893 }
2894 
2895 void QGLMaskTextureCache::quadtreeClear(int channel, const QRect &rect, int node)
2896 {
2897  const quint64 &key = occupied_quadtree[channel][node].key;
2898 
2899  int current_block_size = quadtreeBlocksize(node);
2900  QPoint location = quadtreeLocation(node);
2901 
2902  QRect relative = rect.translated(-location);
2903 
2904  if (relative.left() >= current_block_size || relative.top() >= current_block_size
2905  || relative.right() < 0 || relative.bottom() < 0)
2906  return;
2907 
2908  if (key != 0) {
2909  QGLTextureCacheHash::iterator it = cache.find(key);
2910 
2911  Q_ASSERT(it != cache.end());
2912 
2913  while (it != cache.end() && it.key() == key) {
2914  const CacheInfo &cache_info = it.value();
2915 
2916  if (cache_info.loc.channel == channel
2917  && cache_info.loc.rect.left() <= location.x()
2918  && cache_info.loc.rect.top() <= location.y()
2919  && cache_info.loc.rect.right() >= location.x()
2920  && cache_info.loc.rect.bottom() >= location.y())
2921  {
2922  quadtreeInsert(channel, 0, cache_info.loc.rect);
2923  engine->cacheItemErased(channel, cache_info.loc.rect);
2924  cache.erase(it);
2925  goto found;
2926  } else {
2927  ++it;
2928  }
2929  }
2930 
2931  // if we don't find the key there's an error in the quadtree
2932  Q_ASSERT(false);
2933 found:
2934  Q_ASSERT(occupied_quadtree[channel][node].key == 0);
2935  } else if (occupied_quadtree[channel][node].largest_available_block < current_block_size) {
2936  Q_ASSERT(current_block_size >= block_size);
2937 
2938  node = node * 4 + 1;
2939 
2940  for (int sibling = 0; sibling < 4; ++sibling)
2941  quadtreeClear(channel, rect, node + sibling);
2942  }
2943 }
2944 
2946 {
2947  int needed_block_size = qMax(1, qMax(size.width(), size.height()));
2948 
2949  for (int i = 0; i < 4; ++i) {
2950  int current_block_size = offscreenSize.width();
2951 
2952  if (occupied_quadtree[i][0].largest_available_block >= needed_block_size) {
2953  int node = 0;
2954 
2955  while (current_block_size != occupied_quadtree[i][node].largest_available_block) {
2956  Q_ASSERT(current_block_size > block_size);
2957  Q_ASSERT(current_block_size > occupied_quadtree[i][node].largest_available_block);
2958 
2959  node = node * 4 + 1;
2960  current_block_size /= 2;
2961 
2962  int sibling = 0;
2963 
2964  while (occupied_quadtree[i][node + sibling].largest_available_block < needed_block_size)
2965  ++sibling;
2966 
2967  Q_ASSERT(sibling < 4);
2968  node += sibling;
2969  }
2970 
2971  *channel = i;
2972  *rect = QRect(quadtreeLocation(node), size);
2973 
2974  return true;
2975  }
2976  }
2977 
2978  return false;
2979 }
2980 
2981 void QGLMaskTextureCache::quadtreeFindExistingLocation(const QSize &size, QRect *rect, int *channel)
2982 {
2983  // try to pick small masks to throw out, as large masks are more expensive to recompute
2984  *channel = qrand() % 4;
2985  for (int i = 0; i < 4; ++i)
2986  if (occupied_quadtree[i][0].largest_used_block < occupied_quadtree[*channel][0].largest_used_block)
2987  *channel = i;
2988 
2989  int needed_block_size = qt_next_power_of_two(qMax(1, qMax(size.width(), size.height())));
2990 
2991  int node = 0;
2992  int current_block_size = offscreenSize.width();
2993 
2994  while (current_block_size > block_size
2995  && current_block_size >= needed_block_size * 2
2996  && occupied_quadtree[*channel][node].key == 0)
2997  {
2998  node = node * 4 + 1;
2999 
3000  int sibling = 0;
3001 
3002  for (int i = 1; i < 4; ++i) {
3003  if (occupied_quadtree[*channel][node + i].largest_used_block
3004  <= occupied_quadtree[*channel][node + sibling].largest_used_block)
3005  {
3006  sibling = i;
3007  }
3008  }
3009 
3010  node += sibling;
3011  current_block_size /= 2;
3012  }
3013 
3014  *rect = QRect(quadtreeLocation(node), size);
3015 }
3016 
3017 void QGLMaskTextureCache::quadtreeAllocate(quint64 key, const QSize &size, QRect *rect, int *channel)
3018 {
3019 #ifndef DISABLE_MASK_CACHE
3020  if (!quadtreeFindAvailableLocation(size, rect, channel)) {
3021  quadtreeFindExistingLocation(size, rect, channel);
3022  quadtreeClear(*channel, *rect);
3023  }
3024 
3025  quadtreeInsert(*channel, key, *rect);
3026 #else
3027  *channel = 0;
3028  *rect = QRect(QPoint(), size);
3029 #endif
3030 }
3031 
3033 {
3034 public:
3035  QGLTrapezoidMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram, qreal strokeWidth = -1.0);
3036 
3037  QRect screenRect();
3038  void drawMask(const QRect &rect);
3039 
3040 private:
3043 
3045 
3047 
3048  virtual QVector<QGLTrapezoid> generateTrapezoids() = 0;
3049  virtual QRect computeScreenRect() = 0;
3050 };
3051 
3053 {
3054 public:
3055  QGLPathMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram);
3056 
3057 private:
3058  QVector<QGLTrapezoid> generateTrapezoids();
3059  QRect computeScreenRect();
3060 
3062 };
3063 
3065 {
3066 public:
3067  QGLLineMaskGenerator(const QPainterPath &path, const QTransform &matrix, qreal width, QGLOffscreen &offscreen, GLuint maskFragmentProgram);
3068 
3069 private:
3070  QVector<QGLTrapezoid> generateTrapezoids();
3071  QRect computeScreenRect();
3072 
3074 };
3075 
3077 {
3078 public:
3079  QGLRectMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram);
3080 
3081 private:
3082  QVector<QGLTrapezoid> generateTrapezoids();
3083  QRect computeScreenRect();
3084 
3086 };
3087 
3089 {
3090 public:
3091  QGLEllipseMaskGenerator(const QRectF &rect, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram, int *maskVariableLocations);
3092 
3093  QRect screenRect();
3094  void drawMask(const QRect &rect);
3095 
3096 private:
3098 
3100 
3102 
3104 
3106 
3107  float vertexArray[4 * 2];
3108 };
3109 
3110 QGLTrapezoidMaskGenerator::QGLTrapezoidMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offs, GLuint program, qreal stroke_width)
3111  : QGLMaskGenerator(path, matrix, stroke_width)
3112  , has_screen_rect(false)
3113  , offscreen(&offs)
3114  , maskFragmentProgram(program)
3115 {
3116 }
3117 
3118 extern void qt_add_rect_to_array(const QRectF &r, GLfloat *array);
3119 extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, GLfloat *array);
3120 
3122 {
3123 #ifdef QT_OPENGL_ES
3124  Q_UNUSED(rect);
3125 #else
3126  glMatrixMode(GL_MODELVIEW);
3127  glPushMatrix();
3128  glLoadIdentity();
3129 
3130  QGLContext *ctx = offscreen->context();
3131  offscreen->bind();
3132 
3133  glDisable(GL_TEXTURE_GEN_S);
3134  glDisable(GL_TEXTURE_1D);
3135 
3136  GLfloat vertexArray[4 * 2];
3137  qt_add_rect_to_array(rect, vertexArray);
3138 
3139  bool needs_scissor = rect != screen_rect;
3140 
3141  if (needs_scissor) {
3142  glEnable(GL_SCISSOR_TEST);
3143  glScissor(rect.left(), offscreen->offscreenSize().height() - rect.bottom() - 1, rect.width(), rect.height());
3144  }
3145 
3147 
3148  // clear mask
3149  glBlendFunc(GL_ZERO, GL_ZERO); // clear
3150  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
3151  glEnableClientState(GL_VERTEX_ARRAY);
3152  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3153  glDisableClientState(GL_VERTEX_ARRAY);
3154 
3155  glBlendFunc(GL_ONE, GL_ONE); // add mask
3156  glEnable(GL_FRAGMENT_PROGRAM_ARB);
3158 
3159  QPoint delta = rect.topLeft() - screen_rect.topLeft();
3160  glBegin(GL_QUADS);
3161  for (int i = 0; i < trapezoids.size(); ++i)
3162  drawTrapezoid(trapezoids[i].translated(delta), offscreen->offscreenSize().height(), ctx);
3163  glEnd();
3164 
3165  if (needs_scissor)
3166  glDisable(GL_SCISSOR_TEST);
3167 
3168  glDisable(GL_FRAGMENT_PROGRAM_ARB);
3169 
3170  glMatrixMode(GL_MODELVIEW);
3171  glPopMatrix();
3172 #endif
3173 }
3174 
3176 {
3177  if (!has_screen_rect) {
3179  has_screen_rect = true;
3180  }
3181 
3183 
3184  return screen_rect;
3185 }
3186 
3187 QGLPathMaskGenerator::QGLPathMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offs, GLuint program)
3188  : QGLTrapezoidMaskGenerator(path, matrix, offs, program)
3189 {
3190 }
3191 
3193 {
3194  poly = path().toFillPolygon(matrix());
3195  return poly.boundingRect().toAlignedRect();
3196 }
3197 
3199 {
3200  QOpenGLImmediateModeTessellator tessellator;
3201  tessellator.tessellate(poly.data(), poly.count(), path().fillRule() == Qt::WindingFill);
3202  return tessellator.trapezoids;
3203 }
3204 
3205 QGLRectMaskGenerator::QGLRectMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offs, GLuint program)
3206  : QGLTrapezoidMaskGenerator(path, matrix, offs, program)
3207 {
3208 }
3209 
3210 QGLLineMaskGenerator::QGLLineMaskGenerator(const QPainterPath &path, const QTransform &matrix, qreal width, QGLOffscreen &offs, GLuint program)
3211  : QGLTrapezoidMaskGenerator(path, matrix, offs, program, width)
3212 {
3213 }
3214 
3216 {
3217  transformedPath = matrix().map(path());
3218 
3219  return transformedPath.controlPointRect().adjusted(-1, -1, 1, 1).toAlignedRect();
3220 }
3221 
3223 {
3224  transformedPath = matrix().map(path());
3225 
3226  return transformedPath.controlPointRect().adjusted(-1, -1, 1, 1).toAlignedRect();
3227 }
3228 
3230 {
3231  QOpenGLImmediateModeTessellator tessellator;
3232  QPointF last;
3233  for (int i = 0; i < transformedPath.elementCount(); ++i) {
3235 
3236  Q_ASSERT(!element.isCurveTo());
3237 
3238  if (element.isLineTo())
3239  tessellator.tessellateRect(last, element, strokeWidth());
3240 
3241  last = element;
3242  }
3243 
3244  return tessellator.trapezoids;
3245 }
3246 
3248 {
3250 
3251  QOpenGLImmediateModeTessellator tessellator;
3252  if (matrix().type() <= QTransform::TxScale) {
3257 
3258  QPointF first = (a + d) * 0.5;
3259  QPointF last = (b + c) * 0.5;
3260 
3261  QPointF delta = a - d;
3262 
3263  // manhattan distance (no rotation)
3264  qreal width = qAbs(delta.x()) + qAbs(delta.y());
3265 
3266  Q_ASSERT(qFuzzyIsNull(delta.x()) || qFuzzyIsNull(delta.y()));
3267 
3268  tessellator.tessellateRect(first, last, width);
3269  } else {
3270  QPointF points[5];
3271 
3272  for (int i = 0; i < 5; ++i)
3273  points[i] = transformedPath.elementAt(i);
3274 
3275  tessellator.tessellateConvex(points, 5);
3276  }
3277  return tessellator.trapezoids;
3278 }
3279 
3281 {
3283  path.addEllipse(rect);
3284  return path;
3285 }
3286 
3287 QGLEllipseMaskGenerator::QGLEllipseMaskGenerator(const QRectF &rect, const QTransform &matrix, QGLOffscreen &offs, GLuint program, int *locations)
3288  : QGLMaskGenerator(ellipseRectToPath(rect), matrix),
3289  ellipseRect(rect),
3290  offscreen(&offs),
3291  maskFragmentProgram(program),
3292  maskVariableLocations(locations)
3293 {
3294 }
3295 
3297 {
3299 
3300  QPointF points[] = {
3301  QPointF(ellipseRect.left(), center.y()),
3302  QPointF(ellipseRect.right(), center.y()),
3303  QPointF(center.x(), ellipseRect.top()),
3304  QPointF(center.x(), ellipseRect.bottom())
3305  };
3306 
3307  qreal min_screen_delta_len = QREAL_MAX;
3308 
3309  for (int i = 0; i < 4; ++i) {
3310  QPointF delta = points[i] - center;
3311 
3312  // normalize
3313  delta /= qSqrt(delta.x() * delta.x() + delta.y() * delta.y());
3314 
3315  QPointF screen_delta(matrix().m11() * delta.x() + matrix().m21() * delta.y(),
3316  matrix().m12() * delta.x() + matrix().m22() * delta.y());
3317 
3318  min_screen_delta_len = qMin(min_screen_delta_len,
3319  qreal(qSqrt(screen_delta.x() * screen_delta.x() + screen_delta.y() * screen_delta.y())));
3320  }
3321 
3322  const qreal padding = 2.0f;
3323 
3324  qreal grow = padding / min_screen_delta_len;
3325 
3326  QRectF boundingRect = ellipseRect.adjusted(-grow, -grow, grow, grow);
3327 
3328  boundingRect = matrix().mapRect(boundingRect);
3329 
3330  QPointF p(0.5, 0.5);
3331 
3332  screen_rect = QRect((boundingRect.topLeft() - p).toPoint(),
3333  (boundingRect.bottomRight() + p).toPoint());
3334 
3335  return screen_rect;
3336 }
3337 
3339 {
3340 #ifdef QT_OPENGL_ES
3341  Q_UNUSED(rect);
3342 #else
3343  QGLContext *ctx = offscreen->context();
3344  offscreen->bind();
3345 
3346  glDisable(GL_TEXTURE_GEN_S);
3347  glDisable(GL_TEXTURE_1D);
3348 
3349  // fragment program needs the inverse radii of the ellipse
3350  glTexCoord2f(1.0f / (ellipseRect.width() * 0.5f),
3351  1.0f / (ellipseRect.height() * 0.5f));
3352 
3353  QTransform translate(1, 0, 0, 1, -ellipseRect.center().x(), -ellipseRect.center().y());
3354  QTransform gl_to_qt(1, 0, 0, -1, 0, offscreen->drawableSize().height());
3355  QTransform inv_matrix = gl_to_qt * matrix().inverted() * translate;
3356 
3357  float m[3][4] = { { float(inv_matrix.m11()), float(inv_matrix.m12()), float(inv_matrix.m13()) },
3358  { float(inv_matrix.m21()), float(inv_matrix.m22()), float(inv_matrix.m23()) },
3359  { float(inv_matrix.m31()), float(inv_matrix.m32()), float(inv_matrix.m33()) } };
3360 
3361  QPoint offs(screen_rect.left() - rect.left(), (offscreen->drawableSize().height() - screen_rect.top())
3362  - (offscreen->offscreenSize().height() - rect.top()));
3363 
3364  // last component needs to be 1.0f to avoid Nvidia bug on linux
3365  float ellipse_offset[4] = { float(offs.x()), float(offs.y()), 0.0f, 1.0f };
3366 
3367  GLfloat vertexArray[4 * 2];
3368  qt_add_rect_to_array(rect, vertexArray);
3369 
3370  glBlendFunc(GL_ONE, GL_ZERO); // set mask
3371  glEnable(GL_FRAGMENT_PROGRAM_ARB);
3373 
3377 
3379 
3380  glEnableClientState(GL_VERTEX_ARRAY);
3381  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
3382  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3383  glDisableClientState(GL_VERTEX_ARRAY);
3384  glDisable(GL_FRAGMENT_PROGRAM_ARB);
3385 #endif
3386 }
3387 
3389 {
3390 #ifdef Q_WS_QWS
3391  Q_UNUSED(path);
3392 #else
3393  DEBUG_ONCE_STR("QOpenGLPaintEnginePrivate::drawOffscreenPath()");
3394 
3395  disableClipping();
3396 
3397  GLuint program = qt_gl_program_cache()->getProgram(device->context(),
3399  QGLPathMaskGenerator maskGenerator(path, matrix, offscreen, program);
3400  addItem(qt_mask_texture_cache()->getMask(maskGenerator, this));
3401 
3402  enableClipping();
3403 #endif
3404 }
3405 
3407 {
3409  DEBUG_ONCE_STR("QOpenGLPaintEngine::drawRects(): drawing fast rect");
3410 
3411  GLfloat vertexArray[10];
3412  qt_add_rect_to_array(r, vertexArray);
3413 
3414  if (has_pen)
3416 
3417  if (has_brush) {
3418  flushDrawQueue();
3419 
3420  bool temp = high_quality_antialiasing;
3421  high_quality_antialiasing = false;
3422 
3423  q->updateCompositionMode(composition_mode);
3424 
3425  setGradientOps(cbrush, r);
3426 
3427  bool fast_style = current_style == Qt::LinearGradientPattern
3428  || current_style == Qt::SolidPattern;
3429 
3430  if (fast_style && has_fast_composition_mode) {
3431  glEnableClientState(GL_VERTEX_ARRAY);
3432  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
3433  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
3434  glDisableClientState(GL_VERTEX_ARRAY);
3435  } else {
3436  composite(r);
3437  }
3438 
3439  high_quality_antialiasing = temp;
3440 
3441  q->updateCompositionMode(composition_mode);
3442  }
3443 
3444  if (has_pen) {
3445  if (has_fast_pen && !high_quality_antialiasing) {
3446  setGradientOps(cpen.brush(), r);
3447 
3448  vertexArray[8] = vertexArray[0];
3449  vertexArray[9] = vertexArray[1];
3450 
3451  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
3452  glEnableClientState(GL_VERTEX_ARRAY);
3453  glDrawArrays(GL_LINE_STRIP, 0, 5);
3454  glDisableClientState(GL_VERTEX_ARRAY);
3455  } else {
3458 
3459  qreal left = r.left();
3460  qreal right = r.right();
3461  qreal top = r.top();
3462  qreal bottom = r.bottom();
3463 
3464  path.moveTo(left, top);
3465  path.lineTo(right, top);
3466  path.lineTo(right, bottom);
3467  path.lineTo(left, bottom);
3468  path.lineTo(left, top);
3469 
3470  strokePath(path, false);
3471  }
3472 
3474  }
3475 }
3476 
3478 {
3479  if (matrix.type() < QTransform::TxRotate) {
3480  QRectF r = matrix.mapRect(rect);
3481  return r.topLeft().toPoint() == r.topLeft()
3482  && r.bottomRight().toPoint() == r.bottomRight();
3483  }
3484 
3485  return false;
3486 }
3487 
3488 void QOpenGLPaintEngine::drawRects(const QRect *rects, int rectCount)
3489 {
3490  struct RectF {
3491  qreal x;
3492  qreal y;
3493  qreal w;
3494  qreal h;
3495  };
3496  Q_ASSERT(sizeof(RectF) == sizeof(QRectF));
3497  RectF fr[256];
3498  while (rectCount) {
3499  int i = 0;
3500  while (i < rectCount && i < 256) {
3501  fr[i].x = rects[i].x();
3502  fr[i].y = rects[i].y();
3503  fr[i].w = rects[i].width();
3504  fr[i].h = rects[i].height();
3505  ++i;
3506  }
3507  drawRects((QRectF *)(void *)fr, i);
3508  rects += i;
3509  rectCount -= i;
3510  }
3511 }
3512 
3513 void QOpenGLPaintEngine::drawRects(const QRectF *rects, int rectCount)
3514 {
3516 
3517  if (d->use_emulation) {
3518  QPaintEngineEx::drawRects(rects, rectCount);
3519  return;
3520  }
3521 
3522  for (int i=0; i<rectCount; ++i) {
3523  const QRectF &r = rects[i];
3524 
3525  // optimization for rects which can be drawn aliased
3526  if (!d->high_quality_antialiasing || d->isFastRect(r)) {
3527  d->drawFastRect(r);
3528  } else {
3530  path.addRect(r);
3531 
3532  if (d->has_brush) {
3533  d->disableClipping();
3534  GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
3536 
3537  if (d->matrix.type() >= QTransform::TxProject) {
3538  QGLPathMaskGenerator maskGenerator(path, d->matrix, d->offscreen, program);
3539  d->addItem(qt_mask_texture_cache()->getMask(maskGenerator, d));
3540  } else {
3541  QGLRectMaskGenerator maskGenerator(path, d->matrix, d->offscreen, program);
3542  d->addItem(qt_mask_texture_cache()->getMask(maskGenerator, d));
3543  }
3544 
3545  d->enableClipping();
3546  }
3547 
3548  if (d->has_pen) {
3549  if (d->has_fast_pen)
3550  d->strokeLines(path);
3551  else
3552  d->strokePath(path, false);
3553  }
3554  }
3555  }
3556 }
3557 
3558 static void addQuadAsTriangle(GLfloat *quad, GLfloat *triangle)
3559 {
3560  triangle[0] = quad[0];
3561  triangle[1] = quad[1];
3562 
3563  triangle[2] = quad[2];
3564  triangle[3] = quad[3];
3565 
3566  triangle[4] = quad[4];
3567  triangle[5] = quad[5];
3568 
3569  triangle[6] = quad[4];
3570  triangle[7] = quad[5];
3571 
3572  triangle[8] = quad[6];
3573  triangle[9] = quad[7];
3574 
3575  triangle[10] = quad[0];
3576  triangle[11] = quad[1];
3577 }
3578 
3579 void QOpenGLPaintEngine::drawPoints(const QPoint *points, int pointCount)
3580 {
3581  Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
3582  QT_PointF fp[256];
3583  while (pointCount) {
3584  int i = 0;
3585  while (i < pointCount && i < 256) {
3586  fp[i].x = points[i].x();
3587  fp[i].y = points[i].y();
3588  ++i;
3589  }
3590  drawPoints((QPointF *)(void *)fp, i);
3591  points += i;
3592  pointCount -= i;
3593  }
3594 }
3595 
3596 void QOpenGLPaintEngine::drawPoints(const QPointF *points, int pointCount)
3597 {
3599 
3600  if (d->use_emulation) {
3601  QPaintEngineEx::drawPoints(points, pointCount);
3602  return;
3603  }
3604 
3605  d->setGradientOps(d->cpen.brush(), QRectF());
3606 
3607  if (!d->cpen.isCosmetic() || d->high_quality_antialiasing) {
3608  Qt::PenCapStyle capStyle = d->cpen.capStyle();
3609  if (capStyle == Qt::FlatCap)
3610  d->cpen.setCapStyle(Qt::SquareCap);
3611  QPaintEngine::drawPoints(points, pointCount);
3612  d->cpen.setCapStyle(capStyle);
3613  return;
3614  }
3615 
3616  d->flushDrawQueue();
3617 
3618  if (d->has_fast_pen) {
3619  QVarLengthArray<GLfloat> vertexArray(6 * pointCount);
3620 
3621  glMatrixMode(GL_MODELVIEW);
3622  glPushMatrix();
3623  glLoadIdentity();
3624 
3625  int j = 0;
3626  for (int i = 0; i < pointCount; ++i) {
3627  QPointF mapped = d->matrix.map(points[i]);
3628 
3629  GLfloat x = GLfloat(qRound(mapped.x()));
3630  GLfloat y = GLfloat(qRound(mapped.y()));
3631 
3632  vertexArray[j++] = x;
3633  vertexArray[j++] = y - 0.5f;
3634 
3635  vertexArray[j++] = x + 1.5f;
3636  vertexArray[j++] = y + 1.0f;
3637 
3638  vertexArray[j++] = x;
3639  vertexArray[j++] = y + 1.0f;
3640  }
3641 
3642  glEnableClientState(GL_VERTEX_ARRAY);
3643 
3644  glVertexPointer(2, GL_FLOAT, 0, vertexArray.constData());
3645  glDrawArrays(GL_TRIANGLES, 0, pointCount*3);
3646 
3647  glDisableClientState(GL_VERTEX_ARRAY);
3648 
3649  glPopMatrix();
3650  return;
3651  }
3652 
3653  const qreal *vertexArray = reinterpret_cast<const qreal*>(&points[0]);
3654 
3655  if (sizeof(qreal) == sizeof(double)) {
3656  Q_ASSERT(sizeof(QPointF) == 16);
3657  glVertexPointer(2, GL_DOUBLE, 0, vertexArray);
3658  }
3659  else {
3660  Q_ASSERT(sizeof(QPointF) == 8);
3661  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
3662  }
3663 
3664  glEnableClientState(GL_VERTEX_ARRAY);
3665  glDrawArrays(GL_POINTS, 0, pointCount);
3666  glDisableClientState(GL_VERTEX_ARRAY);
3667 }
3668 
3669 void QOpenGLPaintEngine::drawLines(const QLine *lines, int lineCount)
3670 {
3671  struct PointF {
3672  qreal x;
3673  qreal y;
3674  };
3675  struct LineF {
3676  PointF p1;
3677  PointF p2;
3678  };
3679  Q_ASSERT(sizeof(PointF) == sizeof(QPointF));
3680  Q_ASSERT(sizeof(LineF) == sizeof(QLineF));
3681  LineF fl[256];
3682  while (lineCount) {
3683  int i = 0;
3684  while (i < lineCount && i < 256) {
3685  fl[i].p1.x = lines[i].x1();
3686  fl[i].p1.y = lines[i].y1();
3687  fl[i].p2.x = lines[i].x2();
3688  fl[i].p2.y = lines[i].y2();
3689  ++i;
3690  }
3691  drawLines((QLineF *)(void *)fl, i);
3692  lines += i;
3693  lineCount -= i;
3694  }
3695 }
3696 
3697 void QOpenGLPaintEngine::drawLines(const QLineF *lines, int lineCount)
3698 {
3700 
3701  if (d->use_emulation) {
3702  QPaintEngineEx::drawLines(lines, lineCount);
3703  return;
3704  }
3705 
3706  if (d->has_pen) {
3707  QOpenGLCoordinateOffset offset(d);
3708  if (d->has_fast_pen && !d->high_quality_antialiasing) {
3709  //### gradient resolving on lines isn't correct
3710  d->setGradientOps(d->cpen.brush(), QRectF());
3711 
3712  bool useRects = false;
3713  // scale or 90 degree rotation?
3714  if (d->matrix.type() <= QTransform::TxTranslate
3715  || (!d->cpen.isCosmetic()
3716  && (d->matrix.type() <= QTransform::TxScale
3717  || (d->matrix.type() == QTransform::TxRotate
3718  && d->matrix.m11() == 0 && d->matrix.m22() == 0)))) {
3719  useRects = true;
3720  for (int i = 0; i < lineCount; ++i) {
3721  if (lines[i].p1().x() != lines[i].p2().x()
3722  && lines[i].p1().y() != lines[i].p2().y()) {
3723  useRects = false;
3724  break;
3725  }
3726  }
3727  }
3728 
3729  GLfloat endCap = d->cpen.capStyle() == Qt::FlatCap ? 0.0f : 0.5f;
3730  if (useRects) {
3731  QVarLengthArray<GLfloat> vertexArray(12 * lineCount);
3732 
3733  GLfloat quad[8];
3734  for (int i = 0; i < lineCount; ++i) {
3735  GLfloat x1 = lines[i].x1();
3736  GLfloat x2 = lines[i].x2();
3737  GLfloat y1 = lines[i].y1();
3738  GLfloat y2 = lines[i].y2();
3739 
3740  if (x1 == x2) {
3741  if (y1 > y2)
3742  qSwap(y1, y2);
3743 
3744  quad[0] = x1 - 0.5f;
3745  quad[1] = y1 - endCap;
3746 
3747  quad[2] = x1 + 0.5f;
3748  quad[3] = y1 - endCap;
3749 
3750  quad[4] = x1 + 0.5f;
3751  quad[5] = y2 + endCap;
3752 
3753  quad[6] = x1 - 0.5f;
3754  quad[7] = y2 + endCap;
3755  } else {
3756  if (x1 > x2)
3757  qSwap(x1, x2);
3758 
3759  quad[0] = x1 - endCap;
3760  quad[1] = y1 + 0.5f;
3761 
3762  quad[2] = x1 - endCap;
3763  quad[3] = y1 - 0.5f;
3764 
3765  quad[4] = x2 + endCap;
3766  quad[5] = y1 - 0.5f;
3767 
3768  quad[6] = x2 + endCap;
3769  quad[7] = y1 + 0.5f;
3770  }
3771 
3772  addQuadAsTriangle(quad, &vertexArray[12*i]);
3773  }
3774 
3775  glEnableClientState(GL_VERTEX_ARRAY);
3776 
3777  glVertexPointer(2, GL_FLOAT, 0, vertexArray.constData());
3778  glDrawArrays(GL_TRIANGLES, 0, lineCount*6);
3779 
3780  glDisableClientState(GL_VERTEX_ARRAY);
3781  } else {
3782  QVarLengthArray<GLfloat> vertexArray(4 * lineCount);
3783  for (int i = 0; i < lineCount; ++i) {
3784  vertexArray[4*i] = lines[i].x1();
3785  vertexArray[4*i+1] = lines[i].y1();
3786  vertexArray[4*i+2] = lines[i].x2();
3787  vertexArray[4*i+3] = lines[i].y2();
3788  }
3789 
3790  glEnableClientState(GL_VERTEX_ARRAY);
3791 
3792  glVertexPointer(2, GL_FLOAT, 0, vertexArray.constData());
3793  glDrawArrays(GL_LINES, 0, lineCount*2);
3794 
3795  glVertexPointer(2, GL_FLOAT, 4*sizeof(GLfloat), vertexArray.constData() + 2);
3796  glDrawArrays(GL_POINTS, 0, lineCount);
3797 
3798  glDisableClientState(GL_VERTEX_ARRAY);
3799  }
3800  } else {
3803  for (int i=0; i<lineCount; ++i) {
3804  const QLineF &l = lines[i];
3805 
3806  if (l.p1() == l.p2()) {
3807  if (d->cpen.capStyle() != Qt::FlatCap) {
3808  QPointF p = l.p1();
3809  drawPoints(&p, 1);
3810  }
3811  continue;
3812  }
3813 
3814  path.moveTo(l.x1(), l.y1());
3815  path.lineTo(l.x2(), l.y2());
3816  }
3817 
3818  if (d->has_fast_pen && d->high_quality_antialiasing)
3819  d->strokeLines(path);
3820  else
3821  d->strokePath(path, false);
3822  }
3823  }
3824 }
3825 
3826 void QOpenGLPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
3827 {
3828  Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
3829  QVarLengthArray<QT_PointF> p(pointCount);
3830  for (int i=0; i<pointCount; ++i) {
3831  p[i].x = points[i].x();
3832  p[i].y = points[i].y();
3833  }
3834  drawPolygon((QPointF *)p.data(), pointCount, mode);
3835 }
3836 
3837 void QOpenGLPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
3838 {
3840  if(pointCount < 2)
3841  return;
3842 
3843  if (d->use_emulation) {
3844  QPaintEngineEx::drawPolygon(points, pointCount, mode);
3845  return;
3846  }
3847 
3848  QRectF bounds;
3849  if ((mode == ConvexMode && !d->high_quality_antialiasing && state()->brushNeedsResolving()) ||
3850  ((d->has_fast_pen && !d->high_quality_antialiasing) && state()->penNeedsResolving())) {
3851  qreal minx = points[0].x(), miny = points[0].y(),
3852  maxx = points[0].x(), maxy = points[0].y();
3853  for (int i = 1; i < pointCount; ++i) {
3854  const QPointF &pt = points[i];
3855  if (minx > pt.x())
3856  minx = pt.x();
3857  if (miny > pt.y())
3858  miny = pt.y();
3859  if (maxx < pt.x())
3860  maxx = pt.x();
3861  if (maxy < pt.y())
3862  maxy = pt.y();
3863  }
3864  bounds = QRectF(minx, maxx, maxx-minx, maxy-miny);
3865  }
3866 
3867  QOpenGLCoordinateOffset offset(d);
3868 
3869  if (d->has_brush && mode != PolylineMode) {
3870  if (mode == ConvexMode && !d->high_quality_antialiasing) {
3871  //### resolving on polygon from points isn't correct
3872  d->setGradientOps(d->cbrush, bounds);
3873 
3874  const qreal *vertexArray = reinterpret_cast<const qreal*>(&points[0]);
3875 
3876  if (sizeof(qreal) == sizeof(double)) {
3877  Q_ASSERT(sizeof(QPointF) == 16);
3878  glVertexPointer(2, GL_DOUBLE, 0, vertexArray);
3879  }
3880  else {
3881  Q_ASSERT(sizeof(QPointF) == 8);
3882  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
3883  }
3884 
3885  glEnableClientState(GL_VERTEX_ARRAY);
3886  glDrawArrays(GL_TRIANGLE_FAN, 0, pointCount);
3887  glDisableClientState(GL_VERTEX_ARRAY);
3888  } else {
3890  path.setFillRule(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
3891  path.moveTo(points[0]);
3892  for (int i=1; i<pointCount; ++i)
3893  path.lineTo(points[i]);
3894  d->fillPath(path);
3895  }
3896  }
3897 
3898  if (d->has_pen) {
3899  if (d->has_fast_pen && !d->high_quality_antialiasing) {
3900  d->setGradientOps(d->cpen.brush(), bounds);
3901  QVarLengthArray<GLfloat> vertexArray(pointCount*2 + 2);
3902  glVertexPointer(2, GL_FLOAT, 0, vertexArray.constData());
3903  int i;
3904  for (i=0; i<pointCount; ++i) {
3905  vertexArray[i*2] = points[i].x();
3906  vertexArray[i*2+1] = points[i].y();
3907  }
3908 
3909  glEnableClientState(GL_VERTEX_ARRAY);
3910  if (mode != PolylineMode) {
3911  vertexArray[i*2] = vertexArray[0];
3912  vertexArray[i*2+1] = vertexArray[1];
3913  glDrawArrays(GL_LINE_STRIP, 0, pointCount+1);
3914  } else {
3915  glDrawArrays(GL_LINE_STRIP, 0, pointCount);
3916  glDrawArrays(GL_POINTS, pointCount-1, 1);
3917  }
3918  glDisableClientState(GL_VERTEX_ARRAY);
3919  } else {
3920  QPainterPath path(points[0]);
3921  for (int i = 1; i < pointCount; ++i)
3922  path.lineTo(points[i]);
3923  if (mode != PolylineMode)
3924  path.lineTo(points[0]);
3925 
3926  if (d->has_fast_pen)
3927  d->strokeLines(path);
3928  else
3929  d->strokePath(path, true);
3930  }
3931  }
3932 }
3933 
3935 {
3936  DEBUG_ONCE_STR("QOpenGLPaintEnginePrivate::strokeLines()");
3937 
3938  qreal penWidth = cpen.widthF();
3939 
3940  GLuint program = qt_gl_program_cache()->getProgram(device->context(),
3942  QGLLineMaskGenerator maskGenerator(path, matrix, penWidth == 0 ? 1.0 : penWidth,
3943  offscreen, program);
3944 
3945  disableClipping();
3946 
3947  QBrush temp = cbrush;
3948  QPointF origin = brush_origin;
3949 
3950  cbrush = cpen.brush();
3951  brush_origin = QPointF();
3952 
3953  addItem(qt_mask_texture_cache()->getMask(maskGenerator, this));
3954 
3955  cbrush = temp;
3956  brush_origin = origin;
3957 
3958  enableClipping();
3959 }
3960 
3961 Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
3962 
3963 void QOpenGLPaintEnginePrivate::strokePath(const QPainterPath &path, bool use_cache)
3964 {
3965  QBrush old_brush = cbrush;
3966  cbrush = cpen.brush();
3967 
3968  qreal txscale = 1;
3969  if (cpen.isCosmetic() || (qt_scaleForTransform(matrix, &txscale) && txscale != 1)) {
3970  QTransform temp = matrix;
3971  matrix = QTransform();
3972  glPushMatrix();
3973 
3974  if (has_antialiasing) {
3975  glLoadIdentity();
3976  } else {
3977  float offs_matrix[] =
3978  { 1, 0, 0, 0,
3979  0, 1, 0, 0,
3980  0, 0, 1, 0,
3981  0.5, 0.5, 0, 1 };
3982  glLoadMatrixf(offs_matrix);
3983  }
3984 
3985  QPen pen = cpen;
3986  if (txscale != 1)
3987  pen.setWidthF(pen.widthF() * txscale);
3988  if (use_cache)
3989  fillPath(qt_opengl_stroke_cache()->getStrokedPath(temp.map(path), pen));
3990  else
3991  fillPath(strokeForPath(temp.map(path), pen));
3992 
3993  glPopMatrix();
3994  matrix = temp;
3995  } else if (use_cache) {
3996  fillPath(qt_opengl_stroke_cache()->getStrokedPath(path, cpen));
3997  } else {
3998  fillPath(strokeForPath(path, cpen));
3999  }
4000 
4001  cbrush = old_brush;
4002 }
4003 
4004 void QOpenGLPaintEnginePrivate::strokePathFastPen(const QPainterPath &path, bool needsResolving)
4005 {
4006 #ifndef QT_OPENGL_ES
4007  QRectF bounds;
4008  if (needsResolving)
4009  bounds = path.controlPointRect();
4010  setGradientOps(cpen.brush(), bounds);
4011 
4012  QBezier beziers[32];
4013  for (int i=0; i<path.elementCount(); ++i) {
4014  const QPainterPath::Element &e = path.elementAt(i);
4015  switch (e.type) {
4017  if (i != 0)
4018  glEnd(); // GL_LINE_STRIP
4019  glBegin(GL_LINE_STRIP);
4020  glVertex2d(e.x, e.y);
4021 
4022  break;
4024  glVertex2d(e.x, e.y);
4025  break;
4026 
4028  {
4029  QPointF sp = path.elementAt(i-1);
4030  QPointF cp2 = path.elementAt(i+1);
4031  QPointF ep = path.elementAt(i+2);
4032  i+=2;
4033 
4034  qreal inverseScaleHalf = inverseScale / 2;
4035  beziers[0] = QBezier::fromPoints(sp, e, cp2, ep);
4036  QBezier *b = beziers;
4037  while (b >= beziers) {
4038  // check if we can pop the top bezier curve from the stack
4039  qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1);
4040  qreal d;
4041  if (l > inverseScale) {
4042  d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2)
4043  - (b->y4 - b->y1)*(b->x1 - b->x2) )
4044  + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3)
4045  - (b->y4 - b->y1)*(b->x1 - b->x3) );
4046  d /= l;
4047  } else {
4048  d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) +
4049  qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
4050  }
4051  if (d < inverseScaleHalf || b == beziers + 31) {
4052  // good enough, we pop it off and add the endpoint
4053  glVertex2d(b->x4, b->y4);
4054  --b;
4055  } else {
4056  // split, second half of the polygon goes lower into the stack
4057  b->split(b+1, b);
4058  ++b;
4059  }
4060  }
4061  } // case CurveToElement
4062  default:
4063  break;
4064  } // end of switch
4065  }
4066  glEnd(); // GL_LINE_STRIP
4067 #else
4068  // have to use vertex arrays on embedded
4069  QRectF bounds;
4070  if (needsResolving)
4071  bounds = path.controlPointRect();
4072  setGradientOps(cpen.brush(), bounds);
4073 
4074  glEnableClientState(GL_VERTEX_ARRAY);
4075  tess_points.reset();
4076  QBezier beziers[32];
4077  for (int i=0; i<path.elementCount(); ++i) {
4078  const QPainterPath::Element &e = path.elementAt(i);
4079  switch (e.type) {
4081  if (i != 0) {
4082  glVertexPointer(2, GL_FLOAT, 0, tess_points.data());
4083  glDrawArrays(GL_LINE_STRIP, 0, tess_points.size());
4084  tess_points.reset();
4085  }
4086  tess_points.add(QPointF(e.x, e.y));
4087 
4088  break;
4090  tess_points.add(QPointF(e.x, e.y));
4091  break;
4092 
4094  {
4095  QPointF sp = path.elementAt(i-1);
4096  QPointF cp2 = path.elementAt(i+1);
4097  QPointF ep = path.elementAt(i+2);
4098  i+=2;
4099 
4100  qreal inverseScaleHalf = inverseScale / 2;
4101  beziers[0] = QBezier::fromPoints(sp, e, cp2, ep);
4102  QBezier *b = beziers;
4103  while (b >= beziers) {
4104  // check if we can pop the top bezier curve from the stack
4105  qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1);
4106  qreal d;
4107  if (l > inverseScale) {
4108  d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2)
4109  - (b->y4 - b->y1)*(b->x1 - b->x2) )
4110  + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3)
4111  - (b->y4 - b->y1)*(b->x1 - b->x3) );
4112  d /= l;
4113  } else {
4114  d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) +
4115  qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
4116  }
4117  if (d < inverseScaleHalf || b == beziers + 31) {
4118  // good enough, we pop it off and add the endpoint
4119  tess_points.add(QPointF(b->x4, b->y4));
4120  --b;
4121  } else {
4122  // split, second half of the polygon goes lower into the stack
4123  b->split(b+1, b);
4124  ++b;
4125  }
4126  }
4127  } // case CurveToElement
4128  default:
4129  break;
4130  } // end of switch
4131  }
4132  glVertexPointer(2, GL_FLOAT, 0, tess_points.data());
4133  glDrawArrays(GL_LINE_STRIP, 0, tess_points.size());
4134  glDisableClientState(GL_VERTEX_ARRAY);
4135 #endif
4136 }
4137 
4138 static bool pathClosed(const QPainterPath &path)
4139 {
4140  QPointF lastMoveTo = path.elementAt(0);
4141  QPointF lastPoint = lastMoveTo;
4142 
4143  for (int i = 1; i < path.elementCount(); ++i) {
4144  const QPainterPath::Element &e = path.elementAt(i);
4145  switch (e.type) {
4147  if (lastMoveTo != lastPoint)
4148  return false;
4149  lastMoveTo = lastPoint = e;
4150  break;
4152  lastPoint = e;
4153  break;
4155  lastPoint = path.elementAt(i + 2);
4156  i+=2;
4157  break;
4158  default:
4159  break;
4160  }
4161  }
4162 
4163  return lastMoveTo == lastPoint;
4164 }
4165 
4167 {
4169 
4170  if (path.isEmpty())
4171  return;
4172 
4173  if (d->use_emulation) {
4175  return;
4176  }
4177 
4178  QOpenGLCoordinateOffset offset(d);
4179 
4180  if (d->has_brush) {
4181  bool path_closed = pathClosed(path);
4182 
4183  bool has_thick_pen =
4184  path_closed
4185  && d->has_pen
4186  && d->cpen.style() == Qt::SolidLine
4187  && d->cpen.isSolid()
4188  && d->cpen.color().alpha() == 255
4189  && d->txop < QTransform::TxProject
4190  && d->cpen.widthF() >= 2 / qSqrt(qMin(d->matrix.m11() * d->matrix.m11()
4191  + d->matrix.m21() * d->matrix.m21(),
4192  d->matrix.m12() * d->matrix.m12()
4193  + d->matrix.m22() * d->matrix.m22()));
4194 
4195  if (has_thick_pen) {
4196  DEBUG_ONCE qDebug() << "QOpenGLPaintEngine::drawPath(): Using thick pen optimization, style:" << d->cbrush.style();
4197 
4198  d->flushDrawQueue();
4199 
4200  bool temp = d->high_quality_antialiasing;
4201  d->high_quality_antialiasing = false;
4202 
4203  updateCompositionMode(d->composition_mode);
4204 
4205  d->fillPath(path);
4206 
4207  d->high_quality_antialiasing = temp;
4208  updateCompositionMode(d->composition_mode);
4209  } else {
4210  d->fillPath(path);
4211  }
4212  }
4213 
4214  if (d->has_pen) {
4215  if (d->has_fast_pen && !d->high_quality_antialiasing)
4216  d->strokePathFastPen(path, state()->penNeedsResolving());
4217  else
4218  d->strokePath(path, true);
4219  }
4220 }
4221 
4223 {
4224  QBrush old_brush = cbrush;
4225  QPointF old_brush_origin = brush_origin;
4226 
4227  qreal scaleX = r.width() / sr.width();
4228  qreal scaleY = r.height() / sr.height();
4229 
4230  QTransform brush_matrix = QTransform::fromTranslate(r.left(), r.top());
4231  brush_matrix.scale(scaleX, scaleY);
4232  brush_matrix.translate(-sr.left(), -sr.top());
4233 
4234  cbrush = QBrush(img);
4235  cbrush.setTransform(brush_matrix);
4236  brush_origin = QPointF();
4237 
4238  QPainterPath p;
4239  p.addRect(r);
4240  fillPath(p);
4241 
4242  cbrush = old_brush;
4243  brush_origin = old_brush_origin;
4244 }
4245 
4247  const QPointF &offset)
4248 {
4249  QBrush old_brush = cbrush;
4250  QPointF old_brush_origin = brush_origin;
4251 
4252  QTransform brush_matrix = QTransform::fromTranslate(r.left(), r.top());
4253  brush_matrix.scale(sx, sy);
4254  brush_matrix.translate(-offset.x(), -offset.y());
4255 
4256  cbrush = QBrush(img);
4257  cbrush.setTransform(brush_matrix);
4258  brush_origin = QPointF();
4259 
4260  QPainterPath p;
4261  p.addRect(r);
4262  fillPath(p);
4263 
4264  cbrush = old_brush;
4265  brush_origin = old_brush_origin;
4266 }
4267 
4268 static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy)
4269 {
4270  return QRectF(r.x() * sx, r.y() * sy, r.width() * sx, r.height() * sy);
4271 }
4272 
4273 template <typename T>
4274 static const T qSubImage(const T &image, const QRectF &src, QRectF *srcNew)
4275 {
4276  const int sx1 = qMax(0, qFloor(src.left()));
4277  const int sy1 = qMax(0, qFloor(src.top()));
4278  const int sx2 = qMin(image.width(), qCeil(src.right()));
4279  const int sy2 = qMin(image.height(), qCeil(src.bottom()));
4280 
4281  const T sub = image.copy(sx1, sy1, sx2 - sx1, sy2 - sy1);
4282 
4283  if (srcNew)
4284  *srcNew = src.translated(-sx1, -sy1);
4285 
4286  return sub;
4287 }
4288 
4289 void QOpenGLPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
4290 {
4292  if (pm.depth() == 1) {
4293  QPixmap tpx(pm.size());
4294  tpx.fill(Qt::transparent);
4295  QPainter p(&tpx);
4296  p.setPen(d->cpen);
4297  p.drawPixmap(0, 0, pm);
4298  p.end();
4299  drawPixmap(r, tpx, sr);
4300  return;
4301  }
4302 
4303  const int sz = d->max_texture_size;
4304  if (pm.width() > sz || pm.height() > sz) {
4305  QRectF subsr;
4306  const QPixmap sub = qSubImage(pm, sr, &subsr);
4307 
4308  if (sub.width() <= sz && sub.height() <= sz) {
4309  drawPixmap(r, sub, subsr);
4310  } else {
4311  const QPixmap scaled = sub.scaled(sz, sz, Qt::KeepAspectRatio);
4312  const qreal sx = scaled.width() / qreal(sub.width());
4313  const qreal sy = scaled.height() / qreal(sub.height());
4314 
4315  drawPixmap(r, scaled, scaleRect(subsr, sx, sy));
4316  }
4317  return;
4318  }
4319 
4320 
4321  if (d->composition_mode > QPainter::CompositionMode_Plus || (d->high_quality_antialiasing && !d->isFastRect(r)))
4322  d->drawImageAsPath(r, pm.toImage(), sr);
4323  else {
4325  d->flushDrawQueue();
4326  QGLTexture *tex =
4327  d->device->context()->d_func()->bindTexture(pm, target, GL_RGBA,
4329  drawTextureRect(pm.width(), pm.height(), r, sr, target, tex);
4330  }
4331 }
4332 
4333 void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &offset)
4334 {
4336  if (pm.depth() == 1) {
4337  QPixmap tpx(pm.size());
4338  tpx.fill(Qt::transparent);
4339  QPainter p(&tpx);
4340  p.setPen(d->cpen);
4341  p.drawPixmap(0, 0, pm);
4342  p.end();
4343  drawTiledPixmap(r, tpx, offset);
4344  return;
4345  }
4346 
4347  QImage scaled;
4348  const int sz = d->max_texture_size;
4349  if (pm.width() > sz || pm.height() > sz) {
4350  int rw = qCeil(r.width());
4351  int rh = qCeil(r.height());
4352  if (rw < pm.width() && rh < pm.height()) {
4353  drawTiledPixmap(r, pm.copy(0, 0, rw, rh), offset);
4354  return;
4355  }
4356 
4357  scaled = pm.toImage().scaled(sz, sz, Qt::KeepAspectRatio);
4358  }
4359 
4360  if (d->composition_mode > QPainter::CompositionMode_Plus || (d->high_quality_antialiasing && !d->isFastRect(r))) {
4361  if (scaled.isNull())
4362  d->drawTiledImageAsPath(r, pm.toImage(), 1, 1, offset);
4363  else {
4364  const qreal sx = pm.width() / qreal(scaled.width());
4365  const qreal sy = pm.height() / qreal(scaled.height());
4366  d->drawTiledImageAsPath(r, scaled, sx, sy, offset);
4367  }
4368  } else {
4369  d->flushDrawQueue();
4370 
4371  QGLTexture *tex;
4372  if (scaled.isNull())
4373  tex = d->device->context()->d_func()->bindTexture(pm, GL_TEXTURE_2D, GL_RGBA,
4375  else
4376  tex = d->device->context()->d_func()->bindTexture(scaled, GL_TEXTURE_2D, GL_RGBA,
4378  updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, d->use_smooth_pixmap_transform);
4379 
4380 #ifndef QT_OPENGL_ES
4381  glPushAttrib(GL_CURRENT_BIT);
4382  glDisable(GL_TEXTURE_GEN_S);
4383 #endif
4384  glColor4f(d->opacity, d->opacity, d->opacity, d->opacity);
4385  glEnable(GL_TEXTURE_2D);
4386 
4387  GLdouble tc_w = r.width()/pm.width();
4388  GLdouble tc_h = r.height()/pm.height();
4389 
4390  // Rotate the texture so that it is aligned correctly and the
4391  // wrapping is done correctly
4393  glMatrixMode(GL_TEXTURE);
4394  glPushMatrix();
4395  glRotatef(180.0, 0.0, 1.0, 0.0);
4396  glRotatef(180.0, 0.0, 0.0, 1.0);
4397  }
4398 
4399  GLfloat vertexArray[4*2];
4400  GLfloat texCoordArray[4*2];
4401 
4402  double offset_x = offset.x() / pm.width();
4403  double offset_y = offset.y() / pm.height();
4404 
4405  qt_add_rect_to_array(r, vertexArray);
4406  qt_add_texcoords_to_array(offset_x, offset_y,
4407  tc_w + offset_x, tc_h + offset_y, texCoordArray);
4408 
4409  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
4410  glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
4411 
4412  glEnableClientState(GL_VERTEX_ARRAY);
4413  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
4414  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
4415  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
4416  glDisableClientState(GL_VERTEX_ARRAY);
4418  glPopMatrix();
4419 
4420  glDisable(GL_TEXTURE_2D);
4421 #ifndef QT_OPENGL_ES
4422  glPopAttrib();
4423 #endif
4424  }
4425 }
4426 
4427 void QOpenGLPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
4428  Qt::ImageConversionFlags)
4429 {
4431 
4432  const int sz = d->max_texture_size;
4433  if (image.width() > sz || image.height() > sz) {
4434  QRectF subsr;
4435  const QImage sub = qSubImage(image, sr, &subsr);
4436 
4437  if (sub.width() <= sz && sub.height() <= sz) {
4438  drawImage(r, sub, subsr, 0);
4439  } else {
4440  const QImage scaled = sub.scaled(sz, sz, Qt::KeepAspectRatio);
4441  const qreal sx = scaled.width() / qreal(sub.width());
4442  const qreal sy = scaled.height() / qreal(sub.height());
4443 
4444  drawImage(r, scaled, scaleRect(subsr, sx, sy), 0);
4445  }
4446  return;
4447  }
4448 
4449  if (d->composition_mode > QPainter::CompositionMode_Plus || (d->high_quality_antialiasing && !d->isFastRect(r)))
4450  d->drawImageAsPath(r, image, sr);
4451  else {
4453  d->flushDrawQueue();
4454  QGLTexture *tex =
4455  d->device->context()->d_func()->bindTexture(image, target, GL_RGBA,
4457  drawTextureRect(image.width(), image.height(), r, sr, target, tex);
4458  }
4459 }
4460 
4461 void QOpenGLPaintEngine::drawTextureRect(int tx_width, int tx_height, const QRectF &r,
4462  const QRectF &sr, GLenum target, QGLTexture *tex)
4463 {
4465 #ifndef QT_OPENGL_ES
4466  glPushAttrib(GL_CURRENT_BIT);
4467  glDisable(GL_TEXTURE_GEN_S);
4468 #endif
4469  glColor4f(d->opacity, d->opacity, d->opacity, d->opacity);
4470  glEnable(target);
4471  updateTextureFilter(target, GL_CLAMP_TO_EDGE, d->use_smooth_pixmap_transform);
4472 
4473  qreal x1, x2, y1, y2;
4474  if (target == GL_TEXTURE_2D) {
4475  x1 = sr.x() / tx_width;
4476  x2 = x1 + sr.width() / tx_width;
4478  y1 = 1 - (sr.bottom() / tx_height);
4479  y2 = 1 - (sr.y() / tx_height);
4480  } else {
4481  y1 = sr.bottom() / tx_height;
4482  y2 = sr.y() / tx_height;
4483  }
4484  } else {
4485  x1 = sr.x();
4486  x2 = sr.right();
4487  y1 = sr.bottom();
4488  y2 = sr.y();
4489  }
4490 
4491  GLfloat vertexArray[4*2];
4492  GLfloat texCoordArray[4*2];
4493 
4494  qt_add_rect_to_array(r, vertexArray);
4495  qt_add_texcoords_to_array(x1, y2, x2, y1, texCoordArray);
4496 
4497  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
4498  glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
4499 
4500  glEnableClientState(GL_VERTEX_ARRAY);
4501  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
4502  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
4503  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
4504  glDisableClientState(GL_VERTEX_ARRAY);
4505 
4506  glDisable(target);
4507 #ifndef QT_OPENGL_ES
4508  glPopAttrib();
4509 #endif
4510 }
4511 
4512 #ifdef Q_WS_WIN
4513 HDC
4514 #else
4515 Qt::HANDLE
4516 #endif
4518 {
4519  return 0;
4520 }
4521 
4522 static const int x_margin = 1;
4523 static const int y_margin = 0;
4524 
4526  // stores the offset and size of a glyph texture
4535 };
4536 
4539  ~QGLFontTexture() { free(data); }
4540  int x_offset; // glyph offset within the
4542  GLuint texture;
4543  int width;
4544  int height;
4546 };
4547 
4552 
4553 static inline void qt_delete_glyph_hash(QGLGlyphHash *hash)
4554 {
4555  qDeleteAll(*hash);
4556  delete hash;
4557 }
4558 
4559 class QGLGlyphCache : public QObject
4560 {
4561  Q_OBJECT
4562 public:
4563  QGLGlyphCache() : QObject(0) { current_cache = 0; }
4564  ~QGLGlyphCache();
4566  void cacheGlyphs(QGLContext *, QFontEngine *, glyph_t *glyphs, int numGlyphs);
4567  void cleanCache();
4568  void allocTexture(QGLFontTexture *);
4569 
4570 public slots:
4571  void cleanupContext(const QGLContext *);
4572  void fontEngineDestroyed(QObject *);
4573  void widgetDestroyed(QObject *);
4574 
4575 protected:
4576  QGLGlyphHash *current_cache;
4577  QGLFontTexHash qt_font_textures;
4578  QGLContextHash qt_context_cache;
4579 };
4580 
4582 {
4583 // qDebug() << "cleaning out the QGLGlyphCache";
4584  cleanCache();
4585 }
4586 
4588 {
4589 // qDebug() << "fontEngineDestroyed()";
4590  QFontEngine *fe = static_cast<QFontEngine *>(o); // safe, since only the type is used
4591  QList<const QGLContext *> keys = qt_context_cache.keys();
4592  const QGLContext *ctx = 0;
4593 
4594  for (int i=0; i < keys.size(); ++i) {
4595  QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i));
4596  if (font_cache->find(fe) != font_cache->end()) {
4597  ctx = keys.at(i);
4598  QGLGlyphHash *cache = font_cache->take(fe);
4599  qt_delete_glyph_hash(cache);
4600  break;
4601  }
4602  }
4603 
4604  quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe);
4605  QGLFontTexture *tex = qt_font_textures.take(font_key);
4606  if (tex) {
4607 #ifdef Q_WS_MAC
4608  if (
4609 # ifndef QT_MAC_USE_COCOA
4610  aglGetCurrentContext() != 0
4611 # else
4612  qt_current_nsopengl_context() != 0
4613 # endif
4614  )
4615 #endif
4616  glDeleteTextures(1, &tex->texture);
4617  delete tex;
4618  }
4619 }
4620 
4622 {
4623 // qDebug() << "widget destroyed";
4624  cleanCache(); // ###
4625 }
4626 
4628 {
4629 // qDebug() << "==> cleaning for: " << hex << ctx;
4630  QGLFontGlyphHash *font_cache = qt_context_cache.take(ctx);
4631 
4632  if (font_cache) {
4633  QList<QFontEngine *> keys = font_cache->keys();
4634  for (int i=0; i < keys.size(); ++i) {
4635  QFontEngine *fe = keys.at(i);
4636  qt_delete_glyph_hash(font_cache->take(fe));
4637  quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe);
4638  QGLFontTexture *font_tex = qt_font_textures.take(font_key);
4639  if (font_tex) {
4640 #ifdef Q_WS_MAC
4641  if (
4642 # ifndef QT_MAC_USE_COCOA
4643  aglGetCurrentContext() == 0
4644 # else
4645  qt_current_nsopengl_context() != 0
4646 # endif
4647  )
4648 #endif
4649  glDeleteTextures(1, &font_tex->texture);
4650  delete font_tex;
4651  }
4652  }
4653  delete font_cache;
4654  }
4655 // qDebug() << "<=== done cleaning, num tex:" << qt_font_textures.size() << "num ctx:" << qt_context_cache.size();
4656 }
4657 
4659 {
4660  QGLFontTexHash::const_iterator it = qt_font_textures.constBegin();
4662  while (it != qt_font_textures.constEnd()) {
4663 #if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
4664  if (qt_current_nsopengl_context() == 0)
4665  break;
4666 #endif
4667  glDeleteTextures(1, &it.value()->texture);
4668  ++it;
4669  }
4670  }
4671  qDeleteAll(qt_font_textures);
4672  qt_font_textures.clear();
4673 
4674  QList<const QGLContext *> keys = qt_context_cache.keys();
4675  for (int i=0; i < keys.size(); ++i) {
4676  QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i));
4677  QGLFontGlyphHash::Iterator it = font_cache->begin();
4678  for (; it != font_cache->end(); ++it)
4680  font_cache->clear();
4681  }
4682  qDeleteAll(qt_context_cache);
4683  qt_context_cache.clear();
4684 }
4685 
4687 {
4688  font_tex->data = (uchar *) malloc(font_tex->width*font_tex->height*2);
4689  memset(font_tex->data, 0, font_tex->width*font_tex->height*2);
4690  glBindTexture(GL_TEXTURE_2D, font_tex->texture);
4691 #ifndef QT_OPENGL_ES
4692  glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8_ALPHA8,
4693  font_tex->width, font_tex->height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, font_tex->data);
4694 #else
4695  glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
4696  font_tex->width, font_tex->height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, font_tex->data);
4697 #endif
4698 }
4699 
4700 #if 0
4701 // useful for debugging the glyph cache
4702 static QImage getCurrentTexture(const QColor &color, QGLFontTexture *font_tex)
4703 {
4704  ushort *old_tex_data = (ushort *) malloc(font_tex->width*font_tex->height*2);
4705  glGetTexImage(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, old_tex_data);
4706  QImage im(font_tex->width, font_tex->height, QImage::Format_ARGB32);
4707  for (int y=0; y<font_tex->height; ++y) {
4708  for (int x=0; x<font_tex->width; ++x) {
4709  im.setPixel(x, y, ((*(old_tex_data+x+y*font_tex->width)) << 24) | (0x00ffffff & color.rgb()));
4710  }
4711  }
4712  delete old_tex_data;
4713  return im;
4714 }
4715 #endif
4716 
4718  glyph_t *glyphs, int numGlyphs)
4719 {
4720  QGLContextHash::const_iterator dev_it = qt_context_cache.constFind(context);
4721  QGLFontGlyphHash *font_cache = 0;
4722  const QGLContext *context_key = 0;
4723 
4724  if (dev_it == qt_context_cache.constEnd()) {
4725  // check for shared contexts
4726  QList<const QGLContext *> contexts = qt_context_cache.keys();
4727  for (int i=0; i<contexts.size(); ++i) {
4728  const QGLContext *ctx = contexts.at(i);
4729  if (ctx != context && QGLContext::areSharing(context, ctx)) {
4730  context_key = ctx;
4731  dev_it = qt_context_cache.constFind(context_key);
4732  break;
4733  }
4734  }
4735  }
4736 
4737  if (dev_it == qt_context_cache.constEnd()) {
4738  // no shared contexts either - create a new entry
4739  font_cache = new QGLFontGlyphHash;
4740 // qDebug() << "new context" << context << font_cache;
4741  qt_context_cache.insert(context, font_cache);
4742  if (context->isValid()) {
4743  if (context->device() && context->device()->devType() == QInternal::Widget) {
4744  QWidget *widget = static_cast<QWidget *>(context->device());
4745  connect(widget, SIGNAL(destroyed(QObject*)), SLOT(widgetDestroyed(QObject*)));
4746  }
4747  connect(QGLSignalProxy::instance(),
4748  SIGNAL(aboutToDestroyContext(const QGLContext*)),
4749  SLOT(cleanupContext(const QGLContext*)));
4750  }
4751  } else {
4752  font_cache = dev_it.value();
4753  }
4754  Q_ASSERT(font_cache != 0);
4755 
4756  QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(fontEngine);
4757  QGLGlyphHash *cache = 0;
4758  if (cache_it == font_cache->constEnd()) {
4759  cache = new QGLGlyphHash;
4760  font_cache->insert(fontEngine, cache);
4761  connect(fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*)));
4762  } else {
4763  cache = cache_it.value();
4764  }
4765  current_cache = cache;
4766 
4767  quint64 font_key = (reinterpret_cast<quint64>(context_key ? context_key : context) << 32)
4768  | reinterpret_cast<quint64>(fontEngine);
4769  QGLFontTexHash::const_iterator it = qt_font_textures.constFind(font_key);
4770  QGLFontTexture *font_tex;
4771  if (it == qt_font_textures.constEnd()) {
4772  GLuint font_texture;
4773  glGenTextures(1, &font_texture);
4774  GLint tex_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2);
4775  GLint tex_width = qt_next_power_of_two(tex_height*30); // ###
4776  GLint max_tex_size;
4777  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
4778  Q_ASSERT(max_tex_size > 0);
4779  if (tex_width > max_tex_size)
4780  tex_width = max_tex_size;
4781  font_tex = new QGLFontTexture;
4782  font_tex->texture = font_texture;
4783  font_tex->x_offset = x_margin;
4784  font_tex->y_offset = y_margin;
4785  font_tex->width = tex_width;
4786  font_tex->height = tex_height;
4787  allocTexture(font_tex);
4788 // qDebug() << "new font tex - width:" << tex_width << "height:"<< tex_height
4789 // << hex << "tex id:" << font_tex->texture << "key:" << font_key << "num cached:" << qt_font_textures.size();
4790  qt_font_textures.insert(font_key, font_tex);
4791  } else {
4792  font_tex = it.value();
4793  glBindTexture(GL_TEXTURE_2D, font_tex->texture);
4794  }
4795 
4796  for (int i=0; i< numGlyphs; ++i) {
4797  QGLGlyphHash::const_iterator it = cache->constFind(glyphs[i]);
4798  if (it == cache->constEnd()) {
4799  // render new glyph and put it in the cache
4800  glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
4801  QImage glyph_im(fontEngine->alphaMapForGlyph(glyphs[i]));
4802  int glyph_width = glyph_im.width();
4803  int glyph_height = qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal()) + 2;
4804  Q_ASSERT(glyph_width >= 0);
4805  // pad the glyph width to an even number
4806  if (glyph_width % 2 != 0)
4807  ++glyph_width;
4808 
4809  if (font_tex->x_offset + glyph_width + x_margin > font_tex->width) {
4810  int strip_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2);
4811  font_tex->x_offset = x_margin;
4812  font_tex->y_offset += strip_height;
4813  if (font_tex->y_offset + strip_height > font_tex->height) {
4814  // get hold of the old font texture
4815  uchar *old_tex_data = font_tex->data;
4816  int old_tex_height = font_tex->height;
4817 
4818  // realloc a larger texture
4819  glDeleteTextures(1, &font_tex->texture);
4820  glGenTextures(1, &font_tex->texture);
4821  font_tex->height = qt_next_power_of_two(font_tex->height + strip_height);
4822  allocTexture(font_tex);
4823 
4824  // write back the old texture data
4825  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, font_tex->width, old_tex_height,
4826  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, old_tex_data);
4827  memcpy(font_tex->data, old_tex_data, font_tex->width*old_tex_height*2);
4828  free(old_tex_data);
4829 
4830  // update the texture coords and the y offset for the existing glyphs in
4831  // the cache, because of the texture size change
4832  QGLGlyphHash::iterator it = cache->begin();
4833  while (it != cache->end()) {
4834  it.value()->height = (it.value()->height * old_tex_height) / font_tex->height;
4835  it.value()->y = (it.value()->y * old_tex_height) / font_tex->height;
4836  ++it;
4837  }
4838  }
4839  }
4840 
4841  glyph_height = qMin(glyph_height, glyph_im.height());
4842 
4843  QGLGlyphCoord *qgl_glyph = new QGLGlyphCoord;
4844  qgl_glyph->x = qreal(font_tex->x_offset) / font_tex->width;
4845  qgl_glyph->y = qreal(font_tex->y_offset) / font_tex->height;
4846  qgl_glyph->width = qreal(glyph_width) / font_tex->width;
4847  qgl_glyph->height = qreal(glyph_height) / font_tex->height;
4848  qgl_glyph->log_width = qreal(glyph_width);
4849  qgl_glyph->log_height = qgl_glyph->height * font_tex->height;
4850 #ifdef Q_WS_MAC
4851  qgl_glyph->x_offset = -metrics.x + 1;
4852  qgl_glyph->y_offset = metrics.y - 2;
4853 #else
4854  qgl_glyph->x_offset = -metrics.x;
4855  qgl_glyph->y_offset = metrics.y;
4856 #endif
4857 
4858  if (!glyph_im.isNull()) {
4859  int idx = 0;
4860  uchar *tex_data = (uchar *) malloc(glyph_width*glyph_height*2);
4861  memset(tex_data, 0, glyph_width*glyph_height*2);
4862 
4863  bool is8BitGray = false;
4864 #ifdef Q_WS_QPA
4865  if (glyph_im.format() == QImage::Format_Indexed8) {
4866  is8BitGray = true;
4867  }
4868 #endif
4869  glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8);
4870  int cacheLineStart = (font_tex->x_offset + font_tex->y_offset*font_tex->width)*2;
4871  for (int y=0; y<glyph_height; ++y) {
4872  uchar *s = (uchar *) glyph_im.scanLine(y);
4873  int lineStart = idx;
4874  for (int x=0; x<glyph_im.width(); ++x) {
4875  uchar alpha = is8BitGray ? *s : qAlpha(glyph_im.color(*s));
4876  tex_data[idx] = alpha;
4877  tex_data[idx+1] = alpha;
4878  ++s;
4879  idx += 2;
4880  }
4881  if (glyph_im.width()%2 != 0)
4882  idx += 2;
4883  // update cache
4884  memcpy(font_tex->data+cacheLineStart, tex_data+lineStart, glyph_width*2);
4885  cacheLineStart += font_tex->width*2;
4886  }
4887  glTexSubImage2D(GL_TEXTURE_2D, 0, font_tex->x_offset, font_tex->y_offset,
4888  glyph_width, glyph_height,
4890  free(tex_data);
4891  }
4892 
4893  font_tex->x_offset += glyph_width + x_margin;
4894 
4895  cache->insert(glyphs[i], qgl_glyph);
4896  }
4897  }
4898 }
4899 
4901 {
4902  Q_ASSERT(current_cache != 0);
4903  // ### careful here
4904  QGLGlyphHash::const_iterator it = current_cache->constFind(g);
4905  if (it == current_cache->constEnd())
4906  return 0;
4907  else
4908  return it.value();
4909 }
4910 
4911 Q_GLOBAL_STATIC(QGLGlyphCache, qt_glyph_cache)
4912 
4913 //
4914 // assumption: the context that this is called for has to be the
4915 // current context
4916 //
4918 {
4919  qt_glyph_cache()->cleanupContext(ctx);
4920 }
4921 
4923 {
4925 
4926  d->flushDrawQueue();
4927 
4928  // make sure the glyphs we want to draw are in the cache
4929  qt_glyph_cache()->cacheGlyphs(d->device->context(), textItem->fontEngine(), textItem->glyphs,
4930  textItem->numGlyphs);
4931 
4932  d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops
4933  qt_glColor4ubv(d->pen_color);
4934  glEnable(GL_TEXTURE_2D);
4935 
4936 #ifdef Q_WS_QWS
4937  // XXX: it is necessary to disable alpha writes on GLES/embedded because we don't want
4938  // text rendering to update the alpha in the window surface.
4939  // XXX: This may not be needed as this behavior does seem to be caused by driver bug
4940  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
4941 #endif
4942 
4943  // do the actual drawing
4944  GLfloat vertexArray[4*2];
4945  GLfloat texCoordArray[4*2];
4946 
4947  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
4948  glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
4949 
4950  glEnableClientState(GL_VERTEX_ARRAY);
4951  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
4952  bool antialias = !(textItem->fontEngine()->fontDef.styleStrategy & QFont::NoAntialias)
4953  && (d->matrix.type() > QTransform::TxTranslate);
4954  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
4955  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
4956 
4957  for (int i=0; i< textItem->numGlyphs; ++i) {
4958  QGLGlyphCoord *g = qt_glyph_cache()->lookup(textItem->fontEngine(), textItem->glyphs[i]);
4959 
4960  // we don't cache glyphs with no width/height
4961  if (!g)
4962  continue;
4963 
4964  qreal x1, x2, y1, y2;
4965  x1 = g->x;
4966  y1 = g->y;
4967  x2 = x1 + g->width;
4968  y2 = y1 + g->height;
4969 
4970  QPointF logical_pos((textItem->glyphPositions[i].x - g->x_offset).toReal(),
4971  (textItem->glyphPositions[i].y + g->y_offset).toReal());
4972 
4973  qt_add_rect_to_array(QRectF(logical_pos, QSizeF(g->log_width, g->log_height)), vertexArray);
4974  qt_add_texcoords_to_array(x1, y1, x2, y2, texCoordArray);
4975 
4976  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
4977  }
4978 
4979  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
4980  glDisableClientState(GL_VERTEX_ARRAY);
4981 
4982  glDisable(GL_TEXTURE_2D);
4983 
4984 #ifdef Q_WS_QWS
4985  // XXX: This may not be needed as this behavior does seem to be caused by driver bug
4986  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4987 #endif
4988 
4989 }
4990 
4992 {
4994 
4995  const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
4996 
4997  // fall back to drawing a polygon if the scale factor is large, or
4998  // we use a gradient pen
4999  if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern
5000  && d->pen_brush_style <= Qt::ConicalGradientPattern)) {
5001  QPaintEngine::drawTextItem(p, textItem);
5002  return;
5003  }
5004 
5005  // add the glyphs used to the glyph texture cache
5007  QVarLengthArray<glyph_t> glyphs;
5008  QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y()));
5009  ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
5010 
5011  {
5012  QStaticTextItem staticTextItem;
5013  staticTextItem.chars = const_cast<QChar *>(ti.chars);
5014  staticTextItem.setFontEngine(ti.fontEngine);
5015  staticTextItem.glyphs = glyphs.data();
5016  staticTextItem.numChars = ti.num_chars;
5017  staticTextItem.numGlyphs = glyphs.size();
5018  staticTextItem.glyphPositions = positions.data();
5019  drawStaticTextItem(&staticTextItem);
5020  }
5021 
5022 }
5023 
5024 
5026 {
5027 #ifndef Q_WS_QWS
5029 
5030  if (d->use_emulation) {
5032  return;
5033  }
5034 
5035  if (d->high_quality_antialiasing) {
5036  if (d->has_brush) {
5037  d->disableClipping();
5038 
5039  glMatrixMode(GL_MODELVIEW);
5040  glPushMatrix();
5041  glLoadIdentity();
5042 
5043  GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
5045  QGLEllipseMaskGenerator maskGenerator(rect,
5046  d->matrix,
5047  d->offscreen,
5048  program,
5050 
5051  d->addItem(qt_mask_texture_cache()->getMask(maskGenerator, d));
5052 
5053  d->enableClipping();
5054 
5055  glMatrixMode(GL_MODELVIEW);
5056  glPopMatrix();
5057  }
5058 
5059  if (d->has_pen) {
5061  path.addEllipse(rect);
5062 
5063  d->strokePath(path, false);
5064  }
5065  } else {
5066  DEBUG_ONCE_STR("QOpenGLPaintEngine::drawEllipse(): falling back to drawPath()");
5067 
5069  path.addEllipse(rect);
5070  drawPath(path);
5071  }
5072 #else
5074 #endif
5075 }
5076 
5077 
5079 {
5080 #ifdef Q_WS_QWS
5081  Q_UNUSED(locations);
5082 #else
5084 
5085  QSize sz = offscreen.offscreenSize();
5086 
5087  float inv_mask_size_data[4] = { 1.0f / sz.width(), 1.0f / sz.height(), 0.0f, 0.0f };
5088 
5089  sz = drawable_texture_size;
5090 
5091  float inv_dst_size_data[4] = { 1.0f / sz.width(), 1.0f / sz.height(), 0.0f, 0.0f };
5092 
5093  // default inv size 0.125f == 1.0f / 8.0f for pattern brushes
5094  float inv_brush_texture_size_data[4] = { 0.125f, 0.125f };
5095 
5096  // texture patterns have their own size
5097  if (current_style == Qt::TexturePattern) {
5098  QSize sz = cbrush.texture().size();
5099 
5100  inv_brush_texture_size_data[0] = 1.0f / sz.width();
5101  inv_brush_texture_size_data[1] = 1.0f / sz.height();
5102  }
5103 
5104  for (unsigned int i = 0; i < num_fragment_variables; ++i) {
5105  int location = locations[i];
5106 
5107  if (location < 0)
5108  continue;
5109 
5110  switch (i) {
5111  case VAR_ANGLE:
5113  break;
5114  case VAR_LINEAR:
5116  break;
5117  case VAR_FMP:
5119  break;
5120  case VAR_FMP2_M_RADIUS2:
5121  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, fmp2_m_radius2_data);
5122  break;
5123  case VAR_INV_MASK_SIZE:
5124  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, inv_mask_size_data);
5125  break;
5126  case VAR_INV_DST_SIZE:
5127  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, inv_dst_size_data);
5128  break;
5129  case VAR_INV_MATRIX_M0:
5130  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, inv_matrix_data[0]);
5131  break;
5132  case VAR_INV_MATRIX_M1:
5133  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, inv_matrix_data[1]);
5134  break;
5135  case VAR_INV_MATRIX_M2:
5136  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, inv_matrix_data[2]);
5137  break;
5138  case VAR_PORTERDUFF_AB:
5139  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, porterduff_ab_data);
5140  break;
5141  case VAR_PORTERDUFF_XYZ:
5142  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, porterduff_xyz_data);
5143  break;
5145  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, inv_brush_texture_size_data);
5146  break;
5147  case VAR_MASK_OFFSET:
5148  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, mask_offset_data);
5149  break;
5150  case VAR_MASK_CHANNEL:
5151  glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, location, mask_channel_data);
5152  break;
5153  case VAR_DST_TEXTURE:
5154  case VAR_MASK_TEXTURE:
5155  case VAR_PALETTE:
5156  case VAR_BRUSH_TEXTURE:
5157  // texture variables, not handled here
5158  break;
5159  default:
5160  qDebug() << "QOpenGLPaintEnginePrivate: Unhandled fragment variable:" << i;
5161  }
5162  }
5163 #endif
5164 }
5165 
5166 
5168 {
5169 #ifdef Q_WS_QWS
5170  Q_UNUSED(rect);
5171 #else
5172  ensureDrawableTexture();
5173 
5174  DEBUG_ONCE qDebug() << "Refreshing drawable_texture for rectangle" << rect;
5175  QRectF screen_rect = rect.adjusted(-1, -1, 1, 1);
5176 
5177  int left = qMax(0, static_cast<int>(screen_rect.left()));
5178  int width = qMin(device->size().width() - left, static_cast<int>(screen_rect.width()) + 1);
5179 
5180  int bottom = qMax(0, static_cast<int>(device->size().height() - screen_rect.bottom()));
5181  int height = qMin(device->size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
5182 
5183  glBindTexture(GL_TEXTURE_2D, drawable_texture);
5184  glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, left, bottom, width, height);
5185 #endif
5186 }
5187 
5188 
5189 void QOpenGLPaintEnginePrivate::composite(const QRectF &rect, const QPoint &maskOffset)
5190 {
5191 #ifdef Q_WS_QWS
5192  Q_UNUSED(rect);
5193  Q_UNUSED(maskOffset);
5194 #else
5195  GLfloat vertexArray[8];
5196  qt_add_rect_to_array(rect, vertexArray);
5197 
5198  composite(GL_TRIANGLE_FAN, vertexArray, 4, maskOffset);
5199 #endif
5200 }
5201 
5202 
5203 void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const GLfloat *vertexArray, int vertexCount, const QPoint &maskOffset)
5204 {
5205 #ifdef QT_OPENGL_ES
5206  Q_UNUSED(primitive);
5207  Q_UNUSED(vertexArray);
5208  Q_UNUSED(vertexCount);
5209  Q_UNUSED(maskOffset);
5210 #else
5213 
5214  if (current_style == Qt::NoBrush)
5215  return;
5216 
5217  DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Using compositing program: fragment_brush ="
5218  << fragment_brush << ", fragment_composition_mode =" << fragment_composition_mode;
5219 
5220  if (has_fast_composition_mode)
5221  q->updateCompositionMode(composition_mode);
5222  else {
5223  qreal minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;
5224 
5225  for (int i = 0; i < vertexCount; ++i) {
5226  qreal x = vertexArray[2 * i];
5227  qreal y = vertexArray[2 * i + 1];
5228 
5229  qreal tx, ty;
5230  matrix.map(x, y, &tx, &ty);
5231 
5232  minX = qMin(minX, tx);
5233  minY = qMin(minY, ty);
5234  maxX = qMax(maxX, tx);
5235  maxY = qMax(maxY, ty);
5236  }
5237 
5238  QRectF r(minX, minY, maxX - minX, maxY - minY);
5239  copyDrawable(r);
5240 
5241  glBlendFunc(GL_ONE, GL_ZERO);
5242  }
5243 
5244  int *locations = painter_variable_locations[fragment_brush][fragment_composition_mode];
5245 
5246  int texture_locations[] = { locations[VAR_DST_TEXTURE],
5247  locations[VAR_MASK_TEXTURE],
5248  locations[VAR_PALETTE] };
5249 
5250  int brush_texture_location = locations[VAR_BRUSH_TEXTURE];
5251 
5252  GLuint texture_targets[] = { GL_TEXTURE_2D,
5253  GL_TEXTURE_2D,
5254  GL_TEXTURE_1D };
5255 
5256  GLuint textures[] = { drawable_texture,
5257  offscreen.offscreenTexture(),
5258  grad_palette };
5259 
5260  const int num_textures = sizeof(textures) / sizeof(*textures);
5261 
5262  Q_ASSERT(num_textures == sizeof(texture_locations) / sizeof(*texture_locations));
5263  Q_ASSERT(num_textures == sizeof(texture_targets) / sizeof(*texture_targets));
5264 
5265  for (int i = 0; i < num_textures; ++i)
5266  if (texture_locations[i] >= 0) {
5267  glActiveTexture(GL_TEXTURE0 + texture_locations[i]);
5268  glBindTexture(texture_targets[i], textures[i]);
5269  }
5270 
5271  if (brush_texture_location >= 0) {
5272  glActiveTexture(GL_TEXTURE0 + brush_texture_location);
5273 
5274  if (current_style == Qt::TexturePattern)
5275  device->context()->d_func()->bindTexture(cbrush.textureImage(), GL_TEXTURE_2D, GL_RGBA,
5277  else
5278  device->context()->d_func()->bindTexture(qt_imageForBrush(current_style, false),
5279  GL_TEXTURE_2D, GL_RGBA,
5281 
5282  updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, use_smooth_pixmap_transform);
5283  }
5284 
5285  glEnableClientState(GL_VERTEX_ARRAY);
5286  glVertexPointer(2, GL_FLOAT, 0, vertexArray);
5287  glEnable(GL_FRAGMENT_PROGRAM_ARB);
5288  GLuint program = qt_gl_program_cache()->getProgram(device->context(),
5289  fragment_brush,
5290  fragment_composition_mode, false);
5292 
5293  mask_offset_data[0] = maskOffset.x();
5294  mask_offset_data[1] = -maskOffset.y();
5295 
5296  updateFragmentProgramData(locations);
5297 
5298  glDrawArrays(primitive, 0, vertexCount);
5299 
5300  glDisable(GL_FRAGMENT_PROGRAM_ARB);
5301  glDisableClientState(GL_VERTEX_ARRAY);
5302 
5303  for (int i = 0; i < num_textures; ++i)
5304  if (texture_locations[i] >= 0) {
5305  glActiveTexture(GL_TEXTURE0 + texture_locations[i]);
5306  glBindTexture(texture_targets[i], 0);
5307  }
5308 
5309  if (brush_texture_location >= 0) {
5310  glActiveTexture(GL_TEXTURE0 + brush_texture_location);
5311  glBindTexture(GL_TEXTURE_2D, 0);
5312  }
5313 
5315 
5316  if (!has_fast_composition_mode)
5317  q->updateCompositionMode(composition_mode);
5318 #endif
5319 }
5320 
5322 {
5323  bool isInDrawQueue = false;
5324 
5325  foreach (const QDrawQueueItem &item, drawQueue) {
5326  if (item.location.channel == channel && item.location.rect == rect) {
5327  isInDrawQueue = true;
5328  break;
5329  }
5330  }
5331 
5332  if (isInDrawQueue)
5333  flushDrawQueue();
5334 }
5335 
5337 {
5338  drawQueue << QDrawQueueItem(opacity, cbrush, brush_origin, composition_mode, matrix, location);
5339 }
5340 
5342 {
5344 
5345  opacity = item.opacity;
5346  brush_origin = item.brush_origin;
5347  q->updateCompositionMode(item.composition_mode);
5348  matrix = item.matrix;
5349  cbrush = item.brush;
5350  brush_style = item.brush.style();
5351 
5352  mask_channel_data[0] = item.location.channel == 0;
5353  mask_channel_data[1] = item.location.channel == 1;
5354  mask_channel_data[2] = item.location.channel == 2;
5355  mask_channel_data[3] = item.location.channel == 3;
5356 
5357  setGradientOps(item.brush, item.location.screen_rect);
5358 
5359  composite(item.location.screen_rect, item.location.rect.topLeft() - item.location.screen_rect.topLeft()
5360  - QPoint(0, offscreen.offscreenSize().height() - device->size().height()));
5361 }
5362 
5364 {
5365 #ifndef QT_OPENGL_ES
5367 
5368  offscreen.release();
5369 
5370  if (!drawQueue.isEmpty()) {
5371  DEBUG_ONCE qDebug() << "QOpenGLPaintEngine::flushDrawQueue():" << drawQueue.size() << "items";
5372 
5373  glPushMatrix();
5374  glLoadIdentity();
5375  qreal old_opacity = opacity;
5376  QPointF old_brush_origin = brush_origin;
5377  QPainter::CompositionMode old_composition_mode = composition_mode;
5378  QTransform old_matrix = matrix;
5379  QBrush old_brush = cbrush;
5380 
5381  bool hqaa_old = high_quality_antialiasing;
5382 
5383  high_quality_antialiasing = true;
5384 
5385  foreach (const QDrawQueueItem &item, drawQueue)
5386  drawItem(item);
5387 
5388  opacity = old_opacity;
5389  brush_origin = old_brush_origin;
5390  q->updateCompositionMode(old_composition_mode);
5391  matrix = old_matrix;
5392  cbrush = old_brush;
5393  brush_style = old_brush.style();
5394 
5395  high_quality_antialiasing = hqaa_old;
5396 
5397  setGLBrush(old_brush.color());
5398  qt_glColor4ubv(brush_color);
5399 
5400  drawQueue.clear();
5401 
5402  glPopMatrix();
5403  }
5404 #endif
5405 }
5406 
5408 {
5410 
5411  d->updateDepthClip();
5412 }
5413 
5415 {
5416  updatePen(state()->pen);
5417 }
5418 
5420 {
5421  updateBrush(state()->brush, state()->brushOrigin);
5422 }
5423 
5425 {
5426  updateBrush(state()->brush, state()->brushOrigin);
5427 }
5428 
5430 {
5432  QPainterState *s = state();
5433  d->opacity = s->opacity;
5434  updateBrush(s->brush, s->brushOrigin);
5435  updatePen(s->pen);
5436 }
5437 
5439 {
5440  updateCompositionMode(state()->composition_mode);
5441 }
5442 
5444 {
5445  updateRenderHints(state()->renderHints);
5446 }
5447 
5449 {
5450  updateMatrix(state()->matrix);
5451 }
5452 
5454 
5455 void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
5456 {
5458 
5459  if (brush.style() == Qt::NoBrush)
5460  return;
5461 
5462  if ((!d->use_fragment_programs && needsEmulation(brush.style())) || qt_isExtendedRadialGradient(brush)) {
5463  QPainter *p = painter();
5464  QBrush oldBrush = p->brush();
5465  p->setBrush(brush);
5467  p->setBrush(oldBrush);
5468  return;
5469  }
5470 
5471  QBrush old_brush = state()->brush;
5472  updateBrush(brush, state()->brushOrigin);
5473 
5474  const qreal *points = path.points();
5475  const QPainterPath::ElementType *types = path.elements();
5476  if (!types && path.shape() == QVectorPath::RectangleHint) {
5477  QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
5478  QPen old_pen = state()->pen;
5479  updatePen(Qt::NoPen);
5480  drawRects(&r, 1);
5481  updatePen(old_pen);
5482  } else {
5483  d->fillPath(qt_painterPathFromVectorPath(path));
5484  }
5485 
5486  updateBrush(old_brush, state()->brushOrigin);
5487 }
5488 
5489 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
5490  return (elementCount == 5 // 5-point polygon, check for closed rect
5491  && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
5492  && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
5493  && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
5494  ) ||
5495  (elementCount == 4 // 4-point polygon, check for unclosed rect
5496  && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
5497  && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
5498  );
5499 }
5500 
5502 {
5503  const qreal *points = path.points();
5504  const QPainterPath::ElementType *types = path.elements();
5505  if (!types && path.shape() == QVectorPath::RectangleHint) {
5506  QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
5507  updateClipRegion(QRegion(r.toRect()), op);
5508  return;
5509  }
5510 
5511  QPainterPath p;
5512  if (types) {
5513  int id = 0;
5514  for (int i=0; i<path.elementCount(); ++i) {
5515  switch(types[i]) {
5517  p.moveTo(QPointF(points[id], points[id+1]));
5518  id+=2;
5519  break;
5521  p.lineTo(QPointF(points[id], points[id+1]));
5522  id+=2;
5523  break;
5525  QPointF p1(points[id], points[id+1]);
5526  QPointF p2(points[id+2], points[id+3]);
5527  QPointF p3(points[id+4], points[id+5]);
5528  p.cubicTo(p1, p2, p3);
5529  id+=6;
5530  break;
5531  }
5533  ;
5534  break;
5535  }
5536  }
5537  } else if (!path.isEmpty()) {
5538  p.moveTo(QPointF(points[0], points[1]));
5539  int id = 2;
5540  for (int i=1; i<path.elementCount(); ++i) {
5541  p.lineTo(QPointF(points[id], points[id+1]));
5542  id+=2;
5543  }
5544  }
5545  if (path.hints() & QVectorPath::WindingFill)
5547 
5548  updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op);
5549  return;
5550 }
5551 
5553 {
5555  QOpenGLPaintEngineState *new_state = static_cast<QOpenGLPaintEngineState *>(s);
5556  QOpenGLPaintEngineState *old_state = state();
5557 
5559 
5560  // are we in a save() ?
5561  if (s == d->last_created_state) {
5562  d->last_created_state = 0;
5563  return;
5564  }
5565 
5566  if (isActive()) {
5567  if (old_state->depthClipId != new_state->depthClipId)
5568  d->updateDepthClip();
5569  penChanged();
5570  brushChanged();
5571  opacityChanged();
5572  compositionModeChanged();
5573  renderHintsChanged();
5574  transformChanged();
5575  }
5576 }
5577 
5579 {
5580  const Q_D(QOpenGLPaintEngine);
5581 
5583  if (!orig)
5584  s = new QOpenGLPaintEngineState();
5585  else
5586  s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig));
5587 
5588  d->last_created_state = s;
5589  return s;
5590 }
5591 
5592 //
5593 // QOpenGLPaintEngineState
5594 //
5595 
5597  : QPainterState(other)
5598 {
5599  clipRegion = other.clipRegion;
5600  hasClipping = other.hasClipping;
5601  fastClip = other.fastClip;
5602  depthClipId = other.depthClipId;
5603 }
5604 
5606 {
5607  hasClipping = false;
5608  depthClipId = 0;
5609 }
5610 
5612 {
5613 }
5614 
5616 {
5617  if (!dirty_drawable_texture)
5618  return;
5619 
5620  dirty_drawable_texture = false;
5621 
5622 #ifndef QT_OPENGL_ES
5623  glGenTextures(1, &drawable_texture);
5624  glBindTexture(GL_TEXTURE_2D, drawable_texture);
5625 
5626  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
5627  drawable_texture_size.width(),
5628  drawable_texture_size.height(), 0,
5629  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5630 
5631  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5632  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5635 #endif
5636 }
5637 
5639 
5640 #include "qpaintengine_opengl.moc"
ElementType type
the type of element
Definition: qpainterpath.h:81
bool qt_resolve_version_1_3_functions(QGLContext *ctx)
void setOffscreenSize(const QSize &offscreenSize)
virtual void drawPoints(const QPointF *points, int pointCount)
Draws the first pointCount points in the buffer points.
#define GL_ONE_MINUS_SRC_ALPHA
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
#define glMultiTexCoord4f
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
void setDashOffset(qreal offset)
Sets the dash offset for the generated outlines to offset.
double d
Definition: qnumeric_p.h:62
QRect toAlignedRect() const
Returns a QRect based on the values of this rectangle that is the smallest possible integer rectangle...
Definition: qrect.cpp:2817
QOpenGLPaintEnginePrivate * d
QPointF bottomRight() const
Returns the position of the rectangle&#39;s bottom-right corner.
Definition: qrect.h:540
CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode)
static uint hash(const uchar *p, int n)
Definition: qhash.cpp:68
QGLEllipseMaskGenerator(const QRectF &rect, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram, int *maskVariableLocations)
#define DEBUG_ONCE_STR(str)
QPointF focalPoint() const
Returns the focal point of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2251
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:77
QFontEngine * fontEngine
const T * constData() const
QImage toImage() const
Converts the pixmap to a QImage.
Definition: qpixmap.cpp:542
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
const Vertex * topRight
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
Definition: qpainterpath.h:392
#define GL_LINES
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
Definition: qpainterpath.h:70
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
void drawMask(const QRect &rect)
#define GL_BGRA
Definition: glfunctions.h:63
#define glDeleteProgramsARB
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
static QPainterPath ellipseRectToPath(const QRectF &rect)
qreal right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:527
BrushStyle
Definition: qnamespace.h:1162
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
Definition: qbrush.cpp:167
The QHash::const_iterator class provides an STL-style const iterator for QHash and QMultiHash...
Definition: qhash.h:395
QRect adjusted(int x1, int y1, int x2, int y2) const
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition: qrect.h:431
#define GL_CLAMP_TO_EDGE
Definition: glfunctions.h:62
#define GL_TEXTURE_MIN_FILTER
double qreal
Definition: qglobal.h:1193
#define GL_INCR_WRAP_EXT
static OpenGLVersionFlags openGLVersionFlags()
virtual QImage alphaMapForGlyph(glyph_t)
static mach_timebase_info_data_t info
unsigned char c[8]
Definition: qnumeric_p.h:62
qreal opacity() const
Returns the opacity in the current paint engine state.
Definition: qpainter.cpp:9529
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const QColor & color() const
Returns the brush color.
Definition: qbrush.h:183
void allocTexture(QGLFontTexture *)
QFontEngine * fontEngine() const
int width() const
Returns the width of the pixmap.
Definition: qpixmap.cpp:630
QPointer< QWidget > widget
QSize size() const
Returns the size of the pixmap.
Definition: qpixmap.cpp:661
QHash< const QGLContext *, QGLFontGlyphHash * > QGLContextHash
#define GL_TRUE
void clear()
Removes all items from the hash.
Definition: qhash.h:574
int elementCount() const
virtual void drawPath(const QPainterPath &path)
The default implementation ignores the path and does nothing.
static const unsigned int num_fragment_masks
#define GL_PROGRAM_FORMAT_ASCII_ARB
qreal m32() const
Returns the vertical translation factor.
Definition: qtransform.h:265
QOpenGLPaintEnginePrivate * engine
void drawStaticTextItem(QStaticTextItem *staticTextItem)
CompositionMode
Defines the modes supported for digital image compositing.
Definition: qpainter.h:138
The QLine class provides a two-dimensional vector using integer precision.
Definition: qline.h:57
QDrawQueueItem(qreal _opacity, QBrush _brush, const QPointF &_brush_origion, QPainter::CompositionMode _composition_mode, const QTransform &_matrix, QGLMaskTextureCache::CacheLocation _location)
bool isEmpty() const
int qCeil(qreal v)
Definition: qmath.h:63
T * data() const
Returns the value of the pointer referenced by this object.
#define GL_MAX_TEXTURE_SIZE
const QGradient * gradient() const
Returns the gradient describing this brush.
Definition: qbrush.cpp:871
#define GL_DEPTH_TEST
#define it(className, varName)
QGLFontTexHash qt_font_textures
const QChar * chars
Q_GUI_EXPORT_INLINE int qAlpha(QRgb rgb)
Definition: qrgb.h:66
QFixedPoint * glyphPositions
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
#define GL_POINTS
void setTransform(const QTransform &)
Sets matrix as an explicit transformation matrix on the current brush.
Definition: qbrush.cpp:968
qreal x2() const
Returns the x-coordinate of the line&#39;s end point.
Definition: qline.h:304
void updateState(const QPaintEngineState &state)
Reimplement this function to update the state of a paint engine.
#define GL_INVERT
Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
Definition: qbrush.cpp:881
#define GL_SRC_ALPHA
Qt::PenStyle style() const
Returns the pen style.
Definition: qpen.cpp:428
void addItem(const QGLMaskTextureCache::CacheLocation &location)
int qFloor(qreal v)
Definition: qmath.h:73
void quadtreeInsert(int channel, quint64 key, const QRect &rect, int node=0)
void drawMask(const QRect &rect)
The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
QPointF p1() const
Returns the line&#39;s start point.
Definition: qline.h:314
#define QGL_FUNC_CONTEXT
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition: qimage.cpp:1542
qreal x2
Definition: qbezier_p.h:116
static bool isSupported()
void updateMatrix(const QTransform &matrix)
#define GL_STENCIL_BUFFER_BIT
T & first()
Returns a reference to the first item in the vector.
Definition: qvector.h:260
qreal m21() const
Returns the horizontal shearing factor.
Definition: qtransform.h:249
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
bool quadtreeFindAvailableLocation(const QSize &size, QRect *rect, int *channel)
RenderFlags flags
The QConicalGradient class is used in combination with QBrush to specify a conical gradient brush...
Definition: qbrush.h:329
QGLTrapezoidMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram, qreal strokeWidth=-1.0)
QTransform transform() const
Returns the matrix in the current paint engine state.
Definition: qpainter.cpp:9377
qreal y2() const
Returns the y-coordinate of the line&#39;s end point.
Definition: qline.h:309
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
#define SLOT(a)
Definition: qobjectdefs.h:226
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
bool isBound() const
FillRule
Definition: qnamespace.h:1485
qreal left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:525
void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
Reimplement this function to draw the pixmap in the given rect, starting at the given p...
T1 first
Definition: qpair.h:65
const Vertex * bottomLeft
static QGLSignalProxy * instance()
Definition: qgl.cpp:148
QGLMaskTextureCache::CacheLocation location
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
#define Q27Dot5ToDouble(i)
qreal m22() const
Returns the vertical scaling factor.
Definition: qtransform.h:253
QRectF tessellate(const QPointF *points, int nPoints)
QGLContextHash qt_context_cache
static bool pathClosed(const QPainterPath &path)
#define GL_UNPACK_IMAGE_HEIGHT
QPointF topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:539
bool isLineTo() const
Returns true if the element is a line, otherwise returns false.
Definition: qpainterpath.h:84
void drawImageAsPath(const QRectF &r, const QImage &img, const QRectF &sr)
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
#define GL_PACK_ALIGNMENT
QColor color() const
Returns the color of this pen&#39;s brush.
Definition: qpen.cpp:771
QVector< QGLTrapezoid > generateTrapezoids()
QRect translated(int dx, int dy) const
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis...
Definition: qrect.h:328
void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
Definition: qpainter.cpp:9937
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
void fillPolygon_dev(const QPointF *polygonPoints, int pointCount, Qt::FillRule fill)
virtual uint flags() const
void drawPath(const QPainterPath &path)
The default implementation ignores the path and does nothing.
virtual void drawPoints(const QPointF *points, int pointCount)
Draws the first pointCount points in the buffer points.
QGLMaskGenerator(const QPainterPath &path, const QTransform &matrix, qreal stroke_width=-1)
#define GL_TEXTURE_WRAP_S
static Q_DECL_CONSTEXPR bool qFuzzyCompare(double p1, double p2)
Definition: qglobal.h:2030
QHash< quint64, QGLFontTexture * > QGLFontTexHash
QGLTrapezoid toGLTrapezoid(const Trapezoid &trap)
void setDevice(QPaintDevice *pdev)
long ASN1_INTEGER_get ASN1_INTEGER * a
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
T & value() const
Returns a modifiable reference to the current item&#39;s value.
Definition: qhash.h:348
void fontEngineDestroyed(QObject *)
#define Q_SLOTS
Definition: qobjectdefs.h:71
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
bool isCurveTo() const
Returns true if the element is a curve, otherwise returns false.
Definition: qpainterpath.h:85
int depth() const
Returns the depth of the pixmap.
Definition: qpixmap.cpp:695
ushort red
Returns the red color component of this color.
Definition: qcolor.h:243
static void qt_glColor4ubv(unsigned char *col)
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 y
the y coordinate of the element&#39;s position.
Definition: qpainterpath.h:80
int bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:249
bool isClipEnabled() const
Returns whether clipping is enabled or not in the current paint engine state.
Definition: qpainter.cpp:9473
bool contains(const QPointF &pt) const
Returns true if the given point is inside the path, otherwise returns false.
virtual QSize size() const =0
Q_CORE_EXPORT int qrand()
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it...
Definition: qhash.h:807
#define GL_STENCIL_TEST_TWO_SIDE_EXT
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
void drawOffscreenPath(const QPainterPath &path)
static const unsigned int num_fragment_composition_modes
static void drawTrapezoid(const QGLTrapezoid &trap, const qreal offscreenHeight, QGLContext *ctx)
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
QRectF boundingRect() const
Returns the bounding rectangle of the polygon, or QRectF(0,0,0,0) if the polygon is empty...
Definition: qpolygon.cpp:742
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
int qt_next_power_of_two(int v)
Definition: qgl.cpp:1886
TransformationType type() const
Returns the transformation type of this matrix.
#define GL_STENCIL_TEST
void widgetDestroyed(QObject *)
#define Q_D(Class)
Definition: qglobal.h:2482
void tessellate(const QPointF *points, int nPoints, bool winding)
QTransform transform() const
Returns the current transformation matrix for the brush.
Definition: qbrush.h:185
void strokePathFastPen(const QPainterPath &path, bool needsResolving)
qreal angle() const
Returns the start angle of the conical gradient in logical coordinates.
Definition: qbrush.cpp:2433
QGradient::InterpolationMode interpolationMode
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
uint internal_context
Definition: qgl_p.h:426
QPolygon toPolygon() const
Creates and returns a QPolygon by converting each QPointF to a QPoint.
Definition: qpolygon.cpp:772
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
QGLContext::BindOptions options
Definition: qgl_p.h:611
#define GL_TEXTURE_2D
const QPainterPath::ElementType * elements() const
void setMiterLimit(qreal length)
Sets the miter limit of the generated outlines to limit.
void cleanupGLContextRefs(const QGLContext *context)
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
int y1() const
Returns the y-coordinate of the line&#39;s start point.
Definition: qline.h:117
virtual QGLContext * context() const =0
QStringList keys
QGLTextureCacheHash cache
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
QVector< qreal > dashPattern() const
Returns the dash pattern of this pen.
Definition: qpen.cpp:466
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
void setFontEngine(QFontEngine *fe)
PenStyle
Definition: qnamespace.h:1134
void strokePath(const QPainterPath &path, bool use_cache)
GLuint addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
InterpolationMode interpolationMode() const
Returns the interpolation mode of this gradient.
Definition: qbrush.cpp:1607
qreal y2
Definition: qbezier_p.h:116
virtual void drawMask(const QRect &rect)=0
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
qreal x4
Definition: qbezier_p.h:116
QMultiHash< quint64, CacheInfo > QGLTextureCacheHash
QTransform inverted(bool *invertible=0) const
Returns an inverted copy of this matrix.
Definition: qtransform.cpp:364
static void disableOffset(QOpenGLPaintEnginePrivate *d)
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
QPointF center() const
Returns the center of the conical gradient in logical coordinates.
Definition: qbrush.cpp:2391
#define GL_TEXTURE
PenCapStyle
Definition: qnamespace.h:1147
#define GL_SCISSOR_TEST
static const QGLContext * currentContext()
Returns the current context, i.e.
Definition: qgl.cpp:3545
void updateClipRegion(const QRegion &region, Qt::ClipOperation op)
QGLPathMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram)
#define Q_Q(Class)
Definition: qglobal.h:2483
#define GL_REPEAT
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
QFuture< T > mapped(const Sequence &sequence, MapFunction function)
void setInvMatrixData(const QTransform &inv_matrix)
void copyDrawable(const QRectF &rect)
void setDashPattern(Qt::PenStyle)
Sets the dash pattern for the generated outlines to style.
static bool areSharing(const QGLContext *context1, const QGLContext *context2)
Returns true if context1 and context2 are sharing their GL resources such as textures, shader programs, etc; otherwise returns false.
Definition: qgl.cpp:3319
static const QRectF boundingRect(const QPointF *points, int pointCount)
#define GL_ONE_MINUS_DST_ALPHA
#define glGenProgramsARB
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
Q_CORE_EXPORT void qDebug(const char *,...)
QGradientStops stops() const
Returns the stop points for this gradient.
Definition: qbrush.cpp:1520
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
static const unsigned int num_fragment_brushes
QVector< QGLTrapezoid > generateTrapezoids()
QGlyphLayout glyphs
#define SIGNAL(a)
Definition: qobjectdefs.h:227
qreal m12() const
Returns the vertical shearing factor.
Definition: qtransform.h:241
void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, GLfloat *array)
Definition: qgl.cpp:2989
void drawLines(const QLineF *lines, int lineCount)
The default implementation splits the list of lines in lines into lineCount separate calls to drawPat...
#define GL_FALSE
#define GL_TEXTURE0
Definition: glfunctions.h:61
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition: qbezier.cpp:71
unsigned char uchar
Definition: qglobal.h:994
int width() const
Returns the width.
Definition: qsize.h:126
QRegion clipRegion() const
Returns the currently set clip region.
Definition: qpainter.cpp:2562
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 ARGB_COMBINE_ALPHA(argb, alpha)
#define GL_VERSION
QPainter * painter() const
Returns the paint engine&#39;s painter.
GLenum qt_gl_preferredTextureTarget()
Definition: qgl_p.h:715
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QBrush brush() const
Returns the brush in the current paint engine state.
Definition: qpainter.cpp:9273
QSize drawableSize() const
QVector< QGLTrapezoid > generateTrapezoids()
void pathToVertexArrays(const QPainterPath &path)
#define GL_MIRRORED_REPEAT_IBM
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QFixed y
Definition: qfixed_p.h:191
QPainterState * createState(QPainterState *orig) const
#define GL_MULTISAMPLE
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path...
QPolygonF toFillPolygon(const QMatrix &matrix=QMatrix()) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static void enableOffset(QOpenGLPaintEnginePrivate *d)
QOpenGLPaintEngineState * state()
Qt::ClipOperation clipOperation() const
Returns the clip operation in the current paint engine state.
Definition: qpainter.cpp:9396
unsigned __int64 quint64
Definition: qglobal.h:943
QPointF brushOrigin() const
Returns the brush origin in the current paint engine state.
Definition: qpainter.cpp:9287
void updateFont(const QFont &font)
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
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
Definition: qregion.cpp:4098
Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x)
#define QREAL_MAX
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
#define GL_PACK_SKIP_IMAGES
Qt::PenJoinStyle joinStyle() const
Returns the pen&#39;s join style.
Definition: qpen.cpp:736
Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b)
QFont font() const
Returns the font in the current paint engine state.
Definition: qpainter.cpp:9331
static void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
#define GL_TEXTURE1
#define GL_DECR_WRAP_EXT
void drawItem(const QDrawQueueItem &item)
void quadtreeUpdate(int channel, int node, int current_block_size)
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
QPainterPath getStrokedPath(const QPainterPath &path, const QPen &pen)
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
QSize size() const
Returns the size of the rectangle.
Definition: qrect.h:309
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
virtual QFixed ascent() const =0
void updateFragmentProgramData(int locations[])
QGLGlyphCoord * lookup(QFontEngine *, glyph_t)
qreal y1() const
Returns the y-coordinate of the line&#39;s start point.
Definition: qline.h:299
void quadtreeFindExistingLocation(const QSize &size, QRect *rect, int *channel)
QHash< glyph_t, QGLGlyphCoord * > QGLGlyphHash
virtual QFixed descent() const =0
The QPolygonF class provides a vector of points using floating point precision.
Definition: qpolygon.h:134
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
const T & value() const
Returns the current item&#39;s value.
Definition: qhash.h:420
Q_CORE_EXPORT void qWarning(const char *,...)
QPoint map(const QPoint &p) const
Creates and returns a QPoint object that is a copy of the given point, mapped into the coordinate sys...
Internal QTextItem.
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
int x2() const
Returns the x-coordinate of the line&#39;s end point.
Definition: qline.h:122
QPainter::CompositionMode compositionMode() const
Returns the composition mode in the current paint engine state.
Definition: qpainter.cpp:9503
QOpenGLPaintEnginePrivate * p
#define FloatToQuint64(i)
static const char * data(const QByteArray &arr)
bool isQBitmap() const
Returns true if this is a QBitmap; otherwise returns false.
Definition: qpixmap.cpp:599
QTransform::TransformationType txop
unsigned int uint
Definition: qglobal.h:996
static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables]
void drawTextItem(const QPointF &p, const QTextItem &ti)
This function draws the text item textItem at position p.
#define GL_TRIANGLE_FAN
const_iterator constFind(const Key &key) const
Returns an iterator pointing to the item with the key in the hash.
Definition: qhash.h:859
void setGradientOps(const QBrush &brush, const QRectF &bounds)
#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.
#define GL_FLOAT
GLuint getBuffer(const QGradient &gradient, qreal opacity, QGLContext *ctx)
#define GL_LUMINANCE_ALPHA
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QPaintDevice * device() const
Returns the paint device set for this context.
Definition: qgl.cpp:3507
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:68
T value(int i) const
Returns the value at index position i in the list.
Definition: qlist.h:661
void add(const Type &t)
Definition: qdatabuffer_p.h:93
virtual void setState(QPainterState *s)
The QPainterPathStroker class is used to generate fillable outlines for a given painter path...
Definition: qpainterpath.h:264
void drawPoints(const QPointF *p, int pointCount)
Draws the first pointCount points in the buffer points.
float toFloat(bool *ok=0) const
Returns the byte array converted to a float value.
void drawRects(const QRectF *r, int rectCount)
Draws the first rectCount rectangles in the buffer rects.
QPainterPath clipPath() const
Returns the clip path in the current paint engine state.
Definition: qpainter.cpp:9457
QGLPaintDevice * device
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition: qpen.cpp:797
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)=0
Qt::FillRule fillRule() const
Returns the painter path&#39;s currently set fill rule.
void drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags conversionFlags)
Reimplement this function to draw the part of the image specified by the sr rectangle in the given re...
QHash< QFontEngine *, QGLGlyphHash * > QGLFontGlyphHash
void * HANDLE
Definition: qnamespace.h:1671
Qt::BrushStyle style() const
Returns the brush style.
Definition: qbrush.h:182
QList< QDrawQueueItem > drawQueue
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
const Vertex * bottomRight
QOpenGLCoordinateOffset(QOpenGLPaintEnginePrivate *d)
QPixmap texture() const
Returns the custom brush pattern, or a null pixmap if no custom brush pattern has been set...
Definition: qbrush.cpp:785
#define GL_ZERO
void tessellate(const QPointF *points, int nPoints, bool winding)
handler setDevice(device)
QPainter::CompositionMode composition_mode
#define GL_LEQUAL
QByteArray mid(int index, int len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos...
int indexOf(char c, int from=0) const
Returns the index position of the first occurrence of the character ch in the byte array...
void setState(QPainterState *s)
QPointF start() const
Returns the start point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1796
#define glActiveStencilFaceEXT
void updateCompositionMode(QPainter::CompositionMode composition_mode)
#define GL_FRONT
int Q27Dot5
QRect toRect() const
Returns a QRect based on the values of this rectangle.
Definition: qrect.h:845
GLuint getProgram(const QGLContext *ctx, int brush, int mode, bool mask_mode)
static const char * mask_fragment_program_sources[num_fragment_masks]
#define Q_OBJECT
Definition: qobjectdefs.h:157
qreal y4
Definition: qbezier_p.h:116
QGLStrokeTableHash cache
#define glProgramLocalParameter4fvARB
uint hints() const
QPainter::CompositionMode composition_mode
#define glActiveTexture
Definition: glfunctions.h:69
void fill(const QVectorPath &path, const QBrush &brush)
void qSwap(T &value1, T &value2)
Definition: qglobal.h:2181
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
virtual QRect screenRect()=0
void generateGradientColorTable(const QGradient &g, uint *colorTable, int size, qreal opacity) const
#define GL_UNPACK_ALIGNMENT
#define GL_DEPTH_BUFFER_BIT
qreal m31() const
Returns the horizontal translation factor.
Definition: qtransform.h:261
#define GL_LINE_STRIP
#define GL_BLEND
void cleanupContext(const QGLContext *)
Q_CORE_EXPORT QTextStream & center(QTextStream &s)
virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
const QBrush & brush() const
Returns the painter&#39;s current brush.
Definition: qpainter.cpp:4232
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition: qpixmap.cpp:1080
void setPorterDuffData(float a, float b, float x, float y, float z)
bool isEmpty() const
Returns true if the rectangle is empty, otherwise returns false.
Definition: qrect.h:234
virtual void drawLines(const QLine *lines, int lineCount)
The default implementation converts the first lineCount lines in lines to a QLineF and calls the floa...
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:76
static bool isRect(const T *pts, int elementCount)
QFixed x
Definition: qfixed_p.h:190
const Vertex * topLeft
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:469
#define GL_TEXTURE_WRAP_T
#define GL_LINEAR
QGLTrapezoid(qreal top_, qreal bottom_, qreal topLeftX_, qreal topRightX_, qreal bottomLeftX_, qreal bottomRightX_)
void setPixel(int x, int y, uint index_or_rgb)
Sets the pixel index or color at (x, y) to index_or_rgb.
Definition: qimage.cpp:4311
static bool qt_nvidiaFboNeedsFinish
static void addQuadAsTriangle(GLfloat *quad, GLfloat *triangle)
void setY(int y)
Sets the y coordinate of this point to the given y coordinate.
Definition: qpoint.h:137
bool isValid() const
int top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:243
GLuint offscreenTexture() const
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
#define GL_TRIANGLES
void cleanupPrograms(const QGLContext *context)
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
static const unsigned int num_fragment_variables
ushort blue
Returns the blue color component of this color.
Definition: qcolor.h:245
QPainter::RenderHints renderHints() const
Returns the render hints in the current paint engine state.
Definition: qpainter.cpp:9488
void clip(const QVectorPath &path, Qt::ClipOperation op)
int right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:246
#define GL_BACK
FragmentBrushType
void updateBrush(const QBrush &brush, const QPointF &pt)
CacheInfo(const QPainterPath &p, const QTransform &m, qreal w=-1)
#define GL_DST_ALPHA
unsigned int GLenum
Definition: main.cpp:50
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:467
void cleanupGLContextRefs(const QGLContext *context)
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
Type type() const
Returns the type of gradient.
Definition: qbrush.h:232
static const struct @32 types[]
bool isSharing() const
Returns true if this context is sharing its GL context with another QGLContext, otherwise false is re...
Definition: qgl.cpp:3489
ushort alpha
Returns the alpha color component of this color.
Definition: qcolor.h:242
bool isValid() const
Returns true if a GL rendering context has been successfully created; otherwise returns false...
Definition: qgl.cpp:3477
The QLinearGradient class is used in combination with QBrush to specify a linear gradient brush...
Definition: qbrush.h:280
QPainterPath addCacheElement(quint64 hash_val, QPainterPath path, const QPen &pen)
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
int y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:255
The QGradient class is used in combination with QBrush to specify gradient fills. ...
Definition: qbrush.h:201
void lineToStencil(qreal x, qreal y)
const QGLTrapezoid translated(const QPointF &delta) const
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
unsigned short ushort
Definition: qglobal.h:995
void cacheItemErased(int channel, const QRect &rect)
QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition: qpoint.h:376
void setWidthF(qreal width)
Sets the pen width to the given width in pixels with floating point precision.
Definition: qpen.cpp:690
#define GL_UNSIGNED_BYTE
qreal miterLimit() const
Returns the miter limit of the pen.
Definition: qpen.cpp:589
InterpolationMode
Definition: qbrush.h:225
static const int y_margin
static void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform)
int x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:252
#define ctx
Definition: qgl.cpp:6094
FragmentCompositionModeType
static QTestResult::TestLocation location
Definition: qtestresult.cpp:63
int key
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
#define DEBUG_ONCE
QVector< QRect > rects() const
Returns an array of non-overlapping rectangles that make up the region.
Definition: qregion.cpp:4412
void setBrush(const QBrush &brush)
Sets the painter&#39;s brush to the given brush.
Definition: qpainter.cpp:4171
The QHash::iterator class provides an STL-style non-const iterator for QHash and QMultiHash.
Definition: qhash.h:330
#define GL_TEXTURE_RECTANGLE_NV
qreal x3
Definition: qbezier_p.h:116
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
bool isFastRect(const QRectF &r)
const qreal * points() const
qreal m23() const
Returns the vertical projection factor.
Definition: qtransform.h:257
static uint endianColor(uint c)
void quadtreeClear(int channel, const QRect &rect, int node=0)
void setPen(const QColor &color)
Sets the painter&#39;s pen to have style Qt::SolidLine, width 0 and the specified color.
Definition: qpainter.cpp:4047
static const QMetaObjectPrivate * priv(const uint *data)
#define GL_CULL_FACE
QPointF p2() const
Returns the line&#39;s end point.
Definition: qline.h:319
void createGradientPaletteTexture(const QGradient &g)
QPointF brushOrigin
Definition: qpainter_p.h:149
int height() const
Returns the height.
Definition: qsize.h:129
qreal widthF() const
Returns the pen width with floating point precision.
Definition: qpen.cpp:645
static const char * painter_fragment_program_sources[num_fragment_brushes][num_fragment_composition_modes]
#define GL_UNPACK_SKIP_IMAGES
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QTransform matrix() const
#define GL_FRAGMENT_PROGRAM_ARB
iterator begin()
Returns an STL-style iterator pointing to the first item in the hash.
Definition: qhash.h:464
QFactoryLoader * l
qreal x1
Definition: qbezier_p.h:116
CacheLocation getMask(QGLMaskGenerator &maskGenerator, QOpenGLPaintEnginePrivate *engine)
qreal radius() const
Returns the radius of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2150
FragmentCompositionModeType fragment_composition_mode
Spread spread() const
Returns the spread method use by this gradient.
Definition: qbrush.h:235
virtual void makeCurrent()
Makes this context the current OpenGL rendering context.
Definition: qgl_egl.cpp:213
qreal toReal() const
Definition: qfixed_p.h:77
QWExtra * extra
Definition: qwidget_p.h:700
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
void quadtreeAllocate(quint64 key, const QSize &size, QRect *rect, int *channel)
void createMask(quint64 key, CacheInfo &info, QGLMaskGenerator &maskGenerator)
void split(QBezier *firstHalf, QBezier *secondHalf) const
Definition: qbezier_p.h:224
void fillVertexArray(Qt::FillRule fillRule)
qreal dx() const
Returns the horizontal translation factor.
Definition: qtransform.h:273
static Extensions glExtensions()
Definition: qgl.cpp:5781
int y() const
Returns the y coordinate of this point.
Definition: qpoint.h:131
qreal x
the x coordinate of the element&#39;s position.
Definition: qpainterpath.h:79
static void drawPoints(const T *points, int n, const QTransform &transform, IDirectFBSurface *surface)
QSize offscreenSize() const
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 y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
void cacheGlyphs(QGLContext *, QFontEngine *, glyph_t *glyphs, int numGlyphs)
QPointF center() const
Returns the center of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2102
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
Adds a cubic Bezier curve between the current position and the given endPoint using the control point...
#define GL_FRONT_AND_BACK
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
typedef GLint
Definition: glfunctions.h:67
qreal y1
Definition: qbezier_p.h:116
#define GL_RGBA
QRegion clipRegion() const
Returns the clip region in the current paint engine state.
Definition: qpainter.cpp:9443
qreal top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:526
Q_STATIC_INLINE_FUNCTION int qt_div_255(int x)
qreal dashOffset() const
Returns the dash offset for the pen.
Definition: qpen.cpp:547
QPoint quadtreeLocation(int node)
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device...
Definition: qpainter.cpp:5619
int height() const
Returns the height of the pixmap.
Definition: qpixmap.cpp:645
QList< QAElement > lookup(const QList< QAInterface > &interfaces)
QGLRectMaskGenerator(const QPainterPath &path, const QTransform &matrix, QGLOffscreen &offscreen, GLuint maskFragmentProgram)
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
The QPaintEngineState class provides information about the active paint engine&#39;s current state...
Definition: qpaintengine.h:289
virtual QRect computeScreenRect()=0
void strokeLines(const QPainterPath &path)
bool begin(QPaintDevice *pdev)
Reimplement this function to initialise your paint engine when painting is to start on the paint devi...
QGLContext * context() const
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
T * data()
Returns a pointer to the data stored in the vector.
Definition: qvector.h:152
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
QBrush brush
Definition: qpainter_p.h:153
static QGLPaintDevice * getDevice(QPaintDevice *)
QTransform & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
Definition: qtransform.cpp:485
QGLProgramHash programs
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397
void cleanupGLContextRefs(const QGLContext *context)
QGLLineMaskGenerator(const QPainterPath &path, const QTransform &matrix, qreal width, QGLOffscreen &offscreen, GLuint maskFragmentProgram)
int y2() const
Returns the y-coordinate of the line&#39;s end point.
Definition: qline.h:127
int x() const
Returns the x coordinate of this point.
Definition: qpoint.h:128
static int mask_variable_locations[num_fragment_masks][num_fragment_variables]
QPen pen() const
Returns the pen in the current paint engine state.
Definition: qpainter.cpp:9259
virtual void drawRects(const QRect *rects, int rectCount)
The default implementation converts the first rectCount rectangles in the buffer rects to a QRectF an...
void tessellateRect(const QPointF &a, const QPointF &b, qreal width)
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition: qhash.h:865
void cleanupGLContextRefs(const QGLContext *context)
QGLPrivateCleanup(QOpenGLPaintEnginePrivate *priv)
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
static int grow(int size)
Definition: qlist.cpp:62
QFontDef fontDef
#define GL_TEXTURE_MAG_FILTER
QGLFramebufferObject * offscreen
void addTrap(const Trapezoid &trap)
static void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface)
static bool needsEmulation(Qt::BrushStyle style)
The QTextItem class provides all the information required to draw text in a custom paint engine...
Definition: qpaintengine.h:68
QRectF translated(qreal dx, qreal dy) const
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis...
Definition: qrect.h:740
QDataBuffer< QPointF > tess_points
QPixmap copy(int x, int y, int width, int height) const
Returns a deep copy of the subset of the pixmap that is specified by the rectangle QRect( x...
Definition: qpixmap.h:302
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.h:232
#define slots
Definition: qobjectdefs.h:68
void drawTextureRect(int tx_width, int tx_height, const QRectF &r, const QRectF &sr, GLenum target, QGLTexture *tex)
void fillPath(const QPainterPath &path)
Qt::PenCapStyle capStyle() const
Returns the pen&#39;s cap style.
Definition: qpen.cpp:706
bool qt_resolve_frag_program_extensions(QGLContext *ctx)
#define class
void composite(const QRectF &rect, const QPoint &maskOffset=QPoint())
static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy)
static const KeyPair *const end
#define GL_PACK_IMAGE_HEIGHT
qreal x1() const
Returns the x-coordinate of the line&#39;s start point.
Definition: qline.h:294
void updateRenderHints(QPainter::RenderHints hints)
int x1() const
Returns the x-coordinate of the line&#39;s start point.
Definition: qline.h:112
void qt_add_rect_to_array(const QRectF &r, GLfloat *array)
Definition: qgl.cpp:2972
CacheInfo(QPainterPath p, QPainterPath sp, QPen stroke_pen)
QImage textureImage() const
Returns the custom brush pattern, or a null image if no custom brush pattern has been set...
Definition: qbrush.cpp:829
void setDrawableSize(const QSize &drawableSize)
#define GL_ALWAYS
QMultiHash< quint64, CacheInfo > QGLStrokeTableHash
QMultiHash< quint64, CacheInfo > QGLGradientColorTableHash
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
QPointF center() const
Returns the center point of the rectangle.
Definition: qrect.h:686
void setX(int x)
Sets the x coordinate of this point to the given x coordinate.
Definition: qpoint.h:134
bool qt_resolve_stencil_face_extension(QGLContext *ctx)
qreal y3
Definition: qbezier_p.h:116
uint styleStrategy
Definition: qfont_p.h:92
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
ushort green
Returns the green color component of this color.
Definition: qcolor.h:244
qreal qSqrt(qreal v)
Definition: qmath.h:205
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
#define glProgramStringARB
#define GL_NO_ERROR
void curveToStencil(const QPointF &cp1, const QPointF &cp2, const QPointF &ep)
bool end()
Reimplement this function to finish painting on the current paint device.
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
virtual QVector< QGLTrapezoid > generateTrapezoids()=0
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition: qhash.h:648
#define glBindProgramARB
static void qt_delete_glyph_hash(QGLGlyphHash *hash)
QGLGlyphHash * current_cache
quint64 hash(const QPainterPath &p, const QTransform &m, qreal w)
static QPainterPath strokeForPath(const QPainterPath &path, const QPen &cpen)
void updatePen(const QPen &pen)
unsigned int glyph_t
void drawEllipse(const QRectF &rect)
Reimplement this function to draw the largest ellipse that can be contained within rectangle rect...
QRgb rgb() const
Returns the RGB value of the color.
Definition: qcolor.cpp:1051
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
#define GL_REPLACE
virtual void drawEllipse(const QRectF &r)
Reimplement this function to draw the largest ellipse that can be contained within rectangle rect...
QGLGradientColorTableHash cache
Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
bool end()
Ends painting.
Definition: qpainter.cpp:1929
void setGLBrush(const QColor &c)
qreal m11() const
Returns the horizontal scaling factor.
Definition: qtransform.h:237
void qgl_cleanup_glyph_cache(QGLContext *ctx)
qreal m33() const
Returns the division factor.
Definition: qtransform.h:269
void addEllipse(const QRectF &rect)
Creates an ellipse within the specified boundingRectangle and adds it to the painter path as a closed...
#define GL_ONE
void drawTiledImageAsPath(const QRectF &r, const QImage &img, qreal sx, qreal sy, const QPointF &offset)
static const T qSubImage(const T &image, const QRectF &src, QRectF *srcNew)
#define GL_KEEP
int size() const
static qreal toReal(Register *reg, int type, bool *ok=0)
QPointF finalStop() const
Returns the final stop point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1856
void setGLPen(const QColor &c)
void updateGradient(const QBrush &brush, const QRectF &bounds)
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
static bool needsResolving(const QBrush &brush)
Definition: qpainter.cpp:7339
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
void drawFastRect(const QRectF &rect)
QPainterPath path() const
QScopedPointer< QPainterPrivate > d_ptr
Definition: qpainter.h:546
static const int x_margin
QPoint topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:288
ClipOperation
Definition: qnamespace.h:1495
#define GL_NEAREST
glyph_t * glyphs
Hint shape() const
QMultiHash< const QGLContext *, GLProgram > QGLProgramHash
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