source: trunk/src/gui/painting/qpainter.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 249.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41// QtCore
42#include <qdebug.h>
43#include <qmath.h>
44#include <qmutex.h>
45
46// QtGui
47#include "qbitmap.h"
48#include "qimage.h"
49#include "qpaintdevice.h"
50#include "qpaintengine.h"
51#include "qpainter.h"
52#include "qpainter_p.h"
53#include "qpainterpath.h"
54#include "qpicture.h"
55#include "qpixmapcache.h"
56#include "qpolygon.h"
57#include "qtextlayout.h"
58#include "qwidget.h"
59#include "qapplication.h"
60#include "qstyle.h"
61#include "qthread.h"
62#include "qvarlengtharray.h"
63
64#include <private/qfontengine_p.h>
65#include <private/qpaintengine_p.h>
66#include <private/qemulationpaintengine_p.h>
67#include <private/qpainterpath_p.h>
68#include <private/qtextengine_p.h>
69#include <private/qwidget_p.h>
70#include <private/qpaintengine_raster_p.h>
71#include <private/qmath_p.h>
72
73QT_BEGIN_NAMESPACE
74
75#define QGradient_StretchToDevice 0x10000000
76#define QPaintEngine_OpaqueBackground 0x40000000
77
78// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
79static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
80
81// #define QT_DEBUG_DRAW
82#ifdef QT_DEBUG_DRAW
83bool qt_show_painter_debug_output = true;
84#endif
85
86extern QPixmap qt_pixmapForBrush(int style, bool invert);
87
88void qt_format_text(const QFont &font,
89 const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
90 int tabstops, int* tabarray, int tabarraylen,
91 QPainter *painter);
92
93static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
94{
95 switch (brush.style()) {
96 case Qt::LinearGradientPattern:
97 case Qt::RadialGradientPattern:
98 case Qt::ConicalGradientPattern:
99 return brush.gradient()->coordinateMode();
100 default:
101 ;
102 }
103 return QGradient::LogicalMode;
104}
105
106/* Returns true if the gradient requires stretch to device...*/
107static inline bool check_gradient(const QBrush &brush)
108{
109 return coordinateMode(brush) == QGradient::StretchToDeviceMode;
110}
111
112extern bool qHasPixmapTexture(const QBrush &);
113
114static inline bool is_brush_transparent(const QBrush &brush) {
115 Qt::BrushStyle s = brush.style();
116 bool brushBitmap = qHasPixmapTexture(brush)
117 ? brush.texture().isQBitmap()
118 : (brush.textureImage().depth() == 1);
119 return ((s >= Qt::Dense1Pattern && s <= Qt::DiagCrossPattern)
120 || (s == Qt::TexturePattern && brushBitmap));
121}
122
123static inline bool is_pen_transparent(const QPen &pen) {
124 return pen.style() > Qt::SolidLine || is_brush_transparent(pen.brush());
125}
126
127/* Discards the emulation flags that are not relevant for line drawing
128 and returns the result
129*/
130static inline uint line_emulation(uint emulation)
131{
132 return emulation & (QPaintEngine::PrimitiveTransform
133 | QPaintEngine::AlphaBlend
134 | QPaintEngine::Antialiasing
135 | QPaintEngine::BrushStroke
136 | QPaintEngine::ConstantOpacity
137 | QGradient_StretchToDevice
138 | QPaintEngine::ObjectBoundingModeGradients
139 | QPaintEngine_OpaqueBackground);
140}
141
142#ifndef QT_NO_DEBUG
143static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false)
144{
145 switch (devType) {
146 case QInternal::Image:
147 case QInternal::Printer:
148 case QInternal::Picture:
149 // can be drawn onto these devices safely from any thread
150#ifndef Q_WS_WIN
151 if (extraCondition)
152#endif
153 break;
154 default:
155 if (!extraCondition && QThread::currentThread() != qApp->thread()) {
156 qWarning("QPainter: It is not safe to use %s outside the GUI thread", what);
157 return false;
158 }
159 break;
160 }
161 return true;
162}
163#endif
164
165void QPainterPrivate::checkEmulation()
166{
167 Q_ASSERT(extended);
168 bool doEmulation = false;
169 if (state->bgMode == Qt::OpaqueMode)
170 doEmulation = true;
171
172 const QGradient *bg = state->brush.gradient();
173 if (bg && bg->coordinateMode() > QGradient::LogicalMode)
174 doEmulation = true;
175
176 const QGradient *pg = qpen_brush(state->pen).gradient();
177 if (pg && pg->coordinateMode() > QGradient::LogicalMode)
178 doEmulation = true;
179
180 if (doEmulation) {
181 if (extended != emulationEngine) {
182 if (!emulationEngine)
183 emulationEngine = new QEmulationPaintEngine(extended);
184 extended = emulationEngine;
185 extended->setState(state);
186 }
187 } else if (emulationEngine && emulationEngine != extended) {
188 extended = emulationEngine->real_engine;
189 }
190}
191
192
193QPainterPrivate::~QPainterPrivate()
194{
195 delete emulationEngine;
196 for (int i=0; i<states.size(); ++i)
197 delete states.at(i);
198
199 if (dummyState)
200 delete dummyState;
201}
202
203
204QTransform QPainterPrivate::viewTransform() const
205{
206 if (state->VxF) {
207 qreal scaleW = qreal(state->vw)/qreal(state->ww);
208 qreal scaleH = qreal(state->vh)/qreal(state->wh);
209 return QTransform(scaleW, 0, 0, scaleH,
210 state->vx - state->wx*scaleW, state->vy - state->wy*scaleH);
211 }
212 return QTransform();
213}
214
215
216/*
217 \internal
218 Returns true if using a shared painter; otherwise false.
219*/
220bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
221{
222 Q_ASSERT(q);
223 Q_ASSERT(pdev);
224
225 if (pdev->devType() != QInternal::Widget)
226 return false;
227
228 QWidget *widget = static_cast<QWidget *>(pdev);
229 Q_ASSERT(widget);
230
231 // Someone either called QPainter::setRedirected in the widget's paint event
232 // right before this painter was created (or begin was called) or
233 // sent a paint event directly to the widget.
234 if (!widget->d_func()->redirectDev)
235 return false;
236
237 QPainter *sp = widget->d_func()->sharedPainter();
238 if (!sp || !sp->isActive())
239 return false;
240
241 if (sp->paintEngine()->paintDevice() != widget->d_func()->redirectDev)
242 return false;
243
244 // Check if we're attempting to paint outside a paint event.
245 if (!sp->d_ptr->engine->hasFeature(QPaintEngine::PaintOutsidePaintEvent)
246 && !widget->testAttribute(Qt::WA_PaintOutsidePaintEvent)
247 && !widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
248
249 qWarning("QPainter::begin: Widget painting can only begin as a result of a paintEvent");
250 return false;
251 }
252
253 // Save the current state of the shared painter and assign
254 // the current d_ptr to the shared painter's d_ptr.
255 sp->save();
256 if (!sp->d_ptr->d_ptrs) {
257 // Allocate space for 4 d-pointers (enough for up to 4 sub-sequent
258 // redirections within the same paintEvent(), which should be enough
259 // in 99% of all cases). E.g: A renders B which renders C which renders D.
260 sp->d_ptr->d_ptrs_size = 4;
261 sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *));
262 } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) {
263 // However, to support corner cases we grow the array dynamically if needed.
264 sp->d_ptr->d_ptrs_size <<= 1;
265 const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *);
266 sp->d_ptr->d_ptrs = (QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize);
267 }
268 sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr;
269 q->d_ptr = sp->d_ptr;
270
271 Q_ASSERT(q->d_ptr->state);
272
273 // Now initialize the painter with correct widget properties.
274 q->initFrom(widget);
275 QPoint offset;
276 widget->d_func()->redirected(&offset);
277 offset += q->d_ptr->engine->coordinateOffset();
278
279 // Update system rect.
280 q->d_ptr->state->ww = q->d_ptr->state->vw = widget->width();
281 q->d_ptr->state->wh = q->d_ptr->state->vh = widget->height();
282
283 // Update matrix.
284 if (q->d_ptr->state->WxF)
285 q->d_ptr->state->worldMatrix.translate(-offset.x(), -offset.y());
286 else
287 q->d_ptr->state->redirection_offset = offset;
288 q->d_ptr->updateMatrix();
289
290 QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
291 if (enginePrivate->currentClipWidget == widget) {
292 enginePrivate->systemStateChanged();
293 return true;
294 }
295
296 // Update system transform and clip.
297 enginePrivate->currentClipWidget = widget;
298 enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
299 return true;
300}
301
302void QPainterPrivate::detachPainterPrivate(QPainter *q)
303{
304 Q_ASSERT(refcount > 1);
305 Q_ASSERT(q);
306
307 QPainterPrivate *original = d_ptrs[--refcount - 1];
308 if (inDestructor) {
309 inDestructor = false;
310 if (original)
311 original->inDestructor = true;
312 } else if (!original) {
313 original = new QPainterPrivate(q);
314 }
315
316 d_ptrs[refcount - 1] = 0;
317 q->restore();
318 q->d_ptr = original;
319
320 if (emulationEngine) {
321 extended = emulationEngine->real_engine;
322 delete emulationEngine;
323 emulationEngine = 0;
324 }
325}
326
327
328void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperation op)
329{
330#ifdef QT_DEBUG_DRAW
331 if (qt_show_painter_debug_output) {
332 printf("QPainter::drawHelper\n");
333 }
334#endif
335
336 if (originalPath.isEmpty())
337 return;
338
339 QPaintEngine::PaintEngineFeatures gradientStretch =
340 QPaintEngine::PaintEngineFeatures(QGradient_StretchToDevice
341 | QPaintEngine::ObjectBoundingModeGradients);
342
343 const bool mustEmulateObjectBoundingModeGradients = extended
344 || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
345 && !engine->hasFeature(QPaintEngine::PatternTransform));
346
347 if (!(state->emulationSpecifier & ~gradientStretch)
348 && !mustEmulateObjectBoundingModeGradients) {
349 drawStretchedGradient(originalPath, op);
350 return;
351 } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) {
352 drawOpaqueBackground(originalPath, op);
353 return;
354 }
355
356 Q_Q(QPainter);
357
358 qreal strokeOffsetX = 0, strokeOffsetY = 0;
359
360 QPainterPath path = originalPath * state->matrix;
361 QRectF pathBounds = path.boundingRect();
362 QRectF strokeBounds;
363 bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
364 if (doStroke) {
365 qreal penWidth = state->pen.widthF();
366 if (penWidth == 0) {
367 strokeOffsetX = 1;
368 strokeOffsetY = 1;
369 } else {
370 // In case of complex xform
371 if (state->matrix.type() > QTransform::TxScale) {
372 QPainterPathStroker stroker;
373 stroker.setWidth(penWidth);
374 stroker.setJoinStyle(state->pen.joinStyle());
375 stroker.setCapStyle(state->pen.capStyle());
376 QPainterPath stroke = stroker.createStroke(originalPath);
377 strokeBounds = (stroke * state->matrix).boundingRect();
378 } else {
379 strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
380 strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
381 }
382 }
383 }
384
385 QRect absPathRect;
386 if (!strokeBounds.isEmpty()) {
387 absPathRect = strokeBounds.intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
388 } else {
389 absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
390 .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
391 }
392
393 if (q->hasClipping()) {
394 bool hasPerspectiveTransform = false;
395 for (int i = 0; i < state->clipInfo.size(); ++i) {
396 const QPainterClipInfo &info = state->clipInfo.at(i);
397 if (info.matrix.type() == QTransform::TxProject) {
398 hasPerspectiveTransform = true;
399 break;
400 }
401 }
402 // avoid mapping QRegions with perspective transforms
403 if (!hasPerspectiveTransform) {
404 // The trick with txinv and invMatrix is done in order to
405 // avoid transforming the clip to logical coordinates, and
406 // then back to device coordinates. This is a problem with
407 // QRegion/QRect based clips, since they use integer
408 // coordinates and converting to/from logical coordinates will
409 // lose precision.
410 bool old_txinv = txinv;
411 QTransform old_invMatrix = invMatrix;
412 txinv = true;
413 invMatrix = QTransform().translate(-state->redirection_offset.x(), -state->redirection_offset.y());
414 QPainterPath clipPath = q->clipPath();
415 QRectF r = clipPath.boundingRect().intersected(absPathRect);
416 absPathRect = r.toAlignedRect();
417 txinv = old_txinv;
418 invMatrix = old_invMatrix;
419 }
420 }
421
422// qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",
423// devMinX, devMinY, device->width(), device->height());
424// qDebug() << " - matrix" << state->matrix;
425// qDebug() << " - originalPath.bounds" << originalPath.boundingRect();
426// qDebug() << " - path.bounds" << path.boundingRect();
427
428 if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
429 return;
430
431 QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
432 image.fill(0);
433
434 QPainter p(&image);
435
436 p.d_ptr->helper_device = helper_device;
437
438 p.setOpacity(state->opacity);
439 p.translate(-absPathRect.x(), -absPathRect.y());
440 p.setTransform(state->matrix, true);
441 p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
442 p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
443 p.setBackground(state->bgBrush);
444 p.setBackgroundMode(state->bgMode);
445 p.setBrushOrigin(state->brushOrigin);
446
447 p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
448 p.setRenderHint(QPainter::SmoothPixmapTransform,
449 state->renderHints & QPainter::SmoothPixmapTransform);
450
451 p.drawPath(originalPath);
452
453#ifndef QT_NO_DEBUG
454 static bool do_fallback_overlay = qgetenv("QT_PAINT_FALLBACK_OVERLAY").size() > 0;
455 if (do_fallback_overlay) {
456 QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
457 QPainter pt(&block);
458 pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
459 pt.drawLine(0, 0, 8, 8);
460 pt.end();
461 p.resetTransform();
462 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
463 p.setOpacity(0.5);
464 p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
465 }
466#endif
467
468 p.end();
469
470 q->save();
471 q->resetMatrix();
472 updateState(state);
473 engine->drawImage(absPathRect,
474 image,
475 QRectF(0, 0, absPathRect.width(), absPathRect.height()),
476 Qt::OrderedDither | Qt::OrderedAlphaDither);
477 q->restore();
478}
479
480void QPainterPrivate::drawOpaqueBackground(const QPainterPath &path, DrawOperation op)
481{
482 Q_Q(QPainter);
483
484 q->setBackgroundMode(Qt::TransparentMode);
485
486 if (op & FillDraw && state->brush.style() != Qt::NoBrush) {
487 q->fillPath(path, state->bgBrush.color());
488 q->fillPath(path, state->brush);
489 }
490
491 if (op & StrokeDraw && state->pen.style() != Qt::NoPen) {
492 q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width()));
493 q->strokePath(path, state->pen);
494 }
495
496 q->setBackgroundMode(Qt::OpaqueMode);
497}
498
499static inline QBrush stretchGradientToUserSpace(const QBrush &brush, const QRectF &boundingRect)
500{
501 Q_ASSERT(brush.style() >= Qt::LinearGradientPattern
502 && brush.style() <= Qt::ConicalGradientPattern);
503
504 QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
505 boundingRect.x(), boundingRect.y());
506
507 QGradient g = *brush.gradient();
508 g.setCoordinateMode(QGradient::LogicalMode);
509
510 QBrush b(g);
511 b.setTransform(gradientToUser * b.transform());
512 return b;
513}
514
515void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperation op)
516{
517 Q_Q(QPainter);
518
519 const qreal sw = helper_device->width();
520 const qreal sh = helper_device->height();
521
522 bool changedPen = false;
523 bool changedBrush = false;
524 bool needsFill = false;
525
526 const QPen pen = state->pen;
527 const QBrush brush = state->brush;
528
529 const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
530 const QGradient::CoordinateMode brushMode = coordinateMode(brush);
531
532 QRectF boundingRect;
533
534 // Draw the xformed fill if the brush is a stretch gradient.
535 if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
536 if (brushMode == QGradient::StretchToDeviceMode) {
537 q->setPen(Qt::NoPen);
538 changedPen = pen.style() != Qt::NoPen;
539 q->scale(sw, sh);
540 updateState(state);
541
542 const qreal isw = 1.0 / sw;
543 const qreal ish = 1.0 / sh;
544 QTransform inv(isw, 0, 0, ish, 0, 0);
545 engine->drawPath(path * inv);
546 q->scale(isw, ish);
547 } else {
548 needsFill = true;
549
550 if (brushMode == QGradient::ObjectBoundingMode) {
551 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
552 boundingRect = path.boundingRect();
553 q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
554 changedBrush = true;
555 }
556 }
557 }
558
559 if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
560 // Draw the xformed outline if the pen is a stretch gradient.
561 if (penMode == QGradient::StretchToDeviceMode) {
562 q->setPen(Qt::NoPen);
563 changedPen = true;
564
565 if (needsFill) {
566 updateState(state);
567 engine->drawPath(path);
568 }
569
570 q->scale(sw, sh);
571 q->setBrush(pen.brush());
572 changedBrush = true;
573 updateState(state);
574
575 QPainterPathStroker stroker;
576 stroker.setDashPattern(pen.style());
577 stroker.setWidth(pen.widthF());
578 stroker.setJoinStyle(pen.joinStyle());
579 stroker.setCapStyle(pen.capStyle());
580 stroker.setMiterLimit(pen.miterLimit());
581 QPainterPath stroke = stroker.createStroke(path);
582
583 const qreal isw = 1.0 / sw;
584 const qreal ish = 1.0 / sh;
585 QTransform inv(isw, 0, 0, ish, 0, 0);
586 engine->drawPath(stroke * inv);
587 q->scale(isw, ish);
588 } else {
589 if (!needsFill && brush.style() != Qt::NoBrush) {
590 q->setBrush(Qt::NoBrush);
591 changedBrush = true;
592 }
593
594 if (penMode == QGradient::ObjectBoundingMode) {
595 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
596
597 // avoid computing the bounding rect twice
598 if (!needsFill || brushMode != QGradient::ObjectBoundingMode)
599 boundingRect = path.boundingRect();
600
601 QPen p = pen;
602 p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
603 q->setPen(p);
604 changedPen = true;
605 } else if (changedPen) {
606 q->setPen(pen);
607 changedPen = false;
608 }
609
610 updateState(state);
611 engine->drawPath(path);
612 }
613 } else if (needsFill) {
614 if (pen.style() != Qt::NoPen) {
615 q->setPen(Qt::NoPen);
616 changedPen = true;
617 }
618
619 updateState(state);
620 engine->drawPath(path);
621 }
622
623 if (changedPen)
624 q->setPen(pen);
625 if (changedBrush)
626 q->setBrush(brush);
627}
628
629
630void QPainterPrivate::updateMatrix()
631{
632 state->matrix = state->WxF ? state->worldMatrix : QTransform();
633 if (state->VxF)
634 state->matrix *= viewTransform();
635
636 txinv = false; // no inverted matrix
637 if (!state->redirection_offset.isNull()) {
638 // We want to translate in dev space so we do the adding of the redirection
639 // offset manually.
640 if (state->matrix.isAffine()) {
641 state->matrix = QTransform(state->matrix.m11(), state->matrix.m12(),
642 state->matrix.m21(), state->matrix.m22(),
643 state->matrix.dx()-state->redirection_offset.x(),
644 state->matrix.dy()-state->redirection_offset.y());
645 } else {
646 QTransform temp;
647 temp.translate(-state->redirection_offset.x(), -state->redirection_offset.y());
648 state->matrix *= temp;
649 }
650 }
651 if (extended)
652 extended->transformChanged();
653 else
654 state->dirtyFlags |= QPaintEngine::DirtyTransform;
655
656// printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
657// qDebug() << " --- using matrix" << state->matrix << redirection_offset;
658}
659
660/*! \internal */
661void QPainterPrivate::updateInvMatrix()
662{
663 Q_ASSERT(txinv == false);
664 txinv = true; // creating inverted matrix
665 QTransform m;
666
667 if (state->VxF)
668 m = viewTransform();
669
670 if (state->WxF) {
671 if (state->VxF)
672 m = state->worldMatrix * m;
673 else
674 m = state->worldMatrix;
675 }
676 invMatrix = m.inverted(); // invert matrix
677}
678
679void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
680{
681 bool alpha = false;
682 bool linearGradient = false;
683 bool radialGradient = false;
684 bool conicalGradient = false;
685 bool patternBrush = false;
686 bool xform = false;
687 bool complexXform = false;
688
689 bool skip = true;
690
691 // Pen and brush properties (we have to check both if one changes because the
692 // one that's unchanged can still be in a state which requires emulation)
693 if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
694 // Check Brush stroke emulation
695 if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
696 s->emulationSpecifier |= QPaintEngine::BrushStroke;
697 else
698 s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
699
700 skip = false;
701
702 QBrush penBrush = s->pen.brush();
703 Qt::BrushStyle brushStyle = s->brush.style();
704 Qt::BrushStyle penBrushStyle = penBrush.style();
705 alpha = (penBrushStyle != Qt::NoBrush
706 && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
707 && !penBrush.isOpaque())
708 || (brushStyle != Qt::NoBrush
709 && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
710 && !s->brush.isOpaque());
711 linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
712 (brushStyle == Qt::LinearGradientPattern));
713 radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
714 (brushStyle == Qt::RadialGradientPattern));
715 conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
716 (brushStyle == Qt::ConicalGradientPattern));
717 patternBrush = (((penBrushStyle > Qt::SolidPattern
718 && penBrushStyle < Qt::LinearGradientPattern)
719 || penBrushStyle == Qt::TexturePattern) ||
720 ((brushStyle > Qt::SolidPattern
721 && brushStyle < Qt::LinearGradientPattern)
722 || brushStyle == Qt::TexturePattern));
723
724 bool penTextureAlpha = false;
725 if (penBrush.style() == Qt::TexturePattern)
726 penTextureAlpha = qHasPixmapTexture(penBrush)
727 ? penBrush.texture().hasAlpha()
728 : penBrush.textureImage().hasAlphaChannel();
729 bool brushTextureAlpha = false;
730 if (s->brush.style() == Qt::TexturePattern)
731 brushTextureAlpha = qHasPixmapTexture(s->brush)
732 ? s->brush.texture().hasAlpha()
733 : s->brush.textureImage().hasAlphaChannel();
734 if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
735 || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
736 && !engine->hasFeature(QPaintEngine::MaskedBrush))
737 s->emulationSpecifier |= QPaintEngine::MaskedBrush;
738 else
739 s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
740 }
741
742 if (s->state() & (QPaintEngine::DirtyHints
743 | QPaintEngine::DirtyOpacity
744 | QPaintEngine::DirtyBackgroundMode)) {
745 skip = false;
746 }
747
748 if (skip)
749 return;
750
751#if 0
752 qDebug("QPainterPrivate::updateEmulationSpecifier, state=%p\n"
753 " - alpha: %d\n"
754 " - linearGradient: %d\n"
755 " - radialGradient: %d\n"
756 " - conicalGradient: %d\n"
757 " - patternBrush: %d\n"
758 " - hints: %x\n"
759 " - xform: %d\n",
760 s,
761 alpha,
762 linearGradient,
763 radialGradient,
764 conicalGradient,
765 patternBrush,
766 uint(s->renderHints),
767 xform);
768#endif
769
770 // XForm properties
771 if (s->state() & QPaintEngine::DirtyTransform) {
772 xform = !s->matrix.isIdentity();
773 complexXform = !s->matrix.isAffine();
774 } else if (s->matrix.type() >= QTransform::TxTranslate) {
775 xform = true;
776 complexXform = !s->matrix.isAffine();
777 }
778
779 const bool brushXform = (!s->brush.transform().type() == QTransform::TxNone);
780 const bool penXform = (!s->pen.brush().transform().type() == QTransform::TxNone);
781
782 const bool patternXform = patternBrush && (xform || brushXform || penXform);
783
784 // Check alphablending
785 if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
786 s->emulationSpecifier |= QPaintEngine::AlphaBlend;
787 else
788 s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
789
790 // Linear gradient emulation
791 if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
792 s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
793 else
794 s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
795
796 // Radial gradient emulation
797 if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))
798 s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
799 else
800 s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
801
802 // Conical gradient emulation
803 if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
804 s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
805 else
806 s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
807
808 // Pattern brushes
809 if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
810 s->emulationSpecifier |= QPaintEngine::PatternBrush;
811 else
812 s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
813
814 // Pattern XForms
815 if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
816 s->emulationSpecifier |= QPaintEngine::PatternTransform;
817 else
818 s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
819
820 // Primitive XForms
821 if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
822 s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
823 else
824 s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
825
826 // Perspective XForms
827 if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
828 s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
829 else
830 s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
831
832 // Constant opacity
833 if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
834 s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
835 else
836 s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
837
838 bool gradientStretch = false;
839 bool objectBoundingMode = false;
840 if (linearGradient || conicalGradient || radialGradient) {
841 QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
842 QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
843
844 gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
845 gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
846
847 objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode);
848 objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode);
849 }
850 if (gradientStretch)
851 s->emulationSpecifier |= QGradient_StretchToDevice;
852 else
853 s->emulationSpecifier &= ~QGradient_StretchToDevice;
854
855 if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
856 s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
857 else
858 s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
859
860 // Opaque backgrounds...
861 if (s->bgMode == Qt::OpaqueMode &&
862 (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
863 s->emulationSpecifier |= QPaintEngine_OpaqueBackground;
864 else
865 s->emulationSpecifier &= ~QPaintEngine_OpaqueBackground;
866
867#if 0
868 //won't be correct either way because the device can already have
869 // something rendered to it in which case subsequent emulation
870 // on a fully transparent qimage and then blitting the results
871 // won't produce correct results
872 // Blend modes
873 if (state->composition_mode > QPainter::CompositionMode_Xor &&
874 !engine->hasFeature(QPaintEngine::BlendModes))
875 s->emulationSpecifier |= QPaintEngine::BlendModes;
876 else
877 s->emulationSpecifier &= ~QPaintEngine::BlendModes;
878#endif
879}
880
881void QPainterPrivate::updateStateImpl(QPainterState *newState)
882{
883 // ### we might have to call QPainter::begin() here...
884 if (!engine->state) {
885 engine->state = newState;
886 engine->setDirty(QPaintEngine::AllDirty);
887 }
888
889 if (engine->state->painter() != newState->painter)
890 // ### this could break with clip regions vs paths.
891 engine->setDirty(QPaintEngine::AllDirty);
892
893 // Upon restore, revert all changes since last save
894 else if (engine->state != newState)
895 newState->dirtyFlags |= QPaintEngine::DirtyFlags(static_cast<QPainterState *>(engine->state)->changeFlags);
896
897 // We need to store all changes made so that restore can deal with them
898 else
899 newState->changeFlags |= newState->dirtyFlags;
900
901 updateEmulationSpecifier(newState);
902
903 // Unset potential dirty background mode
904 newState->dirtyFlags &= ~(QPaintEngine::DirtyBackgroundMode
905 | QPaintEngine::DirtyBackground);
906
907 engine->state = newState;
908 engine->updateState(*newState);
909 engine->clearDirty(QPaintEngine::AllDirty);
910
911}
912
913void QPainterPrivate::updateState(QPainterState *newState)
914{
915
916 if (!newState) {
917 engine->state = newState;
918
919 } else if (newState->state() || engine->state!=newState) {
920 bool setNonCosmeticPen = (newState->renderHints & QPainter::NonCosmeticDefaultPen)
921 && newState->pen.widthF() == 0;
922 if (setNonCosmeticPen) {
923 // Override the default pen's cosmetic state if the
924 // NonCosmeticDefaultPen render hint is used.
925 QPen oldPen = newState->pen;
926 newState->pen.setWidth(1);
927 newState->pen.setCosmetic(false);
928 newState->dirtyFlags |= QPaintEngine::DirtyPen;
929
930 updateStateImpl(newState);
931
932 // Restore the state pen back to its default to preserve visible
933 // state.
934 newState->pen = oldPen;
935 } else {
936 updateStateImpl(newState);
937 }
938 }
939}
940
941
942/*!
943 \class QPainter
944 \brief The QPainter class performs low-level painting on widgets and
945 other paint devices.
946
947 \ingroup multimedia
948 \mainclass
949 \reentrant
950
951 QPainter provides highly optimized functions to do most of the
952 drawing GUI programs require. It can draw everything from simple
953 lines to complex shapes like pies and chords. It can also draw
954 aligned text and pixmaps. Normally, it draws in a "natural"
955 coordinate system, but it can also do view and world
956 transformation. QPainter can operate on any object that inherits
957 the QPaintDevice class.
958
959 The common use of QPainter is inside a widget's paint event:
960 Construct and customize (e.g. set the pen or the brush) the
961 painter. Then draw. Remember to destroy the QPainter object after
962 drawing. For example:
963
964 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 0
965
966 The core functionality of QPainter is drawing, but the class also
967 provide several functions that allows you to customize QPainter's
968 settings and its rendering quality, and others that enable
969 clipping. In addition you can control how different shapes are
970 merged together by specifying the painter's composition mode.
971
972 The isActive() function indicates whether the painter is active. A
973 painter is activated by the begin() function and the constructor
974 that takes a QPaintDevice argument. The end() function, and the
975 destructor, deactivates it.
976
977 Together with the QPaintDevice and QPaintEngine classes, QPainter
978 form the basis for Qt's paint system. QPainter is the class used
979 to perform drawing operations. QPaintDevice represents a device
980 that can be painted on using a QPainter. QPaintEngine provides the
981 interface that the painter uses to draw onto different types of
982 devices. If the painter is active, device() returns the paint
983 device on which the painter paints, and paintEngine() returns the
984 paint engine that the painter is currently operating on. For more
985 information, see \l {The Paint System} documentation.
986
987 Sometimes it is desirable to make someone else paint on an unusual
988 QPaintDevice. QPainter supports a static function to do this,
989 setRedirected().
990
991 \warning When the paintdevice is a widget, QPainter can only be
992 used inside a paintEvent() function or in a function called by
993 paintEvent(); that is unless the Qt::WA_PaintOutsidePaintEvent
994 widget attribute is set. On Mac OS X and Windows, you can only
995 paint in a paintEvent() function regardless of this attribute's
996 setting.
997
998 \tableofcontents
999
1000 \section1 Settings
1001
1002 There are several settings that you can customize to make QPainter
1003 draw according to your preferences:
1004
1005 \list
1006
1007 \o font() is the font used for drawing text. If the painter
1008 isActive(), you can retrieve information about the currently set
1009 font, and its metrics, using the fontInfo() and fontMetrics()
1010 functions respectively.
1011
1012 \o brush() defines the color or pattern that is used for filling
1013 shapes.
1014
1015 \o pen() defines the color or stipple that is used for drawing
1016 lines or boundaries.
1017
1018 \o backgroundMode() defines whether there is a background() or
1019 not, i.e it is either Qt::OpaqueMode or Qt::TransparentMode.
1020
1021 \o background() only applies when backgroundMode() is \l
1022 Qt::OpaqueMode and pen() is a stipple. In that case, it
1023 describes the color of the background pixels in the stipple.
1024
1025 \o brushOrigin() defines the origin of the tiled brushes, normally
1026 the origin of widget's background.
1027
1028 \o viewport(), window(), worldMatrix() make up the painter's coordinate
1029 transformation system. For more information, see the \l
1030 {Coordinate Transformations} section and the \l {The Coordinate
1031 System} documentation.
1032
1033 \o hasClipping() tells whether the painter clips at all. (The paint
1034 device clips, too.) If the painter clips, it clips to clipRegion().
1035
1036 \o layoutDirection() defines the layout direction used by the
1037 painter when drawing text.
1038
1039 \o matrixEnabled() tells whether world transformation is enabled.
1040
1041 \o viewTransformEnabled() tells whether view transformation is
1042 enabled.
1043
1044 \endlist
1045
1046 Note that some of these settings mirror settings in some paint
1047 devices, e.g. QWidget::font(). The QPainter::begin() function (or
1048 equivalently the QPainter constructor) copies these attributes
1049 from the paint device.
1050
1051 You can at any time save the QPainter's state by calling the
1052 save() function which saves all the available settings on an
1053 internal stack. The restore() function pops them back.
1054
1055 \section1 Drawing
1056
1057 QPainter provides functions to draw most primitives: drawPoint(),
1058 drawPoints(), drawLine(), drawRect(), drawRoundedRect(),
1059 drawEllipse(), drawArc(), drawPie(), drawChord(), drawPolyline(),
1060 drawPolygon(), drawConvexPolygon() and drawCubicBezier(). The two
1061 convenience functions, drawRects() and drawLines(), draw the given
1062 number of rectangles or lines in the given array of \l
1063 {QRect}{QRects} or \l {QLine}{QLines} using the current pen and
1064 brush.
1065
1066 The QPainter class also provides the fillRect() function which
1067 fills the given QRect, with the given QBrush, and the eraseRect()
1068 function that erases the area inside the given rectangle.
1069
1070 All of these functions have both integer and floating point
1071 versions.
1072
1073 \table 100%
1074 \row
1075 \o \inlineimage qpainter-basicdrawing.png
1076 \o
1077 \bold {Basic Drawing Example}
1078
1079 The \l {painting/basicdrawing}{Basic Drawing} example shows how to
1080 display basic graphics primitives in a variety of styles using the
1081 QPainter class.
1082
1083 \endtable
1084
1085 If you need to draw a complex shape, especially if you need to do
1086 so repeatedly, consider creating a QPainterPath and drawing it
1087 using drawPath().
1088
1089 \table 100%
1090 \row
1091 \o
1092 \bold {Painter Paths example}
1093
1094 The QPainterPath class provides a container for painting
1095 operations, enabling graphical shapes to be constructed and
1096 reused.
1097
1098 The \l {painting/painterpaths}{Painter Paths} example shows how
1099 painter paths can be used to build complex shapes for rendering.
1100
1101 \o \inlineimage qpainter-painterpaths.png
1102 \endtable
1103
1104 QPainter also provides the fillPath() function which fills the
1105 given QPainterPath with the given QBrush, and the strokePath()
1106 function that draws the outline of the given path (i.e. strokes
1107 the path).
1108
1109 See also the \l {demos/deform}{Vector Deformation} demo which
1110 shows how to use advanced vector techniques to draw text using a
1111 QPainterPath, the \l {demos/gradients}{Gradients} demo which shows
1112 the different types of gradients that are available in Qt, and the \l
1113 {demos/pathstroke}{Path Stroking} demo which shows Qt's built-in
1114 dash patterns and shows how custom patterns can be used to extend
1115 the range of available patterns.
1116
1117 \table
1118 \row
1119 \o \inlineimage qpainter-vectordeformation.png
1120 \o \inlineimage qpainter-gradients.png
1121 \o \inlineimage qpainter-pathstroking.png
1122 \header
1123 \o \l {demos/deform}{Vector Deformation}
1124 \o \l {demos/gradients}{Gradients}
1125 \o \l {demos/pathstroke}{Path Stroking}
1126 \endtable
1127
1128
1129 There are functions to draw pixmaps/images, namely drawPixmap(),
1130 drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
1131 produce the same result, except that drawPixmap() is faster
1132 on-screen while drawImage() may be faster on a QPrinter or other
1133 devices.
1134
1135 Text drawing is done using drawText(). When you need
1136 fine-grained positioning, boundingRect() tells you where a given
1137 drawText() command will draw.
1138
1139 There is a drawPicture() function that draws the contents of an
1140 entire QPicture. The drawPicture() function is the only function
1141 that disregards all the painter's settings as QPicture has its own
1142 settings.
1143
1144 \section1 Rendering Quality
1145
1146 To get the optimal rendering result using QPainter, you should use
1147 the platform independent QImage as paint device; i.e. using QImage
1148 will ensure that the result has an identical pixel representation
1149 on any platform.
1150
1151 The QPainter class also provides a means of controlling the
1152 rendering quality through its RenderHint enum and the support for
1153 floating point precision: All the functions for drawing primitives
1154 has a floating point version. These are often used in combination
1155 with the \l {RenderHint}{QPainter::Antialiasing} render hint.
1156
1157 \table 100%
1158 \row
1159 \o \inlineimage qpainter-concentriccircles.png
1160 \o
1161 \bold {Concentric Circles Example}
1162
1163 The \l {painting/concentriccircles}{Concentric Circles} example
1164 shows the improved rendering quality that can be obtained using
1165 floating point precision and anti-aliasing when drawing custom
1166 widgets.
1167
1168 The application's main window displays several widgets which are
1169 drawn using the various combinations of precision and
1170 anti-aliasing.
1171
1172 \endtable
1173
1174 The RenderHint enum specifies flags to QPainter that may or may
1175 not be respected by any given engine. \l
1176 {RenderHint}{QPainter::Antialiasing} indicates that the engine
1177 should antialias edges of primitives if possible, \l
1178 {RenderHint}{QPainter::TextAntialiasing} indicates that the engine
1179 should antialias text if possible, and the \l
1180 {RenderHint}{QPainter::SmoothPixmapTransform} indicates that the
1181 engine should use a smooth pixmap transformation algorithm.
1182 \l {RenderHint}{HighQualityAntialiasing} is an OpenGL-specific rendering hint
1183 indicating that the engine should use fragment programs and offscreen
1184 rendering for antialiasing.
1185
1186 The renderHints() function returns a flag that specifies the
1187 rendering hints that are set for this painter. Use the
1188 setRenderHint() function to set or clear the currently set
1189 RenderHints.
1190
1191 \section1 Coordinate Transformations
1192
1193 Normally, the QPainter operates on the device's own coordinate
1194 system (usually pixels), but QPainter has good support for
1195 coordinate transformations.
1196
1197 \table
1198 \row
1199 \o \inlineimage qpainter-clock.png
1200 \o \inlineimage qpainter-rotation.png
1201 \o \inlineimage qpainter-scale.png
1202 \o \inlineimage qpainter-translation.png
1203 \header
1204 \o nop \o rotate() \o scale() \o translate()
1205 \endtable
1206
1207 The most commonly used transformations are scaling, rotation,
1208 translation and shearing. Use the scale() function to scale the
1209 coordinate system by a given offset, the rotate() function to
1210 rotate it clockwise and translate() to translate it (i.e. adding a
1211 given offset to the points). You can also twist the coordinate
1212 system around the origin using the shear() function. See the \l
1213 {demos/affine}{Affine Transformations} demo for a visualization of
1214 a sheared coordinate system.
1215
1216 See also the \l {painting/transformations}{Transformations}
1217 example which shows how transformations influence the way that
1218 QPainter renders graphics primitives. In particular it shows how
1219 the order of transformations affects the result.
1220
1221 \table 100%
1222 \row
1223 \o
1224 \bold {Affine Transformations Demo}
1225
1226 The \l {demos/affine}{Affine Transformations} demo show Qt's
1227 ability to perform affine transformations on painting
1228 operations. The demo also allows the user to experiment with the
1229 transformation operations and see the results immediately.
1230
1231 \o \inlineimage qpainter-affinetransformations.png
1232 \endtable
1233
1234 All the tranformation operations operate on the transformation
1235 worldMatrix(). A matrix transforms a point in the plane to another
1236 point. For more information about the transformation matrix, see
1237 the \l {The Coordinate System} and QMatrix documentation.
1238
1239 The setWorldMatrix() function can replace or add to the currently
1240 set worldMatrix(). The resetMatrix() function resets any
1241 transformations that were made using translate(), scale(),
1242 shear(), rotate(), setWorldMatrix(), setViewport() and setWindow()
1243 functions. The deviceMatrix() returns the matrix that transforms
1244 from logical coordinates to device coordinates of the platform
1245 dependent paint device. The latter function is only needed when
1246 using platform painting commands on the platform dependent handle,
1247 and the platform does not do transformations nativly.
1248
1249 When drawing with QPainter, we specify points using logical
1250 coordinates which then are converted into the physical coordinates
1251 of the paint device. The mapping of the logical coordinates to the
1252 physical coordinates are handled by QPainter's combinedMatrix(), a
1253 combination of viewport() and window() and worldMatrix(). The
1254 viewport() represents the physical coordinates specifying an
1255 arbitrary rectangle, the window() describes the same rectangle in
1256 logical coordinates, and the worldMatrix() is identical with the
1257 transformation matrix.
1258
1259 See also \l {The Coordinate System} documentation.
1260
1261 \section1 Clipping
1262
1263 QPainter can clip any drawing operation to a rectangle, a region,
1264 or a vector path. The current clip is available using the
1265 functions clipRegion() and clipPath(). Whether paths or regions are
1266 preferred (faster) depends on the underlying paintEngine(). For
1267 example, the QImage paint engine prefers paths while the X11 paint
1268 engine prefers regions. Setting a clip is done in the painters
1269 logical coordinates.
1270
1271 After QPainter's clipping, the paint device may also clip. For
1272 example, most widgets clip away the pixels used by child widgets,
1273 and most printers clip away an area near the edges of the paper.
1274 This additional clipping is not reflected by the return value of
1275 clipRegion() or hasClipping().
1276
1277 \section1 Composition Modes
1278 \target Composition Modes
1279
1280 QPainter provides the CompositionMode enum which defines the
1281 Porter-Duff rules for digital image compositing; it describes a
1282 model for combining the pixels in one image, the source, with the
1283 pixels in another image, the destination.
1284
1285 The two most common forms of composition are \l
1286 {QPainter::CompositionMode}{Source} and \l
1287 {QPainter::CompositionMode}{SourceOver}. \l
1288 {QPainter::CompositionMode}{Source} is used to draw opaque objects
1289 onto a paint device. In this mode, each pixel in the source
1290 replaces the corresponding pixel in the destination. In \l
1291 {QPainter::CompositionMode}{SourceOver} composition mode, the
1292 source object is transparent and is drawn on top of the
1293 destination.
1294
1295 Note that composition transformation operates pixelwise. For that
1296 reason, there is a difference between using the graphic primitive
1297 itself and its bounding rectangle: The bounding rect contains
1298 pixels with alpha == 0 (i.e the pixels surrounding the
1299 primitive). These pixels will overwrite the other image's pixels,
1300 affectively clearing those, while the primitive only overwrites
1301 its own area.
1302
1303 \table 100%
1304 \row
1305 \o \inlineimage qpainter-compositiondemo.png
1306
1307 \o
1308 \bold {Composition Modes Demo}
1309
1310 The \l {demos/composition}{Composition Modes} demo, available in
1311 Qt's demo directory, allows you to experiment with the various
1312 composition modes and see the results immediately.
1313
1314 \endtable
1315
1316 \section1 Limitations
1317 \target Limitations
1318
1319 If you are using coordinates with Qt's raster-based paint engine, it is
1320 important to note that, while coordinates greater than +/- 2\sup 15 can
1321 be used, any painting performed with coordinates outside this range is not
1322 guaranteed to be shown; the drawing may be clipped. This is due to the
1323 use of \c{short int} in the implementation.
1324
1325 The outlines generated by Qt's stroker are only an approximation when dealing
1326 with curved shapes. It is in most cases impossible to represent the outline of
1327 a bezier curve segment using another bezier curve segment, and so Qt approximates
1328 the curve outlines by using several smaller curves. For performance reasons there
1329 is a limit to how many curves Qt uses for these outlines, and thus when using
1330 large pen widths or scales the outline error increases. To generate outlines with
1331 smaller errors it is possible to use the QPainterPathStroker class, which has the
1332 setCurveThreshold member function which let's the user specify the error tolerance.
1333 Another workaround is to convert the paths to polygons first and then draw the
1334 polygons instead.
1335
1336 \sa QPaintDevice, QPaintEngine, {QtSvg Module}, {Basic Drawing Example}
1337*/
1338
1339/*!
1340 \enum QPainter::RenderHint
1341
1342 Renderhints are used to specify flags to QPainter that may or
1343 may not be respected by any given engine.
1344
1345 \value Antialiasing Indicates that the engine should antialias
1346 edges of primitives if possible.
1347
1348 \value TextAntialiasing Indicates that the engine should antialias
1349 text if possible. To forcibly disable antialiasing for text, do not
1350 use this hint. Instead, set QFont::NoAntialias on your font's style
1351 strategy.
1352
1353 \value SmoothPixmapTransform Indicates that the engine should use
1354 a smooth pixmap transformation algorithm (such as bilinear) rather
1355 than nearest neighbor.
1356
1357 \value HighQualityAntialiasing An OpenGL-specific rendering hint
1358 indicating that the engine should use fragment programs and offscreen
1359 rendering for antialiasing.
1360
1361 \value NonCosmeticDefaultPen The engine should interpret pens with a width
1362 of 0 (which otherwise enables QPen::isCosmetic()) as being a non-cosmetic
1363 pen with a width of 1.
1364
1365 \sa renderHints(), setRenderHint(), {QPainter#Rendering
1366 Quality}{Rendering Quality}, {Concentric Circles Example}
1367
1368*/
1369
1370/*!
1371 Constructs a painter.
1372
1373 \sa begin(), end()
1374*/
1375
1376QPainter::QPainter()
1377{
1378 d_ptr = new QPainterPrivate(this);
1379}
1380
1381/*!
1382 \fn QPainter::QPainter(QPaintDevice *device)
1383
1384 Constructs a painter that begins painting the paint \a device
1385 immediately.
1386
1387 This constructor is convenient for short-lived painters, e.g. in a
1388 QWidget::paintEvent() and should be used only once. The
1389 constructor calls begin() for you and the QPainter destructor
1390 automatically calls end().
1391
1392 Here's an example using begin() and end():
1393 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 1
1394
1395 The same example using this constructor:
1396 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 2
1397
1398 Since the constructor cannot provide feedback when the initialization
1399 of the painter failed you should rather use begin() and end() to paint
1400 on external devices, e.g. printers.
1401
1402 \sa begin(), end()
1403*/
1404
1405QPainter::QPainter(QPaintDevice *pd)
1406 : d_ptr(0)
1407{
1408 Q_ASSERT(pd != 0);
1409 if (!QPainterPrivate::attachPainterPrivate(this, pd)) {
1410 d_ptr = new QPainterPrivate(this);
1411 begin(pd);
1412 }
1413 Q_ASSERT(d_ptr);
1414}
1415
1416/*!
1417 Destroys the painter.
1418*/
1419QPainter::~QPainter()
1420{
1421 d_ptr->inDestructor = true;
1422 if (isActive())
1423 end();
1424 else if (d_ptr->refcount > 1)
1425 d_ptr->detachPainterPrivate(this);
1426
1427 if (d_ptr) {
1428 // Make sure we haven't messed things up.
1429 Q_ASSERT(d_ptr->inDestructor);
1430 d_ptr->inDestructor = false;
1431 Q_ASSERT(d_ptr->refcount == 1);
1432 if (d_ptr->d_ptrs)
1433 free(d_ptr->d_ptrs);
1434 delete d_ptr;
1435 }
1436}
1437
1438/*!
1439 Returns the paint device on which this painter is currently
1440 painting, or 0 if the painter is not active.
1441
1442 \sa isActive()
1443*/
1444
1445QPaintDevice *QPainter::device() const
1446{
1447 Q_D(const QPainter);
1448 if (isActive() && d->engine->d_func()->currentClipWidget)
1449 return d->engine->d_func()->currentClipWidget;
1450 return d->original_device;
1451}
1452
1453/*!
1454 Returns true if begin() has been called and end() has not yet been
1455 called; otherwise returns false.
1456
1457 \sa begin(), QPaintDevice::paintingActive()
1458*/
1459
1460bool QPainter::isActive() const
1461{
1462 Q_D(const QPainter);
1463 return d->engine;
1464}
1465
1466/*!
1467 Initializes the painters pen, background and font to the same as
1468 the given \a widget. This function is called automatically when the
1469 painter is opened on a QWidget.
1470
1471 \sa begin(), {QPainter#Settings}{Settings}
1472*/
1473void QPainter::initFrom(const QWidget *widget)
1474{
1475 Q_ASSERT_X(widget, "QPainter::initFrom(const QWidget *widget)", "Widget cannot be 0");
1476 Q_D(QPainter);
1477 if (!d->engine) {
1478 qWarning("QPainter::initFrom: Painter not active, aborted");
1479 return;
1480 }
1481
1482 const QPalette &pal = widget->palette();
1483 d->state->pen = QPen(pal.brush(widget->foregroundRole()), 0);
1484 d->state->bgBrush = pal.brush(widget->backgroundRole());
1485 d->state->deviceFont = QFont(widget->font(), const_cast<QWidget*> (widget));
1486 d->state->font = d->state->deviceFont;
1487 if (d->engine) {
1488 d->engine->setDirty(QPaintEngine::DirtyPen);
1489 d->engine->setDirty(QPaintEngine::DirtyBrush);
1490 d->engine->setDirty(QPaintEngine::DirtyFont);
1491 }
1492 d->state->layoutDirection = widget->layoutDirection();
1493}
1494
1495
1496/*!
1497 Saves the current painter state (pushes the state onto a stack). A
1498 save() must be followed by a corresponding restore(); the end()
1499 function unwinds the stack.
1500
1501 \sa restore()
1502*/
1503
1504void QPainter::save()
1505{
1506#ifdef QT_DEBUG_DRAW
1507 if (qt_show_painter_debug_output)
1508 printf("QPainter::save()\n");
1509#endif
1510 Q_D(QPainter);
1511 if (!d->engine) {
1512 qWarning("QPainter::save: Painter not active");
1513 return;
1514 }
1515
1516 if (d->extended) {
1517 d->state = d->extended->createState(d->states.back());
1518 d->extended->setState(d->state);
1519 } else {
1520 d->updateState(d->state);
1521 d->state = new QPainterState(d->states.back());
1522 d->engine->state = d->state;
1523 }
1524 d->states.push_back(d->state);
1525}
1526
1527/*!
1528 Restores the current painter state (pops a saved state off the
1529 stack).
1530
1531 \sa save()
1532*/
1533
1534void QPainter::restore()
1535{
1536#ifdef QT_DEBUG_DRAW
1537 if (qt_show_painter_debug_output)
1538 printf("QPainter::restore()\n");
1539#endif
1540 Q_D(QPainter);
1541 if (d->states.size()<=1) {
1542 qWarning("QPainter::restore: Unbalanced save/restore");
1543 return;
1544 } else if (!d->engine) {
1545 qWarning("QPainter::restore: Painter not active");
1546 return;
1547 }
1548
1549 QPainterState *tmp = d->state;
1550 d->states.pop_back();
1551 d->state = d->states.back();
1552 d->txinv = false;
1553
1554 if (d->extended) {
1555 d->checkEmulation();
1556 d->extended->setState(d->state);
1557 delete tmp;
1558 return;
1559 }
1560
1561 // trigger clip update if the clip path/region has changed since
1562 // last save
1563 if (!d->state->clipInfo.isEmpty()
1564 && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1565 // reuse the tmp state to avoid any extra allocs...
1566 tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1567 tmp->clipOperation = Qt::NoClip;
1568 tmp->clipPath = QPainterPath();
1569 d->engine->updateState(*tmp);
1570 // replay the list of clip states,
1571 for (int i=0; i<d->state->clipInfo.size(); ++i) {
1572 const QPainterClipInfo &info = d->state->clipInfo.at(i);
1573 tmp->matrix.setMatrix(info.matrix.m11(), info.matrix.m12(), info.matrix.m13(),
1574 info.matrix.m21(), info.matrix.m22(), info.matrix.m23(),
1575 info.matrix.dx() - d->state->redirection_offset.x(),
1576 info.matrix.dy() - d->state->redirection_offset.y(), info.matrix.m33());
1577 tmp->clipOperation = info.operation;
1578 if (info.clipType == QPainterClipInfo::RectClip) {
1579 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1580 tmp->clipRegion = info.rect;
1581 } else if (info.clipType == QPainterClipInfo::RegionClip) {
1582 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1583 tmp->clipRegion = info.region;
1584 } else { // clipType == QPainterClipInfo::PathClip
1585 tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
1586 tmp->clipPath = info.path;
1587 }
1588 d->engine->updateState(*tmp);
1589 }
1590
1591
1592 //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
1593 d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1594 tmp->changeFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1595 tmp->changeFlags |= QPaintEngine::DirtyTransform;
1596 }
1597
1598 d->updateState(d->state);
1599 delete tmp;
1600}
1601
1602
1603/*!
1604
1605 \fn bool QPainter::begin(QPaintDevice *device)
1606
1607 Begins painting the paint \a device and returns true if
1608 successful; otherwise returns false.
1609
1610 Notice that all painter settings (setPen(), setBrush() etc.) are reset
1611 to default values when begin() is called.
1612
1613 The errors that can occur are serious problems, such as these:
1614
1615 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 3
1616
1617 Note that most of the time, you can use one of the constructors
1618 instead of begin(), and that end() is automatically done at
1619 destruction.
1620
1621 \warning A paint device can only be painted by one painter at a
1622 time.
1623
1624 \sa end(), QPainter()
1625*/
1626
1627bool QPainter::begin(QPaintDevice *pd)
1628{
1629 Q_ASSERT(pd);
1630
1631 if (pd->painters > 0) {
1632 qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
1633 return false;
1634 }
1635
1636 if (d_ptr->engine) {
1637 qWarning("QPainter::begin: Painter already active");
1638 return false;
1639 }
1640
1641 if (QPainterPrivate::attachPainterPrivate(this, pd))
1642 return true;
1643
1644 Q_D(QPainter);
1645
1646 d->helper_device = pd;
1647 d->original_device = pd;
1648 QPaintDevice *rpd = 0;
1649
1650 QPoint redirectionOffset;
1651 // We know for sure that redirection is broken when the widget is inside
1652 // its paint event, so it's safe to use our hard-coded redirection. However,
1653 // there IS one particular case we still need to support, and that's
1654 // when people call QPainter::setRedirected in the widget's paint event right
1655 // before any painter is created (or QPainter::begin is called). In that
1656 // particular case our hard-coded redirection is restored and the redirection
1657 // is retrieved from QPainter::redirected (as before).
1658 if (pd->devType() == QInternal::Widget)
1659 rpd = static_cast<QWidget *>(pd)->d_func()->redirected(&redirectionOffset);
1660
1661 if (!rpd)
1662 rpd = redirected(pd, &redirectionOffset);
1663
1664 if (rpd)
1665 pd = rpd;
1666
1667#ifdef QT_DEBUG_DRAW
1668 if (qt_show_painter_debug_output)
1669 printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1670#endif
1671
1672
1673 d->device = pd;
1674 if (pd->devType() == QInternal::Pixmap)
1675 static_cast<QPixmap *>(pd)->detach();
1676 else if (pd->devType() == QInternal::Image)
1677 static_cast<QImage *>(pd)->detach();
1678
1679 d->engine = pd->paintEngine();
1680 d->extended = d->engine && d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : 0;
1681 if (d->emulationEngine)
1682 d->emulationEngine->real_engine = d->extended;
1683
1684 // Setup new state...
1685 Q_ASSERT(!d->state);
1686 d->state = d->extended ? d->extended->createState(0) : new QPainterState;
1687 d->state->painter = this;
1688 d->states.push_back(d->state);
1689
1690 d->state->redirection_offset = redirectionOffset;
1691 d->state->brushOrigin = QPointF();
1692
1693 if (!d->engine) {
1694 qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1695 return true;
1696 }
1697
1698 // Slip a painter state into the engine before we do any other operations
1699 if (d->extended)
1700 d->extended->setState(d->state);
1701 else
1702 d->engine->state = d->state;
1703
1704 switch (pd->devType()) {
1705 case QInternal::Widget:
1706 {
1707 const QWidget *widget = static_cast<const QWidget *>(pd);
1708 Q_ASSERT(widget);
1709
1710 const bool paintOutsidePaintEvent = widget->testAttribute(Qt::WA_PaintOutsidePaintEvent);
1711 const bool inPaintEvent = widget->testAttribute(Qt::WA_WState_InPaintEvent);
1712 if(!d->engine->hasFeature(QPaintEngine::PaintOutsidePaintEvent)
1713 && !paintOutsidePaintEvent && !inPaintEvent) {
1714 qWarning("QPainter::begin: Widget painting can only begin as a "
1715 "result of a paintEvent");
1716 d->engine = 0;
1717 d->device = 0;
1718 return false;
1719 }
1720
1721 // Adjust offset for alien widgets painting outside the paint event.
1722 if (!inPaintEvent && paintOutsidePaintEvent && !widget->internalWinId()
1723 && widget->testAttribute(Qt::WA_WState_Created)) {
1724 d->state->redirection_offset -= widget->mapTo(widget->nativeParentWidget(), QPoint());
1725 }
1726 break;
1727 }
1728 case QInternal::Pixmap:
1729 {
1730 QPixmap *pm = static_cast<QPixmap *>(pd);
1731 Q_ASSERT(pm);
1732 if (pm->isNull()) {
1733 qWarning("QPainter::begin: Cannot paint on a null pixmap");
1734 d->engine = 0;
1735 d->device = 0;
1736 return false;
1737 }
1738
1739 if (pm->depth() == 1) {
1740 d->state->pen = QPen(Qt::color1);
1741 d->state->brush = QBrush(Qt::color0);
1742 }
1743 break;
1744 }
1745 case QInternal::Image:
1746 {
1747 QImage *img = static_cast<QImage *>(pd);
1748 Q_ASSERT(img);
1749 if (img->isNull()) {
1750 qWarning("QPainter::begin: Cannot paint on a null image");
1751 d->engine = 0;
1752 d->device = 0;
1753 return false;
1754 }
1755 if (img->depth() == 1) {
1756 d->state->pen = QPen(Qt::color1);
1757 d->state->brush = QBrush(Qt::color0);
1758 }
1759 break;
1760 }
1761 default:
1762 break;
1763 }
1764 if (d->state->ww == 0) // For compat with 3.x painter defaults
1765 d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1766
1767 d->engine->setPaintDevice(pd);
1768
1769 bool begun = d->engine->begin(pd);
1770 if (!begun) {
1771 qWarning("QPainter::begin(): Returned false");
1772 if (d->engine->isActive()) {
1773 end();
1774 } else {
1775 d->states.clear();
1776 delete d->state;
1777 d->state = 0;
1778 }
1779 d->engine = 0;
1780 d->device = 0;
1781 return false;
1782 } else {
1783 d->engine->setActive(begun);
1784 }
1785
1786 // Copy painter properties from original paint device,
1787 // required for QPixmap::grabWidget()
1788 if (d->original_device->devType() == QInternal::Widget) {
1789 QWidget *widget = static_cast<QWidget *>(d->original_device);
1790 initFrom(widget);
1791 } else {
1792 d->state->layoutDirection = QApplication::layoutDirection();
1793 // make sure we have a font compatible with the paintdevice
1794 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1795 }
1796
1797 QRect systemRect = d->engine->systemRect();
1798 if (!systemRect.isEmpty()) {
1799 d->state->ww = d->state->vw = systemRect.width();
1800 d->state->wh = d->state->vh = systemRect.height();
1801 } else {
1802 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1803 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1804 }
1805
1806 d->state->redirection_offset += d->engine->coordinateOffset();
1807
1808 Q_ASSERT(d->engine->isActive());
1809
1810 if (!d->state->redirection_offset.isNull())
1811 d->updateMatrix();
1812
1813 Q_ASSERT(d->engine->isActive());
1814 d->state->renderHints = QPainter::TextAntialiasing;
1815 ++d->device->painters;
1816
1817 d->state->emulationSpecifier = 0;
1818
1819 return true;
1820}
1821
1822/*!
1823 Ends painting. Any resources used while painting are released. You
1824 don't normally need to call this since it is called by the
1825 destructor.
1826
1827 Returns true if the painter is no longer active; otherwise returns false.
1828
1829 \sa begin(), isActive()
1830*/
1831
1832bool QPainter::end()
1833{
1834#ifdef QT_DEBUG_DRAW
1835 if (qt_show_painter_debug_output)
1836 printf("QPainter::end()\n");
1837#endif
1838 Q_D(QPainter);
1839
1840 if (!d->engine) {
1841 qWarning("QPainter::end: Painter not active, aborted");
1842 d->states.clear();
1843 delete d->state;
1844 d->state = 0;
1845 d->device = 0;
1846 return false;
1847 }
1848
1849 if (d->refcount > 1) {
1850 d->detachPainterPrivate(this);
1851 return true;
1852 }
1853
1854 if (d->states.size() > 1) {
1855 qWarning("QPainter::end: Painter ended with %d saved states",
1856 d->states.size());
1857 }
1858
1859 bool ended = true;
1860
1861 if (d->engine->isActive()) {
1862 ended = d->engine->end();
1863 d->updateState(0);
1864
1865 --d->device->painters;
1866 if (d->device->painters == 0) {
1867 d->engine->setPaintDevice(0);
1868 d->engine->setActive(false);
1869 }
1870 }
1871
1872 if (d->engine->autoDestruct()) {
1873 delete d->engine;
1874 }
1875
1876 d->engine = 0;
1877
1878 if (d->emulationEngine) {
1879 delete d->emulationEngine;
1880 d->emulationEngine = 0;
1881 }
1882
1883 if (d->extended) {
1884 d->extended = 0;
1885 }
1886
1887 d->states.clear();
1888 delete d->state;
1889 d->state = 0;
1890
1891 d->device = 0;
1892 return ended;
1893}
1894
1895
1896/*!
1897 Returns the paint engine that the painter is currently operating
1898 on if the painter is active; otherwise 0.
1899
1900 \sa isActive()
1901*/
1902QPaintEngine *QPainter::paintEngine() const
1903{
1904 Q_D(const QPainter);
1905 return d->engine;
1906}
1907
1908
1909/*!
1910 Returns the font metrics for the painter if the painter is
1911 active. Otherwise, the return value is undefined.
1912
1913 \sa font(), isActive(), {QPainter#Settings}{Settings}
1914*/
1915
1916QFontMetrics QPainter::fontMetrics() const
1917{
1918 Q_D(const QPainter);
1919 if (!d->engine) {
1920 qWarning("QPainter::fontMetrics: Painter not active");
1921 return QFontMetrics(QFont());
1922 }
1923 return QFontMetrics(d->state->font);
1924}
1925
1926
1927/*!
1928 Returns the font info for the painter if the painter is
1929 active. Otherwise, the return value is undefined.
1930
1931 \sa font(), isActive(), {QPainter#Settings}{Settings}
1932*/
1933
1934QFontInfo QPainter::fontInfo() const
1935{
1936 Q_D(const QPainter);
1937 if (!d->engine) {
1938 qWarning("QPainter::fontInfo: Painter not active");
1939 return QFontInfo(QFont());
1940 }
1941 return QFontInfo(d->state->font);
1942}
1943
1944/*!
1945 \since 4.2
1946
1947 Returns the opacity of the painter. The default value is
1948 1.
1949*/
1950
1951qreal QPainter::opacity() const
1952{
1953 Q_D(const QPainter);
1954 if (!d->engine) {
1955 qWarning("QPainter::opacity: Painter not active");
1956 return 1.0;
1957 }
1958 return d->state->opacity;
1959}
1960
1961/*!
1962 \since 4.2
1963
1964 Sets the opacity of the painter to \a opacity. The value should
1965 be in the range 0.0 to 1.0, where 0.0 is fully transparent and
1966 1.0 is fully opaque.
1967
1968 Opacity set on the painter will apply to all drawing operations
1969 individually.
1970*/
1971
1972void QPainter::setOpacity(qreal opacity)
1973{
1974 Q_D(QPainter);
1975
1976 if (!d->engine) {
1977 qWarning("QPainter::setOpacity: Painter not active");
1978 return;
1979 }
1980
1981 opacity = qMin(qreal(1), qMax(qreal(0), opacity));
1982
1983 if (opacity == d->state->opacity)
1984 return;
1985
1986 d->state->opacity = opacity;
1987
1988 if (d->extended)
1989 d->extended->opacityChanged();
1990 else
1991 d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
1992}
1993
1994
1995/*!
1996 Returns the currently set brush origin.
1997
1998 \sa setBrushOrigin(), {QPainter#Settings}{Settings}
1999*/
2000
2001QPoint QPainter::brushOrigin() const
2002{
2003 Q_D(const QPainter);
2004 if (!d->engine) {
2005 qWarning("QPainter::brushOrigin: Painter not active");
2006 return QPoint();
2007 }
2008 return QPointF(d->state->brushOrigin).toPoint();
2009}
2010
2011/*!
2012 \fn void QPainter::setBrushOrigin(const QPointF &position)
2013
2014 Sets the brush origin to \a position.
2015
2016 The brush origin specifies the (0, 0) coordinate of the painter's
2017 brush. This setting only applies to pattern brushes and pixmap
2018 brushes.
2019
2020 Note that while the brushOrigin() was necessary to adopt the
2021 parent's background for a widget in Qt 3, this is no longer the
2022 case since the Qt 4 painter doesn't paint the background unless
2023 you explicitly tell it to do so by setting the widget's \l
2024 {QWidget::autoFillBackground}{autoFillBackground} property to
2025 true.
2026
2027 \sa brushOrigin(), {QPainter#Settings}{Settings}
2028*/
2029
2030void QPainter::setBrushOrigin(const QPointF &p)
2031{
2032 Q_D(QPainter);
2033#ifdef QT_DEBUG_DRAW
2034 if (qt_show_painter_debug_output)
2035 printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
2036#endif
2037
2038 if (!d->engine) {
2039 qWarning("QPainter::setBrushOrigin: Painter not active");
2040 return;
2041 }
2042
2043 d->state->brushOrigin = p;
2044
2045 if (d->extended) {
2046 d->extended->brushOriginChanged();
2047 return;
2048 }
2049
2050 d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
2051}
2052
2053/*!
2054 \fn void QPainter::setBrushOrigin(const QPoint &position)
2055 \overload
2056
2057 Sets the brush's origin to the given \a position.
2058*/
2059
2060/*!
2061 \fn void QPainter::setBrushOrigin(int x, int y)
2062
2063 \overload
2064
2065 Sets the brush's origin to point (\a x, \a y).
2066*/
2067
2068/*!
2069 \enum QPainter::CompositionMode
2070
2071 Defines the modes supported for digital image compositing.
2072 Composition modes are used to specify how the pixels in one image,
2073 the source, are merged with the pixel in another image, the
2074 destination.
2075
2076 Please note that the bitwise raster operation modes, denoted with
2077 a RasterOp prefix, are only natively supported in the X11 and
2078 raster paint engines. This means that the only way to utilize
2079 these modes on the Mac is via a QImage. The RasterOp denoted blend
2080 modes are \e not supported for pens and brushes with alpha
2081 components. Also, turning on the QPainter::Antialiasing render
2082 hint will effectively disable the RasterOp modes.
2083
2084
2085 \image qpainter-compositionmode1.png
2086 \image qpainter-compositionmode2.png
2087
2088 The most common type is SourceOver (often referred to as just
2089 alpha blending) where the source pixel is blended on top of the
2090 destination pixel in such a way that the alpha component of the
2091 source defines the translucency of the pixel.
2092
2093 When the paint device is a QImage, the image format must be set to
2094 \l {QImage::Format}{Format_ARGB32Premultiplied} or
2095 \l {QImage::Format}{Format_ARGB32} for the composition modes to have
2096 any effect. For performance the premultiplied version is the preferred
2097 format.
2098
2099 When a composition mode is set it applies to all painting
2100 operator, pens, brushes, gradients and pixmap/image drawing.
2101
2102 \value CompositionMode_SourceOver This is the default mode. The
2103 alpha of the source is used to blend the pixel on top of the
2104 destination.
2105
2106 \value CompositionMode_DestinationOver The alpha of the
2107 destination is used to blend it on top of the source pixels. This
2108 mode is the inverse of CompositionMode_SourceOver.
2109
2110 \value CompositionMode_Clear The pixels in the destination are
2111 cleared (set to fully transparent) independent of the source.
2112
2113 \value CompositionMode_Source The output is the source
2114 pixel. (This means a basic copy operation and is identical to
2115 SourceOver when the source pixel is opaque).
2116
2117 \value CompositionMode_Destination The output is the destination
2118 pixel. This means that the blending has no effect. This mode is
2119 the inverse of CompositionMode_Source.
2120
2121 \value CompositionMode_SourceIn The output is the source, where
2122 the alpha is reduced by that of the destination.
2123
2124 \value CompositionMode_DestinationIn The output is the
2125 destination, where the alpha is reduced by that of the
2126 source. This mode is the inverse of CompositionMode_SourceIn.
2127
2128 \value CompositionMode_SourceOut The output is the source, where
2129 the alpha is reduced by the inverse of destination.
2130
2131 \value CompositionMode_DestinationOut The output is the
2132 destination, where the alpha is reduced by the inverse of the
2133 source. This mode is the inverse of CompositionMode_SourceOut.
2134
2135 \value CompositionMode_SourceAtop The source pixel is blended on
2136 top of the destination, with the alpha of the source pixel reduced
2137 by the alpha of the destination pixel.
2138
2139 \value CompositionMode_DestinationAtop The destination pixel is
2140 blended on top of the source, with the alpha of the destination
2141 pixel is reduced by the alpha of the destination pixel. This mode
2142 is the inverse of CompositionMode_SourceAtop.
2143
2144 \value CompositionMode_Xor The source, whose alpha is reduced with
2145 the inverse of the destination alpha, is merged with the
2146 destination, whose alpha is reduced by the inverse of the source
2147 alpha. CompositionMode_Xor is not the same as the bitwise Xor.
2148
2149 \value CompositionMode_Plus Both the alpha and color of the source
2150 and destination pixels are added together.
2151
2152 \value CompositionMode_Multiply The output is the source color
2153 multiplied by the destination. Multiplying a color with white
2154 leaves the color unchanged, while multiplying a color
2155 with black produces black.
2156
2157 \value CompositionMode_Screen The source and destination colors
2158 are inverted and then multiplied. Screening a color with white
2159 produces white, whereas screening a color with black leaves the
2160 color unchanged.
2161
2162 \value CompositionMode_Overlay Multiplies or screens the colors
2163 depending on the destination color. The destination color is mixed
2164 with the source color to reflect the lightness or darkness of the
2165 destination.
2166
2167 \value CompositionMode_Darken The darker of the source and
2168 destination colors is selected.
2169
2170 \value CompositionMode_Lighten The lighter of the source and
2171 destination colors is selected.
2172
2173 \value CompositionMode_ColorDodge The destination color is
2174 brightened to reflect the source color. A black source color
2175 leaves the destination color unchanged.
2176
2177 \value CompositionMode_ColorBurn The destination color is darkened
2178 to reflect the source color. A white source color leaves the
2179 destination color unchanged.
2180
2181 \value CompositionMode_HardLight Multiplies or screens the colors
2182 depending on the source color. A light source color will lighten
2183 the destination color, whereas a dark source color will darken the
2184 destination color.
2185
2186 \value CompositionMode_SoftLight Darkens or lightens the colors
2187 depending on the source color. Similar to
2188 CompositionMode_HardLight.
2189
2190 \value CompositionMode_Difference Subtracts the darker of the
2191 colors from the lighter. Painting with white inverts the
2192 destination color, whereas painting with black leaves the
2193 destination color unchanged.
2194
2195 \value CompositionMode_Exclusion Similar to
2196 CompositionMode_Difference, but with a lower contrast. Painting
2197 with white inverts the destination color, whereas painting with
2198 black leaves the destination color unchanged.
2199
2200 \value RasterOp_SourceOrDestination Does a bitwise OR operation on
2201 the source and destination pixels (src OR dst).
2202
2203 \value RasterOp_SourceAndDestination Does a bitwise AND operation
2204 on the source and destination pixels (src AND dst).
2205
2206 \value RasterOp_SourceXorDestination Does a bitwise XOR operation
2207 on the source and destination pixels (src XOR dst).
2208
2209 \value RasterOp_NotSourceAndNotDestination Does a bitwise NOR
2210 operation on the source and destination pixels ((NOT src) AND (NOT
2211 dst)).
2212
2213 \value RasterOp_NotSourceOrNotDestination Does a bitwise NAND
2214 operation on the source and destination pixels ((NOT src) OR (NOT
2215 dst)).
2216
2217 \value RasterOp_NotSourceXorDestination Does a bitwise operation
2218 where the source pixels are inverted and then XOR'ed with the
2219 destination ((NOT src) XOR dst).
2220
2221 \value RasterOp_NotSource Does a bitwise operation where the
2222 source pixels are inverted (NOT src).
2223
2224 \value RasterOp_NotSourceAndDestination Does a bitwise operation
2225 where the source is inverted and then AND'ed with the destination
2226 ((NOT src) AND dst).
2227
2228 \value RasterOp_SourceAndNotDestination Does a bitwise operation
2229 where the source is AND'ed with the inverted destination pixels
2230 (src AND (NOT dst)).
2231
2232 \sa compositionMode(), setCompositionMode(), {QPainter#Composition
2233 Modes}{Composition Modes}, {Image Composition Example}
2234*/
2235
2236/*!
2237 Sets the composition mode to the given \a mode.
2238
2239 \warning You can only set the composition mode for QPainter
2240 objects that operates on a QImage.
2241
2242 \sa compositionMode()
2243*/
2244void QPainter::setCompositionMode(CompositionMode mode)
2245{
2246 Q_D(QPainter);
2247 if (!d->engine) {
2248 qWarning("QPainter::setCompositionMode: Painter not active");
2249 return;
2250 }
2251 if (d->extended) {
2252 d->state->composition_mode = mode;
2253 d->extended->compositionModeChanged();
2254 return;
2255 }
2256
2257 if (mode >= QPainter::RasterOp_SourceOrDestination) {
2258 if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
2259 qWarning("QPainter::setCompositionMode: "
2260 "Raster operation modes not supported on device");
2261 return;
2262 }
2263 } else if (mode >= QPainter::CompositionMode_Plus) {
2264 if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
2265 qWarning("QPainter::setCompositionMode: "
2266 "Blend modes not supported on device");
2267 return;
2268 }
2269 } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
2270 if (mode != CompositionMode_Source && mode != CompositionMode_SourceOver) {
2271 qWarning("QPainter::setCompositionMode: "
2272 "PorterDuff modes not supported on device");
2273 return;
2274 }
2275 }
2276
2277 d->state->composition_mode = mode;
2278 d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
2279}
2280
2281/*!
2282 Returns the current composition mode.
2283
2284 \sa CompositionMode, setCompositionMode()
2285*/
2286QPainter::CompositionMode QPainter::compositionMode() const
2287{
2288 Q_D(const QPainter);
2289 if (!d->engine) {
2290 qWarning("QPainter::compositionMode: Painter not active");
2291 return QPainter::CompositionMode_SourceOver;
2292 }
2293 return d->state->composition_mode;
2294}
2295
2296/*!
2297 Returns the current background brush.
2298
2299 \sa setBackground(), {QPainter#Settings}{Settings}
2300*/
2301
2302const QBrush &QPainter::background() const
2303{
2304 Q_D(const QPainter);
2305 if (!d->engine) {
2306 qWarning("QPainter::background: Painter not active");
2307 return d->fakeState()->brush;
2308 }
2309 return d->state->bgBrush;
2310}
2311
2312
2313/*!
2314 Returns true if clipping has been set; otherwise returns false.
2315
2316 \sa setClipping(), {QPainter#Clipping}{Clipping}
2317*/
2318
2319bool QPainter::hasClipping() const
2320{
2321 Q_D(const QPainter);
2322 if (!d->engine) {
2323 qWarning("QPainter::hasClipping: Painter not active");
2324 return false;
2325 }
2326 return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
2327}
2328
2329
2330/*!
2331 Enables clipping if \a enable is true, or disables clipping if \a
2332 enable is false.
2333
2334 \sa hasClipping(), {QPainter#Clipping}{Clipping}
2335*/
2336
2337void QPainter::setClipping(bool enable)
2338{
2339 Q_D(QPainter);
2340#ifdef QT_DEBUG_DRAW
2341 if (qt_show_painter_debug_output)
2342 printf("QPainter::setClipping(), enable=%s, was=%s\n",
2343 enable ? "on" : "off",
2344 hasClipping() ? "on" : "off");
2345#endif
2346 if (!d->engine) {
2347 qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
2348 return;
2349 }
2350
2351 if (hasClipping() == enable)
2352 return;
2353
2354 // we can't enable clipping if we don't have a clip
2355 if (enable
2356 && (d->state->clipInfo.isEmpty() || d->state->clipInfo.last().operation == Qt::NoClip))
2357 return;
2358 d->state->clipEnabled = enable;
2359
2360 if (d->extended) {
2361 d->extended->clipEnabledChanged();
2362 return;
2363 }
2364
2365 d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
2366 d->updateState(d->state);
2367}
2368
2369
2370/*!
2371 Returns the currently set clip region. Note that the clip region
2372 is given in logical coordinates.
2373
2374 \sa setClipRegion(), clipPath(), setClipping()
2375*/
2376
2377QRegion QPainter::clipRegion() const
2378{
2379 Q_D(const QPainter);
2380 if (!d->engine) {
2381 qWarning("QPainter::clipRegion: Painter not active");
2382 return QRegion();
2383 }
2384
2385 QRegion region;
2386 bool lastWasNothing = true;
2387
2388 if (!d->txinv)
2389 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2390
2391 // ### Falcon: Use QPainterPath
2392 for (int i=0; i<d->state->clipInfo.size(); ++i) {
2393 const QPainterClipInfo &info = d->state->clipInfo.at(i);
2394 QRegion other;
2395 switch (info.clipType) {
2396
2397 case QPainterClipInfo::RegionClip: {
2398 QTransform matrix = (info.matrix * d->invMatrix);
2399 if (lastWasNothing) {
2400 region = info.region * matrix;
2401 lastWasNothing = false;
2402 continue;
2403 }
2404 if (info.operation == Qt::IntersectClip)
2405 region &= info.region * matrix;
2406 else if (info.operation == Qt::UniteClip)
2407 region |= info.region * matrix;
2408 else if (info.operation == Qt::NoClip) {
2409 lastWasNothing = true;
2410 region = QRegion();
2411 } else
2412 region = info.region * matrix;
2413 break;
2414 }
2415
2416 case QPainterClipInfo::PathClip: {
2417 QTransform matrix = (info.matrix * d->invMatrix);
2418 if (lastWasNothing) {
2419 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2420 info.path.fillRule());
2421 lastWasNothing = false;
2422 continue;
2423 }
2424 if (info.operation == Qt::IntersectClip) {
2425 region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2426 info.path.fillRule());
2427 } else if (info.operation == Qt::UniteClip) {
2428 region |= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2429 info.path.fillRule());
2430 } else if (info.operation == Qt::NoClip) {
2431 lastWasNothing = true;
2432 region = QRegion();
2433 } else {
2434 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2435 info.path.fillRule());
2436 }
2437 break;
2438 }
2439
2440 case QPainterClipInfo::RectClip: {
2441 QTransform matrix = (info.matrix * d->invMatrix);
2442 if (lastWasNothing) {
2443 region = QRegion(info.rect) * matrix;
2444 lastWasNothing = false;
2445 continue;
2446 }
2447 if (info.operation == Qt::IntersectClip)
2448 region &= QRegion(info.rect) * matrix;
2449 else if (info.operation == Qt::UniteClip)
2450 region |= QRegion(info.rect) * matrix;
2451 else if (info.operation == Qt::NoClip) {
2452 lastWasNothing = true;
2453 region = QRegion();
2454 } else
2455 region = QRegion(info.rect) * matrix;
2456 break;
2457 }
2458
2459 case QPainterClipInfo::RectFClip: {
2460 QTransform matrix = (info.matrix * d->invMatrix);
2461 if (lastWasNothing) {
2462 region = QRegion(info.rectf.toRect()) * matrix;
2463 lastWasNothing = false;
2464 continue;
2465 }
2466 if (info.operation == Qt::IntersectClip)
2467 region &= QRegion(info.rectf.toRect()) * matrix;
2468 else if (info.operation == Qt::UniteClip)
2469 region |= QRegion(info.rectf.toRect()) * matrix;
2470 else if (info.operation == Qt::NoClip) {
2471 lastWasNothing = true;
2472 region = QRegion();
2473 } else
2474 region = QRegion(info.rectf.toRect()) * matrix;
2475 break;
2476 }
2477 }
2478 }
2479
2480 return region;
2481}
2482
2483extern QPainterPath qt_regionToPath(const QRegion &region);
2484
2485/*!
2486 Returns the currently clip as a path. Note that the clip path is
2487 given in logical coordinates.
2488
2489 \sa setClipPath(), clipRegion(), setClipping()
2490*/
2491QPainterPath QPainter::clipPath() const
2492{
2493 Q_D(const QPainter);
2494
2495 // ### Since we do not support path intersections and path unions yet,
2496 // we just use clipRegion() here...
2497 if (!d->engine) {
2498 qWarning("QPainter::clipPath: Painter not active");
2499 return QPainterPath();
2500 }
2501
2502 // No clip, return empty
2503 if (d->state->clipInfo.size() == 0) {
2504 return QPainterPath();
2505 } else {
2506
2507 // Update inverse matrix, used below.
2508 if (!d->txinv)
2509 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2510
2511 // For the simple case avoid conversion.
2512 if (d->state->clipInfo.size() == 1
2513 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
2514 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2515 return d->state->clipInfo.at(0).path * matrix;
2516
2517 } else if (d->state->clipInfo.size() == 1
2518 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
2519 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2520 QPainterPath path;
2521 path.addRect(d->state->clipInfo.at(0).rect);
2522 return path * matrix;
2523 } else {
2524 // Fallback to clipRegion() for now, since we don't have isect/unite for paths
2525 return qt_regionToPath(clipRegion());
2526 }
2527 }
2528}
2529
2530/*!
2531 \fn void QPainter::setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
2532
2533 Enables clipping, and sets the clip region to the given \a
2534 rectangle using the given clip \a operation. The default operation
2535 is to replace the current clip rectangle.
2536
2537 Note that the clip rectangle is specified in logical (painter)
2538 coordinates.
2539
2540 \sa clipRegion(), setClipping(), {QPainter#Clipping}{Clipping}
2541*/
2542void QPainter::setClipRect(const QRectF &rect, Qt::ClipOperation op)
2543{
2544 Q_D(QPainter);
2545
2546 if (d->extended) {
2547 if (!d->engine) {
2548 qWarning("QPainter::setClipRect: Painter not active");
2549 return;
2550 }
2551 qreal right = rect.x() + rect.width();
2552 qreal bottom = rect.y() + rect.height();
2553 qreal pts[] = { rect.x(), rect.y(),
2554 right, rect.y(),
2555 right, bottom,
2556 rect.x(), bottom };
2557 QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
2558 d->state->clipEnabled = true;
2559 d->extended->clip(vp, op);
2560 d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());
2561 d->state->clipOperation = op;
2562 return;
2563 }
2564
2565 if (qreal(int(rect.top())) == rect.top()
2566 && qreal(int(rect.bottom())) == rect.bottom()
2567 && qreal(int(rect.left())) == rect.left()
2568 && qreal(int(rect.right())) == rect.right())
2569 {
2570 setClipRect(rect.toRect(), op);
2571 return;
2572 }
2573
2574 if (rect.isEmpty()) {
2575 setClipRegion(QRegion(), op);
2576 return;
2577 }
2578
2579 QPainterPath path;
2580 path.addRect(rect);
2581 setClipPath(path, op);
2582}
2583
2584/*!
2585 \fn void QPainter::setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
2586 \overload
2587
2588 Enables clipping, and sets the clip region to the given \a rectangle using the given
2589 clip \a operation.
2590*/
2591void QPainter::setClipRect(const QRect &rect, Qt::ClipOperation op)
2592{
2593 Q_D(QPainter);
2594
2595 if (!d->engine) {
2596 qWarning("QPainter::setClipRect: Painter not active");
2597 return;
2598 }
2599
2600 if (d->extended) {
2601 d->state->clipEnabled = true;
2602 d->extended->clip(rect, op);
2603 d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());
2604 d->state->clipOperation = op;
2605 return;
2606 }
2607
2608 if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))
2609 op = Qt::ReplaceClip;
2610
2611 d->state->clipRegion = rect;
2612 d->state->clipOperation = op;
2613 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2614 d->state->clipInfo.clear();
2615 d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());
2616 d->state->clipEnabled = true;
2617 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2618 d->updateState(d->state);
2619}
2620
2621/*!
2622 \fn void QPainter::setClipRect(int x, int y, int width, int height, Qt::ClipOperation operation)
2623
2624 Enables clipping, and sets the clip region to the rectangle beginning at (\a x, \a y)
2625 with the given \a width and \a height.
2626*/
2627
2628/*!
2629 \fn void QPainter::setClipRegion(const QRegion &region, Qt::ClipOperation operation)
2630
2631 Sets the clip region to the given \a region using the specified clip
2632 \a operation. The default clip operation is to replace the current
2633 clip region.
2634
2635 Note that the clip region is given in logical coordinates.
2636
2637 \sa clipRegion(), setClipRect(), {QPainter#Clipping}{Clipping}
2638*/
2639void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
2640{
2641 Q_D(QPainter);
2642#ifdef QT_DEBUG_DRAW
2643 QRect rect = r.boundingRect();
2644 if (qt_show_painter_debug_output)
2645 printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2646 r.rects().size(), rect.x(), rect.y(), rect.width(), rect.height());
2647#endif
2648 if (!d->engine) {
2649 qWarning("QPainter::setClipRegion: Painter not active");
2650 return;
2651 }
2652
2653 if (d->extended) {
2654 d->state->clipEnabled = true;
2655 d->extended->clip(r, op);
2656 d->state->clipInfo << QPainterClipInfo(r, op, combinedTransform());
2657 d->state->clipOperation = op;
2658 return;
2659 }
2660
2661 if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))
2662 op = Qt::ReplaceClip;
2663
2664 d->state->clipRegion = r;
2665 d->state->clipOperation = op;
2666 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2667 d->state->clipInfo.clear();
2668 d->state->clipInfo << QPainterClipInfo(r, op, combinedTransform());
2669 d->state->clipEnabled = true;
2670 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2671 d->updateState(d->state);
2672}
2673
2674/*!
2675 \since 4.2
2676
2677 Sets the transformation matrix to \a matrix and enables transformations.
2678
2679 \note It is advisable to use setWorldTransform() instead of this function to
2680 preserve the properties of perspective transformations.
2681
2682 If \a combine is true, then \a matrix is combined with the current
2683 transformation matrix; otherwise \a matrix replaces the current
2684 transformation matrix.
2685
2686 If \a matrix is the identity matrix and \a combine is false, this
2687 function calls setWorldMatrixEnabled(false). (The identity matrix is the
2688 matrix where QMatrix::m11() and QMatrix::m22() are 1.0 and the
2689 rest are 0.0.)
2690
2691 The following functions can transform the coordinate system without using
2692 a QMatrix:
2693 \list
2694 \i translate()
2695 \i scale()
2696 \i shear()
2697 \i rotate()
2698 \endlist
2699
2700 They operate on the painter's worldMatrix() and are implemented like this:
2701
2702 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 4
2703
2704 Note that when using setWorldMatrix() function you should always have
2705 \a combine be true when you are drawing into a QPicture. Otherwise
2706 it may not be possible to replay the picture with additional
2707 transformations; using the translate(), scale(), etc. convenience
2708 functions is safe.
2709
2710 For more information about the coordinate system, transformations
2711 and window-viewport conversion, see \l {The Coordinate System}
2712 documentation.
2713
2714 \sa worldMatrixEnabled(), QMatrix
2715*/
2716
2717void QPainter::setWorldMatrix(const QMatrix &matrix, bool combine)
2718{
2719 setWorldTransform(QTransform(matrix), combine);
2720}
2721
2722/*!
2723 \since 4.2
2724
2725 Returns the world transformation matrix.
2726
2727 It is advisable to use worldTransform() because worldMatrix() does not
2728 preserve the properties of perspective transformations.
2729
2730 \sa {QPainter#Coordinate Transformations}{Coordinate Transformations},
2731 {The Coordinate System}
2732*/
2733
2734const QMatrix &QPainter::worldMatrix() const
2735{
2736 Q_D(const QPainter);
2737 if (!d->engine) {
2738 qWarning("QPainter::worldMatrix: Painter not active");
2739 return d->fakeState()->transform.toAffine();
2740 }
2741 return d->state->worldMatrix.toAffine();
2742}
2743
2744/*!
2745 \obsolete
2746
2747 Use setWorldTransform() instead.
2748
2749 \sa setWorldTransform()
2750*/
2751
2752void QPainter::setMatrix(const QMatrix &matrix, bool combine)
2753{
2754 setWorldTransform(QTransform(matrix), combine);
2755}
2756
2757/*!
2758 \obsolete
2759
2760 Use worldTransform() instead.
2761
2762 \sa worldTransform()
2763*/
2764
2765const QMatrix &QPainter::matrix() const
2766{
2767 return worldMatrix();
2768}
2769
2770
2771/*!
2772 \since 4.2
2773
2774 Returns the transformation matrix combining the current
2775 window/viewport and world transformation.
2776
2777 It is advisable to use combinedTransform() instead of this
2778 function to preserve the properties of perspective transformations.
2779
2780 \sa setWorldMatrix(), setWindow(), setViewport()
2781*/
2782QMatrix QPainter::combinedMatrix() const
2783{
2784 return combinedTransform().toAffine();
2785}
2786
2787
2788/*!
2789 Returns the matrix that transforms from logical coordinates to
2790 device coordinates of the platform dependent paint device.
2791
2792 \note It is advisable to use deviceTransform() instead of this
2793 function to preserve the properties of perspective transformations.
2794
2795 This function is \e only needed when using platform painting
2796 commands on the platform dependent handle (Qt::HANDLE), and the
2797 platform does not do transformations nativly.
2798
2799 The QPaintEngine::PaintEngineFeature enum can be queried to
2800 determine whether the platform performs the transformations or
2801 not.
2802
2803 \sa worldMatrix(), QPaintEngine::hasFeature(),
2804*/
2805const QMatrix &QPainter::deviceMatrix() const
2806{
2807 Q_D(const QPainter);
2808 if (!d->engine) {
2809 qWarning("QPainter::deviceMatrix: Painter not active");
2810 return d->fakeState()->transform.toAffine();
2811 }
2812 return d->state->matrix.toAffine();
2813}
2814
2815/*!
2816 Resets any transformations that were made using translate(), scale(),
2817 shear(), rotate(), setWorldMatrix(), setViewport() and
2818 setWindow().
2819
2820 It is advisable to use resetTransform() instead of this function
2821 to preserve the properties of perspective transformations.
2822
2823 \sa {QPainter#Coordinate Transformations}{Coordinate
2824 Transformations}
2825*/
2826
2827void QPainter::resetMatrix()
2828{
2829 resetTransform();
2830}
2831
2832
2833/*!
2834 \since 4.2
2835
2836 Enables transformations if \a enable is true, or disables
2837 transformations if \a enable is false. The world transformation
2838 matrix is not changed.
2839
2840 \sa worldMatrixEnabled(), worldMatrix(), {QPainter#Coordinate
2841 Transformations}{Coordinate Transformations}
2842*/
2843
2844void QPainter::setWorldMatrixEnabled(bool enable)
2845{
2846 Q_D(QPainter);
2847#ifdef QT_DEBUG_DRAW
2848 if (qt_show_painter_debug_output)
2849 printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
2850#endif
2851
2852 if (!d->engine) {
2853 qWarning("QPainter::setMatrixEnabled: Painter not active");
2854 return;
2855 }
2856 if (enable == d->state->WxF)
2857 return;
2858
2859 d->state->WxF = enable;
2860 d->updateMatrix();
2861}
2862
2863/*!
2864 \since 4.2
2865
2866 Returns true if world transformation is enabled; otherwise returns
2867 false.
2868
2869 \sa setWorldMatrixEnabled(), worldMatrix(), {The Coordinate System}
2870*/
2871
2872bool QPainter::worldMatrixEnabled() const
2873{
2874 Q_D(const QPainter);
2875 if (!d->engine) {
2876 qWarning("QPainter::worldMatrixEnabled: Painter not active");
2877 return false;
2878 }
2879 return d->state->WxF;
2880}
2881
2882/*!
2883 \obsolete
2884
2885 Use setWorldMatrixEnabled() instead.
2886
2887 \sa setWorldMatrixEnabled()
2888*/
2889
2890void QPainter::setMatrixEnabled(bool enable)
2891{
2892 setWorldMatrixEnabled(enable);
2893}
2894
2895/*!
2896 \obsolete
2897
2898 Use worldMatrixEnabled() instead
2899
2900 \sa worldMatrixEnabled()
2901*/
2902
2903bool QPainter::matrixEnabled() const
2904{
2905 return worldMatrixEnabled();
2906}
2907
2908/*!
2909 Scales the coordinate system by (\a{sx}, \a{sy}).
2910
2911 \sa setWorldMatrix() {QPainter#Coordinate Transformations}{Coordinate
2912 Transformations}
2913*/
2914
2915void QPainter::scale(qreal sx, qreal sy)
2916{
2917#ifdef QT_DEBUG_DRAW
2918 if (qt_show_painter_debug_output)
2919 printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
2920#endif
2921 Q_D(QPainter);
2922 if (!d->engine) {
2923 qWarning("QPainter::scale: Painter not active");
2924 return;
2925 }
2926
2927 d->state->worldMatrix.scale(sx,sy);
2928 d->state->WxF = true;
2929 d->updateMatrix();
2930}
2931
2932/*!
2933 Shears the coordinate system by (\a{sh}, \a{sv}).
2934
2935 \sa setWorldMatrix(), {QPainter#Coordinate Transformations}{Coordinate
2936 Transformations}
2937*/
2938
2939void QPainter::shear(qreal sh, qreal sv)
2940{
2941#ifdef QT_DEBUG_DRAW
2942 if (qt_show_painter_debug_output)
2943 printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
2944#endif
2945 Q_D(QPainter);
2946 if (!d->engine) {
2947 qWarning("QPainter::shear: Painter not active");
2948 return;
2949 }
2950
2951 d->state->worldMatrix.shear(sh, sv);
2952 d->state->WxF = true;
2953 d->updateMatrix();
2954}
2955
2956/*!
2957 \fn void QPainter::rotate(qreal angle)
2958
2959 Rotates the coordinate system the given \a angle clockwise.
2960
2961 \sa setWorldMatrix(), {QPainter#Coordinate Transformations}{Coordinate
2962 Transformations}
2963*/
2964
2965void QPainter::rotate(qreal a)
2966{
2967#ifdef QT_DEBUG_DRAW
2968 if (qt_show_painter_debug_output)
2969 printf("QPainter::rotate(), angle=%f\n", a);
2970#endif
2971 Q_D(QPainter);
2972 if (!d->engine) {
2973 qWarning("QPainter::rotate: Painter not active");
2974 return;
2975 }
2976
2977 d->state->worldMatrix.rotate(a);
2978 d->state->WxF = true;
2979 d->updateMatrix();
2980}
2981
2982/*!
2983 Translates the coordinate system by the given \a offset; i.e. the
2984 given \a offset is added to points.
2985
2986 \sa setWorldMatrix(), {QPainter#Coordinate Transformations}{Coordinate
2987 Transformations}
2988*/
2989void QPainter::translate(const QPointF &offset)
2990{
2991 qreal dx = offset.x();
2992 qreal dy = offset.y();
2993#ifdef QT_DEBUG_DRAW
2994 if (qt_show_painter_debug_output)
2995 printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
2996#endif
2997 Q_D(QPainter);
2998 if (!d->engine) {
2999 qWarning("QPainter::translate: Painter not active");
3000 return;
3001 }
3002
3003 d->state->worldMatrix.translate(dx, dy);
3004 d->state->WxF = true;
3005 d->updateMatrix();
3006}
3007
3008/*!
3009 \fn void QPainter::translate(const QPoint &offset)
3010 \overload
3011
3012 Translates the coordinate system by the given \a offset.
3013*/
3014
3015/*!
3016 \fn void QPainter::translate(qreal dx, qreal dy)
3017 \overload
3018
3019 Translates the coordinate system by the vector (\a dx, \a dy).
3020*/
3021
3022/*!
3023 \fn void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
3024
3025 Enables clipping, and sets the clip path for the painter to the
3026 given \a path, with the clip \a operation.
3027
3028 Note that the clip path is specified in logical (painter)
3029 coordinates.
3030
3031 \sa clipPath(), clipRegion(), {QPainter#Clipping}{Clipping}
3032
3033*/
3034void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
3035{
3036#ifdef QT_DEBUG_DRAW
3037 if (qt_show_painter_debug_output) {
3038 QRectF b = path.boundingRect();
3039 printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3040 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3041 }
3042#endif
3043 Q_D(QPainter);
3044
3045 if (!d->engine) {
3046 qWarning("QPainter::setClipPath: Painter not active");
3047 return;
3048 }
3049
3050 if (d->extended) {
3051 d->state->clipEnabled = true;
3052 d->extended->clip(path, op);
3053 d->state->clipInfo << QPainterClipInfo(path, op, combinedTransform());
3054 d->state->clipOperation = op;
3055 return;
3056 }
3057
3058
3059
3060 if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))
3061 op = Qt::ReplaceClip;
3062
3063 d->state->clipPath = path;
3064 d->state->clipOperation = op;
3065 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3066 d->state->clipInfo.clear();
3067 d->state->clipInfo << QPainterClipInfo(path, op, combinedTransform());
3068 d->state->clipEnabled = true;
3069 d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
3070 d->updateState(d->state);
3071}
3072
3073/*!
3074 Draws the outline (strokes) the path \a path with the pen specified
3075 by \a pen
3076
3077 \sa fillPath(), {QPainter#Drawing}{Drawing}
3078*/
3079void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
3080{
3081 Q_D(QPainter);
3082
3083 if (!d->engine) {
3084 qWarning("QPainter::strokePath: Painter not active");
3085 return;
3086 }
3087
3088 if (path.isEmpty())
3089 return;
3090
3091 if (d->extended) {
3092 const QGradient *g = qpen_brush(pen).gradient();
3093 if (!g || g->coordinateMode() == QGradient::LogicalMode) {
3094 d->extended->stroke(qtVectorPathForPath(path), pen);
3095 return;
3096 }
3097 }
3098
3099 QBrush oldBrush = d->state->brush;
3100 QPen oldPen = d->state->pen;
3101
3102 setPen(pen);
3103 setBrush(Qt::NoBrush);
3104
3105 drawPath(path);
3106
3107 // Reset old state
3108 setPen(oldPen);
3109 setBrush(oldBrush);
3110}
3111
3112/*!
3113 Fills the given \a path using the given \a brush. The outline is
3114 not drawn.
3115
3116 Alternatively, you can specify a QColor instead of a QBrush; the
3117 QBrush constructor (taking a QColor argument) will automatically
3118 create a solid pattern brush.
3119
3120 \sa drawPath()
3121*/
3122void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
3123{
3124 Q_D(QPainter);
3125
3126 if (!d->engine) {
3127 qWarning("QPainter::fillPath: Painter not active");
3128 return;
3129 }
3130
3131 if (path.isEmpty())
3132 return;
3133
3134 if (d->extended) {
3135 const QGradient *g = brush.gradient();
3136 if (!g || g->coordinateMode() == QGradient::LogicalMode) {
3137 d->extended->fill(qtVectorPathForPath(path), brush);
3138 return;
3139 }
3140 }
3141
3142 QBrush oldBrush = d->state->brush;
3143 QPen oldPen = d->state->pen;
3144
3145 setPen(Qt::NoPen);
3146 setBrush(brush);
3147
3148 drawPath(path);
3149
3150 // Reset old state
3151 setPen(oldPen);
3152 setBrush(oldBrush);
3153}
3154
3155/*!
3156 Draws the given painter \a path using the current pen for outline
3157 and the current brush for filling.
3158
3159 \table 100%
3160 \row
3161 \o \inlineimage qpainter-path.png
3162 \o
3163 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 5
3164 \endtable
3165
3166 \sa {painting/painterpaths}{the Painter Paths
3167 example},{demos/deform}{the Vector Deformation demo}
3168*/
3169void QPainter::drawPath(const QPainterPath &path)
3170{
3171#ifdef QT_DEBUG_DRAW
3172 QRectF pathBounds = path.boundingRect();
3173 if (qt_show_painter_debug_output)
3174 printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
3175 path.elementCount(),
3176 pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
3177#endif
3178
3179 Q_D(QPainter);
3180
3181 if (!d->engine) {
3182 qWarning("QPainter::drawPath: Painter not active");
3183 return;
3184 }
3185
3186 if (d->extended) {
3187 d->extended->drawPath(path);
3188 return;
3189 }
3190 d->updateState(d->state);
3191
3192 if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
3193 d->engine->drawPath(path);
3194 } else {
3195 d->draw_helper(path);
3196 }
3197}
3198
3199/*!
3200 \fn void QPainter::drawLine(const QLineF &line)
3201
3202 Draws a line defined by \a line.
3203
3204 \table 100%
3205 \row
3206 \o \inlineimage qpainter-line.png
3207 \o
3208 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 6
3209 \endtable
3210
3211 \sa drawLines(), drawPolyline(), {The Coordinate System}
3212*/
3213
3214/*!
3215 \fn void QPainter::drawLine(const QLine &line)
3216 \overload
3217
3218 Draws a line defined by \a line.
3219*/
3220
3221/*!
3222 \fn void QPainter::drawLine(const QPoint &p1, const QPoint &p2)
3223 \overload
3224
3225 Draws a line from \a p1 to \a p2.
3226*/
3227
3228/*!
3229 \fn void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
3230 \overload
3231
3232 Draws a line from \a p1 to \a p2.
3233*/
3234
3235/*!
3236 \fn void QPainter::drawLine(int x1, int y1, int x2, int y2)
3237 \overload
3238
3239 Draws a line from (\a x1, \a y1) to (\a x2, \a y2) and sets the
3240 current pen position to (\a x2, \a y2).
3241*/
3242
3243/*!
3244 \fn void QPainter::drawRect(const QRectF &rectangle)
3245
3246 Draws the current \a rectangle with the current pen and brush.
3247
3248 A filled rectangle has a size of \a{rectangle}.size(). A stroked
3249 rectangle has a size of \a{rectangle}.size() plus the pen width.
3250
3251 \table 100%
3252 \row
3253 \o \inlineimage qpainter-rectangle.png
3254 \o
3255 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 7
3256 \endtable
3257
3258 \sa drawRects(), drawPolygon(), {The Coordinate System}
3259*/
3260
3261/*!
3262 \fn void QPainter::drawRect(const QRect &rectangle)
3263
3264 \overload
3265
3266 Draws the current \a rectangle with the current pen and brush.
3267*/
3268
3269/*!
3270 \fn void QPainter::drawRect(int x, int y, int width, int height)
3271
3272 \overload
3273
3274 Draws a rectangle with upper left corner at (\a{x}, \a{y}) and
3275 with the given \a width and \a height.
3276*/
3277
3278/*!
3279 \fn void QPainter::drawRects(const QRectF *rectangles, int rectCount)
3280
3281 Draws the first \a rectCount of the given \a rectangles using the
3282 current pen and brush.
3283
3284 \sa drawRect()
3285*/
3286void QPainter::drawRects(const QRectF *rects, int rectCount)
3287{
3288#ifdef QT_DEBUG_DRAW
3289 if (qt_show_painter_debug_output)
3290 printf("QPainter::drawRects(), count=%d\n", rectCount);
3291#endif
3292 Q_D(QPainter);
3293
3294 if (!d->engine) {
3295 qWarning("QPainter::drawRects: Painter not active");
3296 return;
3297 }
3298
3299 if (rectCount <= 0)
3300 return;
3301
3302 if (d->extended) {
3303 d->extended->drawRects(rects, rectCount);
3304 return;
3305 }
3306
3307 d->updateState(d->state);
3308
3309 if (!d->state->emulationSpecifier) {
3310 d->engine->drawRects(rects, rectCount);
3311 return;
3312 }
3313
3314 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3315 && d->state->matrix.type() == QTransform::TxTranslate) {
3316 for (int i=0; i<rectCount; ++i) {
3317 QRectF r(rects[i].x() + d->state->matrix.dx(),
3318 rects[i].y() + d->state->matrix.dy(),
3319 rects[i].width(),
3320 rects[i].height());
3321 d->engine->drawRects(&r, 1);
3322 }
3323 } else {
3324 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3325 for (int i=0; i<rectCount; ++i) {
3326 QPainterPath rectPath;
3327 rectPath.addRect(rects[i]);
3328 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3329 }
3330 } else {
3331 QPainterPath rectPath;
3332 for (int i=0; i<rectCount; ++i)
3333 rectPath.addRect(rects[i]);
3334 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3335 }
3336 }
3337}
3338
3339/*!
3340 \fn void QPainter::drawRects(const QRect *rectangles, int rectCount)
3341 \overload
3342
3343 Draws the first \a rectCount of the given \a rectangles using the
3344 current pen and brush.
3345*/
3346void QPainter::drawRects(const QRect *rects, int rectCount)
3347{
3348#ifdef QT_DEBUG_DRAW
3349 if (qt_show_painter_debug_output)
3350 printf("QPainter::drawRects(), count=%d\n", rectCount);
3351#endif
3352 Q_D(QPainter);
3353
3354 if (!d->engine) {
3355 qWarning("QPainter::drawRects: Painter not active");
3356 return;
3357 }
3358
3359 if (rectCount <= 0)
3360 return;
3361
3362 if (d->extended) {
3363 d->extended->drawRects(rects, rectCount);
3364 return;
3365 }
3366
3367 d->updateState(d->state);
3368
3369 if (!d->state->emulationSpecifier) {
3370 d->engine->drawRects(rects, rectCount);
3371 return;
3372 }
3373
3374 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3375 && d->state->matrix.type() == QTransform::TxTranslate) {
3376 for (int i=0; i<rectCount; ++i) {
3377 QRectF r(rects[i].x() + d->state->matrix.dx(),
3378 rects[i].y() + d->state->matrix.dy(),
3379 rects[i].width(),
3380 rects[i].height());
3381
3382 d->engine->drawRects(&r, 1);
3383 }
3384 } else {
3385 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3386 for (int i=0; i<rectCount; ++i) {
3387 QPainterPath rectPath;
3388 rectPath.addRect(rects[i]);
3389 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3390 }
3391 } else {
3392 QPainterPath rectPath;
3393 for (int i=0; i<rectCount; ++i)
3394 rectPath.addRect(rects[i]);
3395
3396 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3397 }
3398 }
3399}
3400
3401/*!
3402 \fn void QPainter::drawRects(const QVector<QRectF> &rectangles)
3403 \overload
3404
3405 Draws the given \a rectangles using the current pen and brush.
3406*/
3407
3408/*!
3409 \fn void QPainter::drawRects(const QVector<QRect> &rectangles)
3410
3411 \overload
3412
3413 Draws the given \a rectangles using the current pen and brush.
3414*/
3415
3416/*!
3417 \fn void QPainter::drawPoint(const QPointF &position)
3418
3419 Draws a single point at the given \a position using the current
3420 pen's color.
3421
3422 \sa {The Coordinate System}
3423*/
3424
3425/*!
3426 \fn void QPainter::drawPoint(const QPoint &position)
3427 \overload
3428
3429 Draws a single point at the given \a position using the current
3430 pen's color.
3431*/
3432
3433/*! \fn void QPainter::drawPoint(int x, int y)
3434
3435 \overload
3436
3437 Draws a single point at position (\a x, \a y).
3438*/
3439
3440/*!
3441 Draws the first \a pointCount points in the array \a points using
3442 the current pen's color.
3443
3444 \sa {The Coordinate System}
3445*/
3446void QPainter::drawPoints(const QPointF *points, int pointCount)
3447{
3448#ifdef QT_DEBUG_DRAW
3449 if (qt_show_painter_debug_output)
3450 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3451#endif
3452 Q_D(QPainter);
3453
3454 if (!d->engine) {
3455 qWarning("QPainter::drawPoints: Painter not active");
3456 return;
3457 }
3458
3459 if (pointCount <= 0)
3460 return;
3461
3462 if (d->extended) {
3463 d->extended->drawPoints(points, pointCount);
3464 return;
3465 }
3466
3467 d->updateState(d->state);
3468
3469 if (!d->state->emulationSpecifier) {
3470 d->engine->drawPoints(points, pointCount);
3471 return;
3472 }
3473
3474 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3475 && d->state->matrix.type() == QTransform::TxTranslate) {
3476 // ### use drawPoints function
3477 for (int i=0; i<pointCount; ++i) {
3478 QPointF pt(points[i].x() + d->state->matrix.dx(),
3479 points[i].y() + d->state->matrix.dy());
3480 d->engine->drawPoints(&pt, 1);
3481 }
3482 } else {
3483 QPen pen = d->state->pen;
3484 bool flat_pen = pen.capStyle() == Qt::FlatCap;
3485 if (flat_pen) {
3486 save();
3487 pen.setCapStyle(Qt::SquareCap);
3488 setPen(pen);
3489 }
3490 QPainterPath path;
3491 for (int i=0; i<pointCount; ++i) {
3492 path.moveTo(points[i].x(), points[i].y());
3493 path.lineTo(points[i].x() + 0.0001, points[i].y());
3494 }
3495 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3496 if (flat_pen)
3497 restore();
3498 }
3499}
3500
3501/*!
3502 \overload
3503
3504 Draws the first \a pointCount points in the array \a points using
3505 the current pen's color.
3506*/
3507
3508void QPainter::drawPoints(const QPoint *points, int pointCount)
3509{
3510#ifdef QT_DEBUG_DRAW
3511 if (qt_show_painter_debug_output)
3512 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3513#endif
3514 Q_D(QPainter);
3515
3516 if (!d->engine) {
3517 qWarning("QPainter::drawPoints: Painter not active");
3518 return;
3519 }
3520
3521 if (pointCount <= 0)
3522 return;
3523
3524 if (d->extended) {
3525 d->extended->drawPoints(points, pointCount);
3526 return;
3527 }
3528
3529 d->updateState(d->state);
3530
3531 if (!d->state->emulationSpecifier) {
3532 d->engine->drawPoints(points, pointCount);
3533 return;
3534 }
3535
3536 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3537 && d->state->matrix.type() == QTransform::TxTranslate) {
3538 // ### use drawPoints function
3539 for (int i=0; i<pointCount; ++i) {
3540 QPointF pt(points[i].x() + d->state->matrix.dx(),
3541 points[i].y() + d->state->matrix.dy());
3542 d->engine->drawPoints(&pt, 1);
3543 }
3544 } else {
3545 QPen pen = d->state->pen;
3546 bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3547 if (flat_pen) {
3548 save();
3549 pen.setCapStyle(Qt::SquareCap);
3550 setPen(pen);
3551 }
3552 QPainterPath path;
3553 for (int i=0; i<pointCount; ++i) {
3554 path.moveTo(points[i].x(), points[i].y());
3555 path.lineTo(points[i].x() + 0.0001, points[i].y());
3556 }
3557 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3558 if (flat_pen)
3559 restore();
3560 }
3561}
3562
3563/*!
3564 \fn void QPainter::drawPoints(const QPolygonF &points)
3565
3566 \overload
3567
3568 Draws the points in the vector \a points.
3569*/
3570
3571/*!
3572 \fn void QPainter::drawPoints(const QPolygon &points)
3573
3574 \overload
3575
3576 Draws the points in the vector \a points.
3577*/
3578
3579/*!
3580 \fn void QPainter::drawPoints(const QPolygon &polygon, int index,
3581 int count)
3582
3583 \overload
3584 \compat
3585
3586 Draws \a count points in the vector \a polygon starting on \a index
3587 using the current pen.
3588
3589 Use drawPoints() combined with QPolygon::constData() instead.
3590
3591 \oldcode
3592 QPainter painter(this);
3593 painter.drawPoints(polygon, index, count);
3594 \newcode
3595 int pointCount = (count == -1) ? polygon.size() - index : count;
3596
3597 QPainter painter(this);
3598 painter.drawPoints(polygon.constData() + index, pointCount);
3599 \endcode
3600*/
3601
3602/*!
3603 Sets the background mode of the painter to the given \a mode
3604
3605 Qt::TransparentMode (the default) draws stippled lines and text
3606 without setting the background pixels. Qt::OpaqueMode fills these
3607 space with the current background color.
3608
3609 Note that in order to draw a bitmap or pixmap transparently, you
3610 must use QPixmap::setMask().
3611
3612 \sa backgroundMode(), setBackground(),
3613 {QPainter#Settings}{Settings}
3614*/
3615
3616void QPainter::setBackgroundMode(Qt::BGMode mode)
3617{
3618#ifdef QT_DEBUG_DRAW
3619 if (qt_show_painter_debug_output)
3620 printf("QPainter::setBackgroundMode(), mode=%d\n", mode);
3621#endif
3622
3623 Q_D(QPainter);
3624 if (!d->engine) {
3625 qWarning("QPainter::setBackgroundMode: Painter not active");
3626 return;
3627 }
3628 if (d->state->bgMode == mode)
3629 return;
3630
3631 d->state->bgMode = mode;
3632 if (d->extended) {
3633 d->checkEmulation();
3634 } else {
3635 d->state->dirtyFlags |= QPaintEngine::DirtyBackgroundMode;
3636 }
3637}
3638
3639/*!
3640 Returns the current background mode.
3641
3642 \sa setBackgroundMode(), {QPainter#Settings}{Settings}
3643*/
3644Qt::BGMode QPainter::backgroundMode() const
3645{
3646 Q_D(const QPainter);
3647 if (!d->engine) {
3648 qWarning("QPainter::backgroundMode: Painter not active");
3649 return Qt::TransparentMode;
3650 }
3651 return d->state->bgMode;
3652}
3653
3654
3655/*!
3656 \overload
3657
3658 Sets the painter's pen to have style Qt::SolidLine, width 0 and the
3659 specified \a color.
3660*/
3661
3662void QPainter::setPen(const QColor &color)
3663{
3664#ifdef QT_DEBUG_DRAW
3665 if (qt_show_painter_debug_output)
3666 printf("QPainter::setPen(), color=%04x\n", color.rgb());
3667#endif
3668 Q_D(QPainter);
3669 if (!d->engine) {
3670 qWarning("QPainter::setPen: Painter not active");
3671 return;
3672 }
3673
3674 if (d->state->pen.style() == Qt::SolidLine
3675 && d->state->pen.widthF() == 0
3676 && d->state->pen.isSolid()
3677 && d->state->pen.color() == color)
3678 return;
3679
3680 QPen pen(color.isValid() ? color : QColor(Qt::black), 0, Qt::SolidLine);
3681
3682 d->state->pen = pen;
3683 if (d->extended)
3684 d->extended->penChanged();
3685 else
3686 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3687}
3688
3689/*!
3690 Sets the painter's pen to be the given \a pen.
3691
3692 The \a pen defines how to draw lines and outlines, and it also
3693 defines the text color.
3694
3695 \sa pen(), {QPainter#Settings}{Settings}
3696*/
3697
3698void QPainter::setPen(const QPen &pen)
3699{
3700
3701#ifdef QT_DEBUG_DRAW
3702 if (qt_show_painter_debug_output)
3703 printf("QPainter::setPen(), color=%04x, (brushStyle=%d) style=%d, cap=%d, join=%d\n",
3704 pen.color().rgb(), pen.brush().style(), pen.style(), pen.capStyle(), pen.joinStyle());
3705#endif
3706 Q_D(QPainter);
3707 if (!d->engine) {
3708 qWarning("QPainter::setPen: Painter not active");
3709 return;
3710 }
3711
3712 if (d->state->pen == pen)
3713 return;
3714
3715 if (d->extended) {
3716 d->state->pen = pen;
3717 d->checkEmulation();
3718 d->extended->penChanged();
3719 return;
3720 }
3721
3722 // Do some checks to see if we are the same pen.
3723 Qt::PenStyle currentStyle = d->state->pen.style();
3724 if (currentStyle == pen.style() && currentStyle != Qt::CustomDashLine) {
3725 if (currentStyle == Qt::NoPen ||
3726 (d->state->pen.isSolid() && pen.isSolid()
3727 && d->state->pen.color() == pen.color()
3728 && d->state->pen.widthF() == pen.widthF()
3729 && d->state->pen.capStyle() == pen.capStyle()
3730 && d->state->pen.joinStyle() == pen.joinStyle()
3731 && d->state->pen.isCosmetic() == pen.isCosmetic()))
3732 return;
3733 }
3734
3735 d->state->pen = pen;
3736 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3737}
3738
3739/*!
3740 \overload
3741
3742 Sets the painter's pen to have the given \a style, width 0 and
3743 black color.
3744*/
3745
3746void QPainter::setPen(Qt::PenStyle style)
3747{
3748 Q_D(QPainter);
3749 if (!d->engine) {
3750 qWarning("QPainter::setPen: Painter not active");
3751 return;
3752 }
3753
3754 if (d->state->pen.style() == style
3755 && (style == Qt::NoPen || (d->state->pen.widthF() == 0
3756 && d->state->pen.isSolid()
3757 && d->state->pen.color() == QColor(Qt::black))))
3758 return;
3759
3760 // QPen(Qt::NoPen) is to avoid creating QPenData, including its brush (from the color)
3761 // Note that this works well as long as QPen(Qt::NoPen) returns a black, zero-width pen
3762 d->state->pen = (style == Qt::NoPen) ? QPen(Qt::NoPen) : QPen(Qt::black, 0, style);
3763
3764 if (d->extended)
3765 d->extended->penChanged();
3766 else
3767 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3768
3769}
3770
3771/*!
3772 Returns the painter's current pen.
3773
3774 \sa setPen(), {QPainter#Settings}{Settings}
3775*/
3776
3777const QPen &QPainter::pen() const
3778{
3779 Q_D(const QPainter);
3780 if (!d->engine) {
3781 qWarning("QPainter::pen: Painter not active");
3782 return d->fakeState()->pen;
3783 }
3784 return d->state->pen;
3785}
3786
3787
3788/*!
3789 Sets the painter's brush to the given \a brush.
3790
3791 The painter's brush defines how shapes are filled.
3792
3793 \sa brush(), {QPainter#Settings}{Settings}
3794*/
3795
3796void QPainter::setBrush(const QBrush &brush)
3797{
3798#ifdef QT_DEBUG_DRAW
3799 if (qt_show_painter_debug_output)
3800 printf("QPainter::setBrush(), color=%04x, style=%d\n", brush.color().rgb(), brush.style());
3801#endif
3802 Q_D(QPainter);
3803 if (!d->engine) {
3804 qWarning("QPainter::setBrush: Painter not active");
3805 return;
3806 }
3807
3808 if (d->state->brush.d == brush.d)
3809 return;
3810
3811 if (d->extended) {
3812 d->state->brush = brush;
3813 d->checkEmulation();
3814 d->extended->brushChanged();
3815 return;
3816 }
3817
3818 Qt::BrushStyle currentStyle = d->state->brush.style();
3819 if (currentStyle == brush.style()) {
3820 if (currentStyle == Qt::NoBrush
3821 || (currentStyle == Qt::SolidPattern
3822 && d->state->brush.color() == brush.color()))
3823 return;
3824 }
3825
3826 d->state->brush = brush;
3827 d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3828}
3829
3830
3831/*!
3832 \overload
3833
3834 Sets the painter's brush to black color and the specified \a
3835 style.
3836*/
3837
3838void QPainter::setBrush(Qt::BrushStyle style)
3839{
3840 Q_D(QPainter);
3841 if (!d->engine) {
3842 qWarning("QPainter::setBrush: Painter not active");
3843 return;
3844 }
3845 if (d->state->brush.style() == style &&
3846 (style == Qt::NoBrush
3847 || (style == Qt::SolidPattern && d->state->brush.color() == QColor(0, 0, 0))))
3848 return;
3849 d->state->brush = QBrush(Qt::black, style);
3850 if (d->extended)
3851 d->extended->brushChanged();
3852 else
3853 d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3854}
3855
3856/*!
3857 Returns the painter's current brush.
3858
3859 \sa QPainter::setBrush(), {QPainter#Settings}{Settings}
3860*/
3861
3862const QBrush &QPainter::brush() const
3863{
3864 Q_D(const QPainter);
3865 if (!d->engine) {
3866 qWarning("QPainter::brush: Painter not active");
3867 return d->fakeState()->brush;
3868 }
3869 return d->state->brush;
3870}
3871
3872/*!
3873 \fn void QPainter::setBackground(const QBrush &brush)
3874
3875 Sets the background brush of the painter to the given \a brush.
3876
3877 The background brush is the brush that is filled in when drawing
3878 opaque text, stippled lines and bitmaps. The background brush has
3879 no effect in transparent background mode (which is the default).
3880
3881 \sa background(), setBackgroundMode(),
3882 {QPainter#Settings}{Settings}
3883*/
3884
3885void QPainter::setBackground(const QBrush &bg)
3886{
3887#ifdef QT_DEBUG_DRAW
3888 if (qt_show_painter_debug_output)
3889 printf("QPainter::setBackground(), color=%04x, style=%d\n", bg.color().rgb(), bg.style());
3890#endif
3891
3892 Q_D(QPainter);
3893 if (!d->engine) {
3894 qWarning("QPainter::setBackground: Painter not active");
3895 return;
3896 }
3897 d->state->bgBrush = bg;
3898 if (!d->extended)
3899 d->state->dirtyFlags |= QPaintEngine::DirtyBackground;
3900}
3901
3902/*!
3903 Sets the painter's font to the given \a font.
3904
3905 This font is used by subsequent drawText() functions. The text
3906 color is the same as the pen color.
3907
3908 If you set a font that isn't available, Qt finds a close match.
3909 font() will return what you set using setFont() and fontInfo() returns the
3910 font actually being used (which may be the same).
3911
3912 \sa font(), drawText(), {QPainter#Settings}{Settings}
3913*/
3914
3915void QPainter::setFont(const QFont &font)
3916{
3917 Q_D(QPainter);
3918
3919#ifdef QT_DEBUG_DRAW
3920 if (qt_show_painter_debug_output)
3921 printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.family().toLatin1().constData(), font.pointSize());
3922#endif
3923
3924 if (!d->engine) {
3925 qWarning("QPainter::setFont: Painter not active");
3926 return;
3927 }
3928
3929 d->state->font = QFont(font.resolve(d->state->deviceFont), device());
3930 if (!d->extended)
3931 d->state->dirtyFlags |= QPaintEngine::DirtyFont;
3932}
3933
3934/*!
3935 Returns the currently set font used for drawing text.
3936
3937 \sa setFont(), drawText(), {QPainter#Settings}{Settings}
3938*/
3939const QFont &QPainter::font() const
3940{
3941 Q_D(const QPainter);
3942 if (!d->engine) {
3943 qWarning("QPainter::font: Painter not active");
3944 return d->fakeState()->font;
3945 }
3946 return d->state->font;
3947}
3948
3949/*!
3950 \since 4.4
3951
3952 Draws the given rectangle \a rect with rounded corners.
3953
3954 The \a xRadius and \a yRadius arguments specify the radii
3955 of the ellipses defining the corners of the rounded rectangle.
3956 When \a mode is Qt::RelativeSize, \a xRadius and
3957 \a yRadius are specified in percentage of half the rectangle's
3958 width and height respectively, and should be in the range
3959 0.0 to 100.0.
3960
3961 A filled rectangle has a size of rect.size(). A stroked rectangle
3962 has a size of rect.size() plus the pen width.
3963
3964 \table 100%
3965 \row
3966 \o \inlineimage qpainter-roundrect.png
3967 \o
3968 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 8
3969 \endtable
3970
3971 \sa drawRect(), QPen
3972*/
3973// FALCON: Should we add a specialized method in QPaintEngineEx?
3974void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
3975{
3976#ifdef QT_DEBUG_DRAW
3977 if (qt_show_painter_debug_output)
3978 printf("QPainter::drawRoundedRect(), [%.2f,%.2f,%.2f,%.2f]\n", rect.x(), rect.y(), rect.width(), rect.height());
3979#endif
3980 Q_D(QPainter);
3981
3982 if (!d->engine)
3983 return;
3984
3985 if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
3986 drawRect(rect);
3987 return;
3988 }
3989
3990 if (d->extended) {
3991 QPainterPath::ElementType types[] = {
3992 QPainterPath::MoveToElement,
3993 QPainterPath::LineToElement,
3994 QPainterPath::CurveToElement,
3995 QPainterPath::CurveToDataElement,
3996 QPainterPath::CurveToDataElement,
3997 QPainterPath::LineToElement,
3998 QPainterPath::CurveToElement,
3999 QPainterPath::CurveToDataElement,
4000 QPainterPath::CurveToDataElement,
4001 QPainterPath::LineToElement,
4002 QPainterPath::CurveToElement,
4003 QPainterPath::CurveToDataElement,
4004 QPainterPath::CurveToDataElement,
4005 QPainterPath::LineToElement,
4006 QPainterPath::CurveToElement,
4007 QPainterPath::CurveToDataElement,
4008 QPainterPath::CurveToDataElement
4009 };
4010
4011 qreal x1 = rect.left();
4012 qreal x2 = rect.right();
4013 qreal y1 = rect.top();
4014 qreal y2 = rect.bottom();
4015
4016 if (mode == Qt::RelativeSize) {
4017 xRadius = xRadius * rect.width() / 200.;
4018 yRadius = yRadius * rect.height() / 200.;
4019 }
4020
4021 xRadius = qMin(xRadius, rect.width() / 2);
4022 yRadius = qMin(yRadius, rect.height() / 2);
4023
4024 qreal pts[] = {
4025 x1 + xRadius, y1, // MoveTo
4026 x2 - xRadius, y1, // LineTo
4027 x2 - (1 - KAPPA) * xRadius, y1, // CurveTo
4028 x2, y1 + (1 - KAPPA) * yRadius,
4029 x2, y1 + yRadius,
4030 x2, y2 - yRadius, // LineTo
4031 x2, y2 - (1 - KAPPA) * yRadius, // CurveTo
4032 x2 - (1 - KAPPA) * xRadius, y2,
4033 x2 - xRadius, y2,
4034 x1 + xRadius, y2, // LineTo
4035 x1 + (1 - KAPPA) * xRadius, y2, // CurveTo
4036 x1, y2 - (1 - KAPPA) * yRadius,
4037 x1, y2 - yRadius,
4038 x1, y1 + yRadius, // LineTo
4039 x1, y1 + KAPPA * yRadius, // CurveTo
4040 x1 + (1 - KAPPA) * xRadius, y1,
4041 x1 + xRadius, y1
4042 };
4043
4044 QVectorPath path(pts, 17, types);
4045 d->extended->draw(path);
4046 return;
4047 }
4048
4049 QPainterPath path;
4050 path.addRoundedRect(rect, xRadius, yRadius, mode);
4051 drawPath(path);
4052}
4053
4054/*!
4055 \fn void QPainter::drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius,
4056 Qt::SizeMode mode = Qt::AbsoluteSize);
4057 \since 4.4
4058 \overload
4059
4060 Draws the given rectangle \a rect with rounded corners.
4061*/
4062
4063/*!
4064 \fn void QPainter::drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius,
4065 Qt::SizeMode mode = Qt::AbsoluteSize);
4066 \since 4.4
4067 \overload
4068
4069 Draws the given rectangle \a x, \a y, \a w, \a h with rounded corners.
4070*/
4071
4072/*!
4073 \obsolete
4074
4075 Draws a rectangle \a r with rounded corners.
4076
4077 The \a xRnd and \a yRnd arguments specify how rounded the corners
4078 should be. 0 is angled corners, 99 is maximum roundedness.
4079
4080 A filled rectangle has a size of r.size(). A stroked rectangle
4081 has a size of r.size() plus the pen width.
4082
4083 \sa drawRoundedRect()
4084*/
4085void QPainter::drawRoundRect(const QRectF &r, int xRnd, int yRnd)
4086{
4087#ifdef QT_DEBUG_DRAW
4088 if (qt_show_painter_debug_output)
4089 printf("QPainter::drawRoundRectangle(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
4090#endif
4091 Q_D(QPainter);
4092
4093 if (!d->engine)
4094 return;
4095
4096 if(xRnd <= 0 || yRnd <= 0) { // draw normal rectangle
4097 drawRect(r);
4098 return;
4099 }
4100
4101 QPainterPath path;
4102 path.addRoundRect(r, xRnd, yRnd);
4103 drawPath(path);
4104}
4105
4106
4107/*!
4108 \fn void QPainter::drawRoundRect(const QRect &r, int xRnd = 25, int yRnd = 25)
4109
4110 \overload
4111 \obsolete
4112
4113 Draws the rectangle \a r with rounded corners.
4114*/
4115
4116/*!
4117 \obsolete
4118
4119 \fn QPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd)
4120
4121 \overload
4122
4123 Draws the rectangle \a x, \a y, \a w, \a h with rounded corners.
4124*/
4125
4126/*!
4127 \fn void QPainter::drawEllipse(const QRectF &rectangle)
4128
4129 Draws the ellipse defined by the given \a rectangle.
4130
4131 A filled ellipse has a size of \a{rectangle}.\l
4132 {QRect::size()}{size()}. A stroked ellipse has a size of
4133 \a{rectangle}.\l {QRect::size()}{size()} plus the pen width.
4134
4135 \table 100%
4136 \row
4137 \o \inlineimage qpainter-ellipse.png
4138 \o
4139 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 9
4140 \endtable
4141
4142 \sa drawPie(), {The Coordinate System}
4143*/
4144void QPainter::drawEllipse(const QRectF &r)
4145{
4146#ifdef QT_DEBUG_DRAW
4147 if (qt_show_painter_debug_output)
4148 printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
4149#endif
4150 Q_D(QPainter);
4151
4152 if (!d->engine)
4153 return;
4154
4155 QRectF rect(r.normalized());
4156 if (rect.isEmpty())
4157 return;
4158
4159 if (d->extended) {
4160 d->extended->drawEllipse(rect);
4161 return;
4162 }
4163
4164 d->updateState(d->state);
4165 if (d->state->emulationSpecifier) {
4166 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4167 && d->state->matrix.type() == QTransform::TxTranslate) {
4168 rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
4169 } else {
4170 QPainterPath path;
4171 path.addEllipse(rect);
4172 d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
4173 return;
4174 }
4175 }
4176
4177 d->engine->drawEllipse(rect);
4178}
4179
4180/*!
4181 \fn QPainter::drawEllipse(const QRect &rectangle)
4182
4183 \overload
4184
4185 Draws the ellipse defined by the given \a rectangle.
4186*/
4187void QPainter::drawEllipse(const QRect &r)
4188{
4189#ifdef QT_DEBUG_DRAW
4190 if (qt_show_painter_debug_output)
4191 printf("QPainter::drawEllipse(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
4192#endif
4193 Q_D(QPainter);
4194
4195 if (!d->engine)
4196 return;
4197
4198 QRect rect(r.normalized());
4199 if (rect.isEmpty())
4200 return;
4201
4202 if (d->extended) {
4203 d->extended->drawEllipse(rect);
4204 return;
4205 }
4206
4207 d->updateState(d->state);
4208
4209 if (d->state->emulationSpecifier) {
4210 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4211 && d->state->matrix.type() == QTransform::TxTranslate) {
4212 rect.translate(QPoint(qRound(d->state->matrix.dx()), qRound(d->state->matrix.dy())));
4213 } else {
4214 QPainterPath path;
4215 path.addEllipse(rect);
4216 d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
4217 return;
4218 }
4219 }
4220
4221 d->engine->drawEllipse(rect);
4222}
4223
4224/*!
4225 \fn QPainter::drawEllipse(int x, int y, int width, int height)
4226
4227 \overload
4228
4229 Draws the ellipse defined by the rectangle beginning at (\a{x},
4230 \a{y}) with the given \a width and \a height.
4231*/
4232
4233/*!
4234 \since 4.4
4235
4236 \fn QPainter::drawEllipse(const QPointF &center, qreal rx, qreal ry)
4237
4238 \overload
4239
4240 Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
4241*/
4242
4243/*!
4244 \since 4.4
4245
4246 \fn QPainter::drawEllipse(const QPoint &center, int rx, int ry)
4247
4248 \overload
4249
4250 Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
4251*/
4252
4253/*!
4254 \fn void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
4255
4256 Draws the arc defined by the given \a rectangle, \a startAngle and
4257 \a spanAngle.
4258
4259 The \a startAngle and \a spanAngle must be specified in 1/16th of
4260 a degree, i.e. a full circle equals 5760 (16 * 360). Positive
4261 values for the angles mean counter-clockwise while negative values
4262 mean the clockwise direction. Zero degrees is at the 3 o'clock
4263 position.
4264
4265 \table 100%
4266 \row
4267 \o \inlineimage qpainter-arc.png
4268 \o
4269 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 10
4270 \endtable
4271
4272 \sa drawPie(), drawChord(), {The Coordinate System}
4273*/
4274
4275void QPainter::drawArc(const QRectF &r, int a, int alen)
4276{
4277#ifdef QT_DEBUG_DRAW
4278 if (qt_show_painter_debug_output)
4279 printf("QPainter::drawArc(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4280 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4281#endif
4282 Q_D(QPainter);
4283
4284 if (!d->engine)
4285 return;
4286
4287 QRectF rect = r.normalized();
4288
4289 QPainterPath path;
4290 path.arcMoveTo(rect, a/16.0);
4291 path.arcTo(rect, a/16.0, alen/16.0);
4292 strokePath(path, d->state->pen);
4293}
4294
4295/*! \fn void QPainter::drawArc(const QRect &rectangle, int startAngle,
4296 int spanAngle)
4297
4298 \overload
4299
4300 Draws the arc defined by the given \a rectangle, \a startAngle and
4301 \a spanAngle.
4302*/
4303
4304/*!
4305 \fn void QPainter::drawArc(int x, int y, int width, int height,
4306 int startAngle, int spanAngle)
4307
4308 \overload
4309
4310 Draws the arc defined by the rectangle beginning at (\a x, \a y)
4311 with the specified \a width and \a height, and the given \a
4312 startAngle and \a spanAngle.
4313*/
4314
4315/*!
4316 \fn void QPainter::drawPie(const QRectF &rectangle, int startAngle, int spanAngle)
4317
4318 Draws a pie defined by the given \a rectangle, \a startAngle and
4319 and \a spanAngle.
4320
4321 The pie is filled with the current brush().
4322
4323 The startAngle and spanAngle must be specified in 1/16th of a
4324 degree, i.e. a full circle equals 5760 (16 * 360). Positive values
4325 for the angles mean counter-clockwise while negative values mean
4326 the clockwise direction. Zero degrees is at the 3 o'clock
4327 position.
4328
4329 \table 100%
4330 \row
4331 \o \inlineimage qpainter-pie.png
4332 \o
4333 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 11
4334 \endtable
4335
4336 \sa drawEllipse(), drawChord(), {The Coordinate System}
4337*/
4338void QPainter::drawPie(const QRectF &r, int a, int alen)
4339{
4340#ifdef QT_DEBUG_DRAW
4341 if (qt_show_painter_debug_output)
4342 printf("QPainter::drawPie(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4343 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4344#endif
4345 Q_D(QPainter);
4346
4347 if (!d->engine)
4348 return;
4349
4350 if (a > (360*16)) {
4351 a = a % (360*16);
4352 } else if (a < 0) {
4353 a = a % (360*16);
4354 if (a < 0) a += (360*16);
4355 }
4356
4357 QRectF rect = r.normalized();
4358
4359 QPainterPath path;
4360 path.moveTo(rect.center());
4361 path.arcTo(rect.x(), rect.y(), rect.width(), rect.height(), a/16.0, alen/16.0);
4362 path.closeSubpath();
4363 drawPath(path);
4364
4365}
4366
4367/*!
4368 \fn void QPainter::drawPie(const QRect &rectangle, int startAngle, int spanAngle)
4369 \overload
4370
4371 Draws a pie defined by the given \a rectangle, \a startAngle and
4372 and \a spanAngle.
4373*/
4374
4375/*!
4376 \fn void QPainter::drawPie(int x, int y, int width, int height, int
4377 startAngle, int spanAngle)
4378
4379 \overload
4380
4381 Draws the pie defined by the rectangle beginning at (\a x, \a y) with
4382 the specified \a width and \a height, and the given \a startAngle and
4383 \a spanAngle.
4384*/
4385
4386/*!
4387 \fn void QPainter::drawChord(const QRectF &rectangle, int startAngle, int spanAngle)
4388
4389 Draws the chord defined by the given \a rectangle, \a startAngle and
4390 \a spanAngle. The chord is filled with the current brush().
4391
4392 The startAngle and spanAngle must be specified in 1/16th of a
4393 degree, i.e. a full circle equals 5760 (16 * 360). Positive values
4394 for the angles mean counter-clockwise while negative values mean
4395 the clockwise direction. Zero degrees is at the 3 o'clock
4396 position.
4397
4398 \table 100%
4399 \row
4400 \o \inlineimage qpainter-chord.png
4401 \o
4402 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 12
4403 \endtable
4404
4405 \sa drawArc(), drawPie(), {The Coordinate System}
4406*/
4407void QPainter::drawChord(const QRectF &r, int a, int alen)
4408{
4409#ifdef QT_DEBUG_DRAW
4410 if (qt_show_painter_debug_output)
4411 printf("QPainter::drawChord(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4412 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4413#endif
4414 Q_D(QPainter);
4415
4416 if (!d->engine)
4417 return;
4418
4419 QRectF rect = r.normalized();
4420
4421 QPainterPath path;
4422 path.arcMoveTo(rect, a/16.0);
4423 path.arcTo(rect, a/16.0, alen/16.0);
4424 path.closeSubpath();
4425 drawPath(path);
4426}
4427/*!
4428 \fn void QPainter::drawChord(const QRect &rectangle, int startAngle, int spanAngle)
4429
4430 \overload
4431
4432 Draws the chord defined by the given \a rectangle, \a startAngle and
4433 \a spanAngle.
4434*/
4435
4436/*!
4437 \fn void QPainter::drawChord(int x, int y, int width, int height, int
4438 startAngle, int spanAngle)
4439
4440 \overload
4441
4442 Draws the chord defined by the rectangle beginning at (\a x, \a y)
4443 with the specified \a width and \a height, and the given \a
4444 startAngle and \a spanAngle.
4445*/
4446
4447#ifdef QT3_SUPPORT
4448/*!
4449 \fn void QPainter::drawLineSegments(const QPolygon &polygon, int
4450 index, int count)
4451
4452 Draws \a count separate lines from points defined by the \a
4453 polygon, starting at \a{polygon}\e{[index]} (\a index defaults to
4454 0). If \a count is -1 (the default) all points until the end of
4455 the array are used.
4456
4457 Use drawLines() combined with QPolygon::constData() instead.
4458
4459 \oldcode
4460 QPainter painter(this);
4461 painter.drawLineSegments(polygon, index, count);
4462 \newcode
4463 int lineCount = (count == -1) ? (polygon.size() - index) / 2 : count;
4464
4465 QPainter painter(this);
4466 painter.drawLines(polygon.constData() + index * 2, lineCount);
4467 \endcode
4468*/
4469
4470void QPainter::drawLineSegments(const QPolygon &a, int index, int nlines)
4471{
4472#ifdef QT_DEBUG_DRAW
4473 if (qt_show_painter_debug_output)
4474 printf("QPainter::drawLineSegments(), count=%d\n", a.size()/2);
4475#endif
4476 Q_D(QPainter);
4477
4478 if (!d->engine)
4479 return;
4480
4481 if (nlines < 0)
4482 nlines = a.size()/2 - index/2;
4483 if (index + nlines*2 > (int)a.size())
4484 nlines = (a.size() - index)/2;
4485 if (nlines < 1 || index < 0)
4486 return;
4487
4488 if (d->extended) {
4489 // FALCON: Use QVectorPath
4490 QVector<QLineF> lines;
4491 for (int i=index; i<index + nlines*2; i+=2)
4492 lines << QLineF(a.at(i), a.at(i+1));
4493 d->extended->drawLines(lines.data(), lines.size());
4494 return;
4495 }
4496
4497 d->updateState(d->state);
4498
4499 QVector<QLineF> lines;
4500 if (d->state->emulationSpecifier) {
4501 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4502 && d->state->matrix.type() == QTransform::TxTranslate) {
4503 QPointF offset(d->state->matrix.dx(), d->state->matrix.dy());
4504 for (int i=index; i<index + nlines*2; i+=2)
4505 lines << QLineF(a.at(i) + offset, a.at(i+1) + offset);
4506 } else {
4507 QPainterPath linesPath;
4508 for (int i=index; i<index + nlines*2; i+=2) {
4509 linesPath.moveTo(a.at(i));
4510 linesPath.lineTo(a.at(i+1));
4511 }
4512 d->draw_helper(linesPath, QPainterPrivate::StrokeDraw);
4513 return;
4514 }
4515 } else {
4516 for (int i=index; i<index + nlines*2; i+=2)
4517 lines << QLineF(a.at(i), a.at(i+1));
4518 }
4519
4520 d->engine->drawLines(lines.data(), lines.size());
4521}
4522#endif // QT3_SUPPORT
4523
4524/*!
4525 Draws the first \a lineCount lines in the array \a lines
4526 using the current pen.
4527
4528 \sa drawLine(), drawPolyline()
4529*/
4530void QPainter::drawLines(const QLineF *lines, int lineCount)
4531{
4532#ifdef QT_DEBUG_DRAW
4533 if (qt_show_painter_debug_output)
4534 printf("QPainter::drawLines(), line count=%d\n", lineCount);
4535#endif
4536
4537 Q_D(QPainter);
4538
4539 if (!d->engine || lineCount < 1)
4540 return;
4541
4542 if (d->extended) {
4543 d->extended->drawLines(lines, lineCount);
4544 return;
4545 }
4546
4547 d->updateState(d->state);
4548
4549 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4550
4551 if (lineEmulation) {
4552 if (lineEmulation == QPaintEngine::PrimitiveTransform
4553 && d->state->matrix.type() == QTransform::TxTranslate) {
4554 for (int i = 0; i < lineCount; ++i) {
4555 QLineF line = lines[i];
4556 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4557 d->engine->drawLines(&line, 1);
4558 }
4559 } else {
4560 QPainterPath linePath;
4561 for (int i = 0; i < lineCount; ++i) {
4562 linePath.moveTo(lines[i].p1());
4563 linePath.lineTo(lines[i].p2());
4564 }
4565 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4566 }
4567 return;
4568 }
4569 d->engine->drawLines(lines, lineCount);
4570}
4571
4572/*!
4573 \fn void QPainter::drawLines(const QLine *lines, int lineCount)
4574 \overload
4575
4576 Draws the first \a lineCount lines in the array \a lines
4577 using the current pen.
4578*/
4579void QPainter::drawLines(const QLine *lines, int lineCount)
4580{
4581#ifdef QT_DEBUG_DRAW
4582 if (qt_show_painter_debug_output)
4583 printf("QPainter::drawLine(), line count=%d\n", lineCount);
4584#endif
4585
4586 Q_D(QPainter);
4587
4588 if (!d->engine || lineCount < 1)
4589 return;
4590
4591 if (d->extended) {
4592 d->extended->drawLines(lines, lineCount);
4593 return;
4594 }
4595
4596 d->updateState(d->state);
4597
4598 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4599
4600 if (lineEmulation) {
4601 if (lineEmulation == QPaintEngine::PrimitiveTransform
4602 && d->state->matrix.type() == QTransform::TxTranslate) {
4603 for (int i = 0; i < lineCount; ++i) {
4604 QLineF line = lines[i];
4605 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4606 d->engine->drawLines(&line, 1);
4607 }
4608 } else {
4609 QPainterPath linePath;
4610 for (int i = 0; i < lineCount; ++i) {
4611 linePath.moveTo(lines[i].p1());
4612 linePath.lineTo(lines[i].p2());
4613 }
4614 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4615 }
4616 return;
4617 }
4618 d->engine->drawLines(lines, lineCount);
4619}
4620
4621/*!
4622 \overload
4623
4624 Draws the first \a lineCount lines in the array \a pointPairs
4625 using the current pen. The lines are specified as pairs of points
4626 so the number of entries in \a pointPairs must be at least \a
4627 lineCount * 2.
4628*/
4629void QPainter::drawLines(const QPointF *pointPairs, int lineCount)
4630{
4631 Q_ASSERT(sizeof(QLineF) == 2*sizeof(QPointF));
4632
4633 drawLines((QLineF*)pointPairs, lineCount);
4634}
4635
4636/*!
4637 \overload
4638
4639 Draws the first \a lineCount lines in the array \a pointPairs
4640 using the current pen.
4641*/
4642void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
4643{
4644 Q_ASSERT(sizeof(QLine) == 2*sizeof(QPoint));
4645
4646 drawLines((QLine*)pointPairs, lineCount);
4647}
4648
4649
4650/*!
4651 \fn void QPainter::drawLines(const QVector<QPointF> &pointPairs)
4652 \overload
4653
4654 Draws a line for each pair of points in the vector \a pointPairs
4655 using the current pen. If there is an odd number of points in the
4656 array, the last point will be ignored.
4657*/
4658
4659/*!
4660 \fn void QPainter::drawLines(const QVector<QPoint> &pointPairs)
4661 \overload
4662
4663 Draws a line for each pair of points in the vector \a pointPairs
4664 using the current pen.
4665*/
4666
4667/*!
4668 \fn void QPainter::drawLines(const QVector<QLineF> &lines)
4669 \overload
4670
4671 Draws the set of lines defined by the list \a lines using the
4672 current pen and brush.
4673*/
4674
4675/*!
4676 \fn void QPainter::drawLines(const QVector<QLine> &lines)
4677 \overload
4678
4679 Draws the set of lines defined by the list \a lines using the
4680 current pen and brush.
4681*/
4682
4683/*!
4684 Draws the polyline defined by the first \a pointCount points in \a
4685 points using the current pen.
4686
4687 Note that unlike the drawPolygon() function the last point is \e
4688 not connected to the first, neither is the polyline filled.
4689
4690 \table 100%
4691 \row
4692 \o
4693 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 13
4694 \endtable
4695
4696 \sa drawLines(), drawPolygon(), {The Coordinate System}
4697*/
4698void QPainter::drawPolyline(const QPointF *points, int pointCount)
4699{
4700#ifdef QT_DEBUG_DRAW
4701 if (qt_show_painter_debug_output)
4702 printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4703#endif
4704 Q_D(QPainter);
4705
4706 if (!d->engine || pointCount < 2)
4707 return;
4708
4709 if (d->extended) {
4710 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4711 return;
4712 }
4713
4714 d->updateState(d->state);
4715
4716 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4717
4718 if (lineEmulation) {
4719 // ###
4720// if (lineEmulation == QPaintEngine::PrimitiveTransform
4721// && d->state->matrix.type() == QTransform::TxTranslate) {
4722// } else {
4723 QPainterPath polylinePath(points[0]);
4724 for (int i=1; i<pointCount; ++i)
4725 polylinePath.lineTo(points[i]);
4726 d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4727// }
4728 } else {
4729 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4730 }
4731}
4732
4733/*!
4734 \overload
4735
4736 Draws the polyline defined by the first \a pointCount points in \a
4737 points using the current pen.
4738 */
4739void QPainter::drawPolyline(const QPoint *points, int pointCount)
4740{
4741#ifdef QT_DEBUG_DRAW
4742 if (qt_show_painter_debug_output)
4743 printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4744#endif
4745 Q_D(QPainter);
4746
4747 if (!d->engine || pointCount < 2)
4748 return;
4749
4750 if (d->extended) {
4751 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4752 return;
4753 }
4754
4755 d->updateState(d->state);
4756
4757 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4758
4759 if (lineEmulation) {
4760 // ###
4761// if (lineEmulation == QPaintEngine::PrimitiveTransform
4762// && d->state->matrix.type() == QTransform::TxTranslate) {
4763// } else {
4764 QPainterPath polylinePath(points[0]);
4765 for (int i=1; i<pointCount; ++i)
4766 polylinePath.lineTo(points[i]);
4767 d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4768// }
4769 } else {
4770 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4771 }
4772}
4773
4774/*!
4775 \fn void QPainter::drawPolyline(const QPolygon &polygon, int index, int
4776 count)
4777
4778 \overload
4779 \compat
4780
4781 Draws the polyline defined by the \a count lines of the given \a
4782 polygon starting at \a index (\a index defaults to 0).
4783
4784 Use drawPolyline() combined with QPolygon::constData() instead.
4785
4786 \oldcode
4787 QPainter painter(this);
4788 painter.drawPolyline(polygon, index, count);
4789 \newcode
4790 int pointCount = (count == -1) ? polygon.size() - index : count;
4791
4792 QPainter painter(this);
4793 painter.drawPolyline(polygon.constData() + index, pointCount);
4794 \endcode
4795*/
4796
4797/*!
4798 \fn void QPainter::drawPolyline(const QPolygonF &points)
4799
4800 \overload
4801
4802 Draws the polyline defined by the given \a points using the
4803 current pen.
4804*/
4805
4806/*!
4807 \fn void QPainter::drawPolyline(const QPolygon &points)
4808
4809 \overload
4810
4811 Draws the polyline defined by the given \a points using the
4812 current pen.
4813*/
4814
4815/*!
4816 Draws the polygon defined by the first \a pointCount points in the
4817 array \a points using the current pen and brush.
4818
4819 \table 100%
4820 \row
4821 \o \inlineimage qpainter-polygon.png
4822 \o
4823 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 14
4824 \endtable
4825
4826 The first point is implicitly connected to the last point, and the
4827 polygon is filled with the current brush().
4828
4829 If \a fillRule is Qt::WindingFill, the polygon is filled using the
4830 winding fill algorithm. If \a fillRule is Qt::OddEvenFill, the
4831 polygon is filled using the odd-even fill algorithm. See
4832 \l{Qt::FillRule} for a more detailed description of these fill
4833 rules.
4834
4835 \sa drawConvexPolygon(), drawPolyline(), {The Coordinate System}
4836*/
4837void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
4838{
4839#ifdef QT_DEBUG_DRAW
4840 if (qt_show_painter_debug_output)
4841 printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4842#endif
4843
4844 Q_D(QPainter);
4845
4846 if (!d->engine || pointCount < 2)
4847 return;
4848
4849 if (d->extended) {
4850 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4851 return;
4852 }
4853
4854 d->updateState(d->state);
4855
4856 uint emulationSpecifier = d->state->emulationSpecifier;
4857
4858 if (emulationSpecifier) {
4859 QPainterPath polygonPath(points[0]);
4860 for (int i=1; i<pointCount; ++i)
4861 polygonPath.lineTo(points[i]);
4862 polygonPath.closeSubpath();
4863 polygonPath.setFillRule(fillRule);
4864 d->draw_helper(polygonPath);
4865 return;
4866 }
4867
4868 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4869}
4870
4871/*! \overload
4872
4873 Draws the polygon defined by the first \a pointCount points in the
4874 array \a points.
4875*/
4876void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
4877{
4878#ifdef QT_DEBUG_DRAW
4879 if (qt_show_painter_debug_output)
4880 printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4881#endif
4882
4883 Q_D(QPainter);
4884
4885 if (!d->engine || pointCount < 2)
4886 return;
4887
4888 if (d->extended) {
4889 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4890 return;
4891 }
4892
4893 d->updateState(d->state);
4894
4895 uint emulationSpecifier = d->state->emulationSpecifier;
4896
4897 if (emulationSpecifier) {
4898 QPainterPath polygonPath(points[0]);
4899 for (int i=1; i<pointCount; ++i)
4900 polygonPath.lineTo(points[i]);
4901 polygonPath.closeSubpath();
4902 polygonPath.setFillRule(fillRule);
4903 d->draw_helper(polygonPath);
4904 return;
4905 }
4906
4907 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4908}
4909
4910/*! \fn void QPainter::drawPolygon(const QPolygonF &polygon, bool winding, int index = 0,
4911 int count = -1)
4912 \compat
4913 \overload
4914
4915 Use drawPolygon() combined with QPolygonF::constData() instead.
4916
4917 \oldcode
4918 QPainter painter(this);
4919 painter.drawPolygon(polygon, winding, index, count);
4920 \newcode
4921 int pointCount = (count == -1) ? polygon.size() - index : count;
4922 int fillRule = winding ? Qt::WindingFill : Qt::OddEvenFill;
4923
4924 QPainter painter(this);
4925 painter.drawPolygon( polygon.constData() + index, pointCount, fillRule);
4926 \endcode
4927*/
4928
4929/*! \fn void QPainter::drawPolygon(const QPolygon &polygon, bool winding,
4930 int index = 0, int count = -1)
4931
4932 \compat
4933 \overload
4934
4935 Use drawPolygon() combined with QPolygon::constData() instead.
4936
4937 \oldcode
4938 QPainter painter(this);
4939 painter.drawPolygon(polygon, winding, index, count);
4940 \newcode
4941 int pointCount = (count == -1) ? polygon.size() - index : count;
4942 int fillRule = winding ? Qt::WindingFill : Qt::OddEvenFill;
4943
4944 QPainter painter(this);
4945 painter.drawPolygon( polygon.constData() + index, pointCount, fillRule);
4946 \endcode
4947*/
4948
4949/*! \fn void QPainter::drawPolygon(const QPolygonF &points, Qt::FillRule fillRule)
4950
4951 \overload
4952
4953 Draws the polygon defined by the given \a points using the fill
4954 rule \a fillRule.
4955*/
4956
4957/*! \fn void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule)
4958
4959 \overload
4960
4961 Draws the polygon defined by the given \a points using the fill
4962 rule \a fillRule.
4963*/
4964
4965/*!
4966 \fn void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
4967
4968 Draws the convex polygon defined by the first \a pointCount points
4969 in the array \a points using the current pen.
4970
4971 \table 100%
4972 \row
4973 \o \inlineimage qpainter-polygon.png
4974 \o
4975 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 15
4976 \endtable
4977
4978 The first point is implicitly connected to the last point, and the
4979 polygon is filled with the current brush(). If the supplied
4980 polygon is not convex, i.e. it contains at least one angle larger
4981 than 180 degrees, the results are undefined.
4982
4983 On some platforms (e.g. X11), the drawConvexPolygon() function can
4984 be faster than the drawPolygon() function.
4985
4986 \sa drawPolygon(), drawPolyline(), {The Coordinate System}
4987*/
4988
4989/*!
4990 \fn void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
4991 \overload
4992
4993 Draws the convex polygon defined by the first \a pointCount points
4994 in the array \a points using the current pen.
4995*/
4996
4997/*!
4998 \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon)
4999
5000 \overload
5001
5002 Draws the convex polygon defined by \a polygon using the current
5003 pen and brush.
5004*/
5005
5006/*!
5007 \fn void QPainter::drawConvexPolygon(const QPolygon &polygon)
5008 \overload
5009
5010 Draws the convex polygon defined by \a polygon using the current
5011 pen and brush.
5012*/
5013
5014/*!
5015 \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon, int
5016 index, int count)
5017
5018 \compat
5019 \overload
5020
5021 Use drawConvexPolygon() combined with QPolygonF::constData()
5022 instead.
5023
5024 \oldcode
5025 QPainter painter(this);
5026 painter.drawConvexPolygon(polygon, index, count);
5027 \newcode
5028 int pointCount = (count == -1) ? polygon.size() - index : count;
5029
5030 QPainter painter(this);
5031 painter.drawConvexPolygon(polygon.constData() + index, pointCount);
5032 \endcode
5033*/
5034
5035/*!
5036 \fn void QPainter::drawConvexPolygon(const QPolygon &polygon, int
5037 index, int count)
5038
5039 \compat
5040 \overload
5041
5042 Use drawConvexPolygon() combined with QPolygon::constData()
5043 instead.
5044
5045 \oldcode
5046 QPainter painter(this);
5047 painter.drawConvexPolygon(polygon, index, count);
5048 \newcode
5049 int pointCount = (count == -1) ? polygon.size() - index : count;
5050
5051 QPainter painter(this);
5052 painter.drawConvexPolygon(polygon.constData() + index, pointCount);
5053 \endcode
5054*/
5055
5056void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
5057{
5058#ifdef QT_DEBUG_DRAW
5059 if (qt_show_painter_debug_output)
5060 printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
5061#endif
5062
5063 Q_D(QPainter);
5064
5065 if (!d->engine || pointCount < 2)
5066 return;
5067
5068 if (d->extended) {
5069 d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
5070 return;
5071 }
5072
5073 d->updateState(d->state);
5074
5075 uint emulationSpecifier = d->state->emulationSpecifier;
5076
5077 if (emulationSpecifier) {
5078 QPainterPath polygonPath(points[0]);
5079 for (int i=1; i<pointCount; ++i)
5080 polygonPath.lineTo(points[i]);
5081 polygonPath.closeSubpath();
5082 polygonPath.setFillRule(Qt::WindingFill);
5083 d->draw_helper(polygonPath);
5084 return;
5085 }
5086
5087 d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
5088}
5089
5090void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
5091{
5092#ifdef QT_DEBUG_DRAW
5093 if (qt_show_painter_debug_output)
5094 printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
5095#endif
5096
5097 Q_D(QPainter);
5098
5099 if (!d->engine || pointCount < 2)
5100 return;
5101
5102 if (d->extended) {
5103 d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
5104 return;
5105 }
5106
5107 d->updateState(d->state);
5108
5109 uint emulationSpecifier = d->state->emulationSpecifier;
5110
5111 if (emulationSpecifier) {
5112 QPainterPath polygonPath(points[0]);
5113 for (int i=1; i<pointCount; ++i)
5114 polygonPath.lineTo(points[i]);
5115 polygonPath.closeSubpath();
5116 polygonPath.setFillRule(Qt::WindingFill);
5117 d->draw_helper(polygonPath);
5118 return;
5119 }
5120
5121 d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
5122}
5123
5124/*!
5125 \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
5126
5127 Draws the rectangular portion \a source of the given \a pixmap
5128 into the given \a target in the paint device.
5129
5130 \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
5131
5132 \table 100%
5133 \row
5134 \o
5135 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 16
5136 \endtable
5137
5138 If \a pixmap is a QBitmap it is drawn with the bits that are "set"
5139 using the pens color. If backgroundMode is Qt::OpaqueMode, the
5140 "unset" bits are drawn using the color of the background brush; if
5141 backgroundMode is Qt::TransparentMode, the "unset" bits are
5142 transparent. Drawing bitmaps with gradient or texture colors is
5143 not supported.
5144
5145 \sa drawImage()
5146*/
5147void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
5148{
5149#if defined QT_DEBUG_DRAW
5150 if (qt_show_painter_debug_output)
5151 printf("QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
5152 p.x(), p.y(),
5153 pm.width(), pm.height());
5154#endif
5155
5156 Q_D(QPainter);
5157
5158 if (!d->engine || pm.isNull())
5159 return;
5160
5161#ifndef QT_NO_DEBUG
5162 qt_painter_thread_test(d->device->devType(), "drawPixmap()");
5163#endif
5164
5165 if (d->extended) {
5166 d->extended->drawPixmap(p, pm);
5167 return;
5168 }
5169
5170 qreal x = p.x();
5171 qreal y = p.y();
5172
5173 int w = pm.width();
5174 int h = pm.height();
5175
5176 // Emulate opaque background for bitmaps
5177 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
5178 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
5179 }
5180
5181 d->updateState(d->state);
5182
5183 if ((d->state->matrix.type() > QTransform::TxTranslate
5184 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5185 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5186 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5187 {
5188 save();
5189 // If there is no scaling or transformation involved we have to make sure we use the
5190 // antialiased and not the aliased coordinate system by rounding the coordinates.
5191 if (d->state->matrix.type() <= QTransform::TxTranslate) {
5192 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
5193 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
5194 }
5195 translate(x, y);
5196 setBackgroundMode(Qt::TransparentMode);
5197 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5198 QBrush brush(d->state->pen.color(), pm);
5199 setBrush(brush);
5200 setPen(Qt::NoPen);
5201 setBrushOrigin(QPointF(0, 0));
5202
5203 drawRect(pm.rect());
5204 restore();
5205 } else {
5206 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5207 x += d->state->matrix.dx();
5208 y += d->state->matrix.dy();
5209 }
5210 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(0, 0, w, h));
5211 }
5212}
5213
5214void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
5215{
5216#if defined QT_DEBUG_DRAW
5217 if (qt_show_painter_debug_output)
5218 printf("QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
5219 r.x(), r.y(), r.width(), r.height(),
5220 pm.width(), pm.height(),
5221 sr.x(), sr.y(), sr.width(), sr.height());
5222#endif
5223
5224 Q_D(QPainter);
5225 if (!d->engine || pm.isNull())
5226 return;
5227#ifndef QT_NO_DEBUG
5228 qt_painter_thread_test(d->device->devType(), "drawPixmap()");
5229#endif
5230
5231 qreal x = r.x();
5232 qreal y = r.y();
5233 qreal w = r.width();
5234 qreal h = r.height();
5235 qreal sx = sr.x();
5236 qreal sy = sr.y();
5237 qreal sw = sr.width();
5238 qreal sh = sr.height();
5239
5240 // Sanity-check clipping
5241 if (sw <= 0)
5242 sw = pm.width() - sx;
5243
5244 if (sh <= 0)
5245 sh = pm.height() - sy;
5246
5247 if (w < 0)
5248 w = sw;
5249 if (h < 0)
5250 h = sh;
5251
5252 if (sx < 0) {
5253 qreal w_ratio = sx * w/sw;
5254 x -= w_ratio;
5255 w += w_ratio;
5256 sw += sx;
5257 sx = 0;
5258 }
5259
5260 if (sy < 0) {
5261 qreal h_ratio = sy * h/sh;
5262 y -= h_ratio;
5263 h += h_ratio;
5264 sh += sy;
5265 sy = 0;
5266 }
5267
5268 if (sw + sx > pm.width()) {
5269 qreal delta = sw - (pm.width() - sx);
5270 qreal w_ratio = delta * w/sw;
5271 sw -= delta;
5272 w -= w_ratio;
5273 }
5274
5275 if (sh + sy > pm.height()) {
5276 qreal delta = sh - (pm.height() - sy);
5277 qreal h_ratio = delta * h/sh;
5278 sh -= delta;
5279 h -= h_ratio;
5280 }
5281
5282 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5283 return;
5284
5285 if (d->extended) {
5286 d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5287 return;
5288 }
5289
5290 // Emulate opaque background for bitmaps
5291 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
5292 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
5293
5294 d->updateState(d->state);
5295
5296 if ((d->state->matrix.type() > QTransform::TxTranslate
5297 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5298 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5299 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
5300 || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
5301 {
5302 save();
5303 // If there is no scaling or transformation involved we have to make sure we use the
5304 // antialiased and not the aliased coordinate system by rounding the coordinates.
5305 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5306 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
5307 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
5308 sx = qRound(sx);
5309 sy = qRound(sy);
5310 sw = qRound(sw);
5311 sh = qRound(sh);
5312 }
5313 translate(x, y);
5314 scale(w / sw, h / sh);
5315 setBackgroundMode(Qt::TransparentMode);
5316 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5317 QBrush brush(d->state->pen.color(), pm);
5318 setBrush(brush);
5319 setPen(Qt::NoPen);
5320 setBrushOrigin(QPointF(-sx, -sy));
5321
5322 drawRect(QRectF(0, 0, sw, sh));
5323 restore();
5324 } else {
5325 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5326 x += d->state->matrix.dx();
5327 y += d->state->matrix.dy();
5328 }
5329 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5330 }
5331}
5332
5333
5334/*!
5335 \fn void QPainter::drawPixmap(const QRect &target, const QPixmap &pixmap,
5336 const QRect &source)
5337 \overload
5338
5339 Draws the rectangular portion \a source of the given \a pixmap
5340 into the given \a target in the paint device.
5341
5342 \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
5343*/
5344
5345/*!
5346 \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap,
5347 const QRectF &source)
5348 \overload
5349
5350 Draws the rectangular portion \a source of the given \a pixmap
5351 with its origin at the given \a point.
5352*/
5353
5354/*!
5355 \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap,
5356 const QRect &source)
5357
5358 \overload
5359
5360 Draws the rectangular portion \a source of the given \a pixmap
5361 with its origin at the given \a point.
5362*/
5363
5364/*!
5365 \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap)
5366 \overload
5367
5368 Draws the given \a pixmap with its origin at the given \a point.
5369*/
5370
5371/*!
5372 \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap)
5373 \overload
5374
5375 Draws the given \a pixmap with its origin at the given \a point.
5376*/
5377
5378/*!
5379 \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap)
5380
5381 \overload
5382
5383 Draws the given \a pixmap at position (\a{x}, \a{y}).
5384*/
5385
5386/*!
5387 \fn void QPainter::drawPixmap(const QRect &rectangle, const QPixmap &pixmap)
5388 \overload
5389
5390 Draws the given \a pixmap into the given \a rectangle.
5391
5392 \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
5393*/
5394
5395/*!
5396 \fn void QPainter::drawPixmap(int x, int y, int width, int height,
5397 const QPixmap &pixmap)
5398
5399 \overload
5400
5401 Draws the \a pixmap into the rectangle at position (\a{x}, \a{y})
5402 with the given \a width and \a height.
5403*/
5404
5405/*!
5406 \fn void QPainter::drawPixmap(int x, int y, int w, int h, const QPixmap &pixmap,
5407 int sx, int sy, int sw, int sh)
5408
5409 \overload
5410
5411 Draws the rectangular portion with the origin (\a{sx}, \a{sy}),
5412 width \a sw and height \a sh, of the given \a pixmap , at the
5413 point (\a{x}, \a{y}), with a width of \a w and a height of \a h.
5414 If sw or sh are equal to zero the width/height of the pixmap
5415 is used and adjusted by the offset sx/sy;
5416*/
5417
5418/*!
5419 \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap,
5420 int sx, int sy, int sw, int sh)
5421
5422 \overload
5423
5424 Draws a pixmap at (\a{x}, \a{y}) by copying a part of the given \a
5425 pixmap into the paint device.
5426
5427 (\a{x}, \a{y}) specifies the top-left point in the paint device that is
5428 to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
5429 pixmap that is to be drawn. The default is (0, 0).
5430
5431 (\a{sw}, \a{sh}) specifies the size of the pixmap that is to be drawn.
5432 The default, (0, 0) (and negative) means all the way to the
5433 bottom-right of the pixmap.
5434*/
5435
5436void QPainter::drawImage(const QPointF &p, const QImage &image)
5437{
5438 Q_D(QPainter);
5439
5440 if (!d->engine || image.isNull())
5441 return;
5442
5443 if (d->extended) {
5444 d->extended->drawImage(p, image);
5445 return;
5446 }
5447
5448 qreal x = p.x();
5449 qreal y = p.y();
5450
5451 int w = image.width();
5452 int h = image.height();
5453
5454 d->updateState(d->state);
5455
5456 if (((d->state->matrix.type() > QTransform::TxTranslate)
5457 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5458 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5459 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5460 {
5461 save();
5462 // If there is no scaling or transformation involved we have to make sure we use the
5463 // antialiased and not the aliased coordinate system by rounding the coordinates.
5464 if (d->state->matrix.type() <= QTransform::TxTranslate) {
5465 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
5466 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
5467 }
5468 translate(x, y);
5469 setBackgroundMode(Qt::TransparentMode);
5470 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5471 QBrush brush(image);
5472 setBrush(brush);
5473 setPen(Qt::NoPen);
5474 setBrushOrigin(QPointF(0, 0));
5475
5476 drawRect(image.rect());
5477 restore();
5478 return;
5479 }
5480
5481 if (d->state->matrix.type() == QTransform::TxTranslate
5482 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5483 x += d->state->matrix.dx();
5484 y += d->state->matrix.dy();
5485 }
5486
5487 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(0, 0, w, h), Qt::AutoColor);
5488}
5489
5490void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
5491 Qt::ImageConversionFlags flags)
5492{
5493 Q_D(QPainter);
5494
5495 if (!d->engine || image.isNull())
5496 return;
5497
5498 qreal x = targetRect.x();
5499 qreal y = targetRect.y();
5500 qreal w = targetRect.width();
5501 qreal h = targetRect.height();
5502 qreal sx = sourceRect.x();
5503 qreal sy = sourceRect.y();
5504 qreal sw = sourceRect.width();
5505 qreal sh = sourceRect.height();
5506
5507 // Sanity-check clipping
5508 if (sw <= 0)
5509 sw = image.width() - sx;
5510
5511 if (sh <= 0)
5512 sh = image.height() - sy;
5513
5514 if (w < 0)
5515 w = sw;
5516 if (h < 0)
5517 h = sh;
5518
5519 if (sx < 0) {
5520 qreal w_ratio = sx * w/sw;
5521 x -= w_ratio;
5522 w += w_ratio;
5523 sw += sx;
5524 sx = 0;
5525 }
5526
5527 if (sy < 0) {
5528 qreal h_ratio = sy * h/sh;
5529 y -= h_ratio;
5530 h += h_ratio;
5531 sh += sy;
5532 sy = 0;
5533 }
5534
5535 if (sw + sx > image.width()) {
5536 qreal delta = sw - (image.width() - sx);
5537 qreal w_ratio = delta * w/sw;
5538 sw -= delta;
5539 w -= w_ratio;
5540 }
5541
5542 if (sh + sy > image.height()) {
5543 qreal delta = sh - (image.height() - sy);
5544 qreal h_ratio = delta * h/sh;
5545 sh -= delta;
5546 h -= h_ratio;
5547 }
5548
5549 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5550 return;
5551
5552 if (d->extended) {
5553 d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5554 return;
5555 }
5556
5557 d->updateState(d->state);
5558
5559 if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5560 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5561 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5562 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5563 {
5564 save();
5565 // If there is no scaling or transformation involved we have to make sure we use the
5566 // antialiased and not the aliased coordinate system by rounding the coordinates.
5567 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5568 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();
5569 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();
5570 sx = qRound(sx);
5571 sy = qRound(sy);
5572 sw = qRound(sw);
5573 sh = qRound(sh);
5574 }
5575 translate(x, y);
5576 scale(w / sw, h / sh);
5577 setBackgroundMode(Qt::TransparentMode);
5578 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5579 QBrush brush(image);
5580 setBrush(brush);
5581 setPen(Qt::NoPen);
5582 setBrushOrigin(QPointF(-sx, -sy));
5583
5584 drawRect(QRectF(0, 0, sw, sh));
5585 restore();
5586 return;
5587 }
5588
5589 if (d->state->matrix.type() == QTransform::TxTranslate
5590 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5591 x += d->state->matrix.dx();
5592 y += d->state->matrix.dy();
5593 }
5594
5595 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5596}
5597
5598/*!
5599 \fn void QPainter::drawText(const QPointF &position, const QString &text)
5600
5601 Draws the given \a text with the currently defined text direction,
5602 beginning at the given \a position.
5603
5604 This function does not handle the newline character (\n), as it cannot
5605 break text into multiple lines, and it cannot display the newline character.
5606 Use the QPainter::drawText() overload that takes a rectangle instead
5607 if you want to draw multiple lines of text with the newline character, or
5608 if you want the text to be wrapped.
5609
5610 By default, QPainter draws text anti-aliased.
5611
5612 \note The y-position is used as the baseline of the font.
5613*/
5614
5615void QPainter::drawText(const QPointF &p, const QString &str)
5616{
5617 drawText(p, str, 0, 0);
5618}
5619
5620/*!
5621 \internal
5622*/
5623void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
5624{
5625#ifdef QT_DEBUG_DRAW
5626 if (qt_show_painter_debug_output)
5627 printf("QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5628#endif
5629
5630 Q_D(QPainter);
5631
5632 if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5633 return;
5634
5635 QStackTextEngine engine(str, d->state->font);
5636 engine.option.setTextDirection(d->state->layoutDirection);
5637 if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
5638 engine.ignoreBidi = true;
5639 engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5640 }
5641 engine.itemize();
5642 QScriptLine line;
5643 line.length = str.length();
5644 engine.shapeLine(line);
5645
5646 int nItems = engine.layoutData->items.size();
5647 QVarLengthArray<int> visualOrder(nItems);
5648 QVarLengthArray<uchar> levels(nItems);
5649 for (int i = 0; i < nItems; ++i)
5650 levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5651 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5652
5653 if (justificationPadding > 0) {
5654 engine.option.setAlignment(Qt::AlignJustify);
5655 engine.forceJustification = true;
5656 // this works because justify() is only interested in the difference between width and textWidth
5657 line.width = justificationPadding;
5658 engine.justify(line);
5659 }
5660 QFixed x = QFixed::fromReal(p.x());
5661 QFixed ox = x;
5662
5663 for (int i = 0; i < nItems; ++i) {
5664 int item = visualOrder[i];
5665 const QScriptItem &si = engine.layoutData->items.at(item);
5666 if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
5667 x += si.width;
5668 continue;
5669 }
5670 QFont f = engine.font(si);
5671 QTextItemInt gf(si, &f);
5672 gf.glyphs = engine.shapedGlyphs(&si);
5673 gf.chars = engine.layoutData->string.unicode() + si.position;
5674 gf.num_chars = engine.length(item);
5675 gf.width = si.width;
5676 gf.logClusters = engine.logClusters(&si);
5677
5678 drawTextItem(QPointF(x.toReal(), p.y()), gf);
5679
5680 x += si.width;
5681 }
5682}
5683
5684void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br)
5685{
5686#ifdef QT_DEBUG_DRAW
5687 if (qt_show_painter_debug_output)
5688 printf("QPainter::drawText(), r=[%d,%d,%d,%d], flags=%d, str='%s'\n",
5689 r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5690#endif
5691
5692 Q_D(QPainter);
5693
5694 if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
5695 return;
5696
5697 if (!d->extended)
5698 d->updateState(d->state);
5699
5700 QRectF bounds;
5701 qt_format_text(d->state->font, r, flags, 0, str, br ? &bounds : 0, 0, 0, 0, this);
5702 if (br)
5703 *br = bounds.toAlignedRect();
5704}
5705
5706/*!
5707 \fn void QPainter::drawText(const QPoint &position, const QString &text)
5708
5709 \overload
5710
5711 Draws the given \a text with the currently defined text direction,
5712 beginning at the given \a position.
5713
5714 By default, QPainter draws text anti-aliased.
5715
5716 \note The y-position is used as the baseline of the font.
5717
5718*/
5719
5720/*!
5721 \fn void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect)
5722 \overload
5723
5724 Draws the given \a text within the provided \a rectangle.
5725
5726 \table 100%
5727 \row
5728 \o \inlineimage qpainter-text.png
5729 \o
5730 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 17
5731 \endtable
5732
5733 The \a boundingRect (if not null) is set to the what the bounding rectangle
5734 should be in order to enclose the whole text. The \a flags argument is a bitwise
5735 OR of the following flags:
5736
5737 \list
5738 \o Qt::AlignLeft
5739 \o Qt::AlignRight
5740 \o Qt::AlignHCenter
5741 \o Qt::AlignJustify
5742 \o Qt::AlignTop
5743 \o Qt::AlignBottom
5744 \o Qt::AlignVCenter
5745 \o Qt::AlignCenter
5746 \o Qt::TextDontClip
5747 \o Qt::TextSingleLine
5748 \o Qt::TextExpandTabs
5749 \o Qt::TextShowMnemonic
5750 \o Qt::TextWordWrap
5751 \o Qt::TextIncludeTrailingSpaces
5752 \endlist
5753
5754 \sa Qt::AlignmentFlag, Qt::TextFlag, boundingRect(), layoutDirection()
5755
5756 By default, QPainter draws text anti-aliased.
5757
5758 \note The y-coordinate of \a rectangle is used as the top of the font.
5759*/
5760void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *br)
5761{
5762#ifdef QT_DEBUG_DRAW
5763 if (qt_show_painter_debug_output)
5764 printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], flags=%d, str='%s'\n",
5765 r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5766#endif
5767
5768 Q_D(QPainter);
5769
5770 if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
5771 return;
5772
5773 if (!d->extended)
5774 d->updateState(d->state);
5775
5776 qt_format_text(d->state->font, r, flags, 0, str, br, 0, 0, 0, this);
5777}
5778
5779/*!
5780 \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect)
5781 \overload
5782
5783 Draws the given \a text within the provided \a rectangle according
5784 to the specified \a flags. The \a boundingRect (if not null) is set to
5785 the what the bounding rectangle should be in order to enclose the whole text.
5786
5787 By default, QPainter draws text anti-aliased.
5788
5789 \note The y-coordinate of \a rectangle is used as the top of the font.
5790*/
5791
5792/*!
5793 \fn void QPainter::drawText(int x, int y, const QString &text)
5794
5795 \overload
5796
5797 Draws the given \a text at position (\a{x}, \a{y}), using the painter's
5798 currently defined text direction.
5799
5800 By default, QPainter draws text anti-aliased.
5801
5802 \note The y-position is used as the baseline of the font.
5803
5804*/
5805
5806/*!
5807 \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
5808 const QString &text, QRect *boundingRect)
5809
5810 \overload
5811
5812 Draws the given \a text within the rectangle with origin (\a{x},
5813 \a{y}), \a width and \a height.
5814
5815 The \a boundingRect (if not null) is set to the actual bounding
5816 rectangle of the output. The \a flags argument is a bitwise OR of
5817 the following flags:
5818
5819 \list
5820 \o Qt::AlignLeft
5821 \o Qt::AlignRight
5822 \o Qt::AlignHCenter
5823 \o Qt::AlignJustify
5824 \o Qt::AlignTop
5825 \o Qt::AlignBottom
5826 \o Qt::AlignVCenter
5827 \o Qt::AlignCenter
5828 \o Qt::TextSingleLine
5829 \o Qt::TextExpandTabs
5830 \o Qt::TextShowMnemonic
5831 \o Qt::TextWordWrap
5832 \endlist
5833
5834 By default, QPainter draws text anti-aliased.
5835
5836 \note The y-position is used as the baseline of the font.
5837
5838 \sa Qt::AlignmentFlag, Qt::TextFlag
5839*/
5840
5841/*!
5842 \fn void QPainter::drawText(const QRectF &rectangle, const QString &text,
5843 const QTextOption &option)
5844 \overload
5845
5846 Draws the given \a text in the \a rectangle specified using the \a option
5847 to control its positioning and orientation.
5848
5849 By default, QPainter draws text anti-aliased.
5850
5851 \note The y-coordinate of \a rectangle is used as the top of the font.
5852*/
5853void QPainter::drawText(const QRectF &r, const QString &text, const QTextOption &o)
5854{
5855#ifdef QT_DEBUG_DRAW
5856 if (qt_show_painter_debug_output)
5857 printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], str='%s'\n",
5858 r.x(), r.y(), r.width(), r.height(), text.toLatin1().constData());
5859#endif
5860
5861 Q_D(QPainter);
5862
5863 if (!d->engine || text.length() == 0 || pen().style() == Qt::NoPen)
5864 return;
5865
5866 if (!d->extended)
5867 d->updateState(d->state);
5868
5869 qt_format_text(d->state->font, r, 0, &o, text, 0, 0, 0, 0, this);
5870}
5871
5872/*!
5873 \fn void QPainter::drawTextItem(int x, int y, const QTextItem &ti)
5874
5875 \internal
5876 \overload
5877*/
5878
5879/*!
5880 \fn void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti)
5881
5882 \internal
5883 \overload
5884
5885 Draws the text item \a ti at position \a p.
5886*/
5887
5888/*! \internal
5889 Draws the text item \a ti at position \a p.
5890
5891 This method ignores the painters background mode and
5892 color. drawText and qt_format_text have to do it themselves, as
5893 only they know the extents of the complete string.
5894
5895 It ignores the font set on the painter as the text item has one of its own.
5896
5897 The underline and strikeout parameters of the text items font are
5898 ignored aswell. You'll need to pass in the correct flags to get
5899 underlining and strikeout.
5900*/
5901static QPainterPath generateWavyPath(qreal minWidth, qreal maxRadius, QPaintDevice *device)
5902{
5903 extern int qt_defaultDpi();
5904 QPainterPath path;
5905
5906 bool up = true;
5907 const qreal radius = qMax(qreal(.5), qMin(qreal(1.25 * device->logicalDpiY() / qt_defaultDpi()), maxRadius));
5908 qreal xs, ys;
5909 int i = 0;
5910 path.moveTo(0, radius);
5911 do {
5912 xs = i*(2*radius);
5913 ys = 0;
5914
5915 qreal remaining = minWidth - xs;
5916 qreal angle = 180;
5917
5918 // cut-off at the last arc segment
5919 if (remaining < 2 * radius)
5920 angle = 180 * remaining / (2 * radius);
5921
5922 path.arcTo(xs, ys, 2*radius, 2*radius, 180, up ? angle : -angle);
5923
5924 up = !up;
5925 ++i;
5926 } while (xs + 2*radius < minWidth);
5927
5928 return path;
5929}
5930
5931static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QTextItemInt &ti)
5932{
5933 QTextCharFormat::UnderlineStyle underlineStyle = ti.underlineStyle;
5934 if (underlineStyle == QTextCharFormat::NoUnderline
5935 && !(ti.flags & (QTextItem::StrikeOut | QTextItem::Overline)))
5936 return;
5937
5938 QFontEngine *fe = ti.fontEngine;
5939
5940 const QPen oldPen = painter->pen();
5941 const QBrush oldBrush = painter->brush();
5942 painter->setBrush(Qt::NoBrush);
5943 QPen pen = oldPen;
5944 pen.setStyle(Qt::SolidLine);
5945 pen.setWidthF(fe->lineThickness().toReal());
5946 pen.setCapStyle(Qt::FlatCap);
5947
5948 QLineF line(pos.x(), pos.y(), pos.x() + ti.width.toReal(), pos.y());
5949 // deliberately ceil the offset to avoid the underline coming too close to
5950 // the text above it.
5951 const qreal underlinePos = pos.y() + qCeil(fe->underlinePosition().toReal());
5952
5953 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
5954 underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle));
5955 }
5956
5957 if (underlineStyle == QTextCharFormat::WaveUnderline) {
5958 painter->save();
5959 painter->setRenderHint(QPainter::Antialiasing);
5960 painter->translate(pos.x(), underlinePos);
5961
5962 QColor uc = ti.charFormat.underlineColor();
5963 if (uc.isValid())
5964 painter->setPen(uc);
5965
5966 painter->drawPath(generateWavyPath(ti.width.toReal(),
5967 fe->underlinePosition().toReal(),
5968 painter->device()));
5969 painter->restore();
5970 } else if (underlineStyle != QTextCharFormat::NoUnderline) {
5971 QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos);
5972
5973 QColor uc = ti.charFormat.underlineColor();
5974 if (uc.isValid())
5975 pen.setColor(uc);
5976
5977 pen.setStyle((Qt::PenStyle)(underlineStyle));
5978 painter->setPen(pen);
5979 painter->drawLine(underLine);
5980 }
5981
5982 pen.setStyle(Qt::SolidLine);
5983 pen.setColor(oldPen.color());
5984
5985 if (ti.flags & QTextItem::StrikeOut) {
5986 QLineF strikeOutLine = line;
5987 strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
5988 painter->setPen(pen);
5989 painter->drawLine(strikeOutLine);
5990 }
5991
5992 if (ti.flags & QTextItem::Overline) {
5993 QLineF overLine = line;
5994 overLine.translate(0., - fe->ascent().toReal());
5995 painter->setPen(pen);
5996 painter->drawLine(overLine);
5997 }
5998
5999 painter->setPen(oldPen);
6000 painter->setBrush(oldBrush);
6001}
6002
6003/*!
6004 \internal
6005 \since 4.1
6006*/
6007void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti)
6008{
6009#ifdef QT_DEBUG_DRAW
6010 if (qt_show_painter_debug_output)
6011 printf("QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6012 p.x(), p.y(), qPrintable(_ti.text()));
6013#endif
6014
6015 Q_D(QPainter);
6016
6017 if (!d->engine)
6018 return;
6019
6020#ifndef QT_NO_DEBUG
6021 qt_painter_thread_test(d->device->devType(),
6022 "text and fonts",
6023 QFontDatabase::supportsThreadedFontRendering());
6024#endif
6025
6026 QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti));
6027
6028 if (!d->extended && d->state->bgMode == Qt::OpaqueMode) {
6029 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal());
6030 fillRect(rect, d->state->bgBrush);
6031 }
6032
6033 if (pen().style() == Qt::NoPen)
6034 return;
6035
6036 const RenderHints oldRenderHints = d->state->renderHints;
6037 if (!d->state->renderHints & QPainter::Antialiasing && d->state->matrix.type() >= QTransform::TxScale) {
6038 // draw antialias decoration (underline/overline/strikeout) with
6039 // transformed text
6040
6041 bool aa = true;
6042 const QTransform &m = d->state->matrix;
6043 if (d->state->matrix.type() < QTransform::TxShear) {
6044 bool isPlain90DegreeRotation =
6045 (qFuzzyCompare(m.m11() + 1, qreal(1))
6046 && qFuzzyCompare(m.m12(), qreal(1))
6047 && qFuzzyCompare(m.m21(), qreal(-1))
6048 && qFuzzyCompare(m.m22() + 1, qreal(1))
6049 )
6050 ||
6051 (qFuzzyCompare(m.m11(), qreal(-1))
6052 && qFuzzyCompare(m.m12() + 1, qreal(1))
6053 && qFuzzyCompare(m.m21() + 1, qreal(1))
6054 && qFuzzyCompare(m.m22(), qreal(-1))
6055 )
6056 ||
6057 (qFuzzyCompare(m.m11() + 1, qreal(1))
6058 && qFuzzyCompare(m.m12(), qreal(-1))
6059 && qFuzzyCompare(m.m21(), qreal(1))
6060 && qFuzzyCompare(m.m22() + 1, qreal(1))
6061 )
6062 ;
6063 aa = !isPlain90DegreeRotation;
6064 }
6065 if (aa)
6066 setRenderHint(QPainter::Antialiasing, true);
6067 }
6068
6069 if (!d->extended)
6070 d->updateState(d->state);
6071
6072 if (!ti.glyphs.numGlyphs) {
6073 // nothing to do
6074 } else if (ti.fontEngine->type() == QFontEngine::Multi) {
6075 QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
6076
6077 const QGlyphLayout &glyphs = ti.glyphs;
6078 int which = glyphs.glyphs[0] >> 24;
6079
6080 qreal x = p.x();
6081 qreal y = p.y();
6082
6083 int start = 0;
6084 int end, i;
6085 for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6086 const int e = glyphs.glyphs[end] >> 24;
6087 if (e == which)
6088 continue;
6089
6090
6091 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6092 ti2.width = 0;
6093 // set the high byte to zero and calc the width
6094 for (i = start; i < end; ++i) {
6095 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6096 ti2.width += ti.glyphs.effectiveAdvance(i);
6097 }
6098
6099 d->engine->drawTextItem(QPointF(x, y), ti2);
6100
6101 // reset the high byte for all glyphs and advance to the next sub-string
6102 const int hi = which << 24;
6103 for (i = start; i < end; ++i) {
6104 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6105 }
6106 x += ti2.width.toReal();
6107
6108 // change engine
6109 start = end;
6110 which = e;
6111 }
6112
6113 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6114 ti2.width = 0;
6115 // set the high byte to zero and calc the width
6116 for (i = start; i < end; ++i) {
6117 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6118 ti2.width += ti.glyphs.effectiveAdvance(i);
6119 }
6120
6121 if (d->extended)
6122 d->extended->drawTextItem(QPointF(x, y), ti2);
6123 else
6124 d->engine->drawTextItem(QPointF(x,y), ti2);
6125
6126 // reset the high byte for all glyphs
6127 const int hi = which << 24;
6128 for (i = start; i < end; ++i)
6129 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6130
6131 } else {
6132 if (d->extended)
6133 d->extended->drawTextItem(p, ti);
6134 else
6135 d->engine->drawTextItem(p, ti);
6136 }
6137 drawTextItemDecoration(this, p, ti);
6138
6139 if (d->state->renderHints != oldRenderHints) {
6140 d->state->renderHints = oldRenderHints;
6141 if (d->extended)
6142 d->extended->renderHintsChanged();
6143 else
6144 d->state->dirtyFlags |= QPaintEngine::DirtyHints;
6145 }
6146}
6147
6148/*!
6149 \fn QRectF QPainter::boundingRect(const QRectF &rectangle, int flags, const QString &text)
6150
6151 Returns the bounding rectangle of the \a text as it will appear
6152 when drawn inside the given \a rectangle with the specified \a
6153 flags using the currently set font(); i.e the function tells you
6154 where the drawText() function will draw when given the same
6155 arguments.
6156
6157 If the \a text does not fit within the given \a rectangle using
6158 the specified \a flags, the function returns the required
6159 rectangle.
6160
6161 The \a flags argument is a bitwise OR of the following flags:
6162 \list
6163 \o Qt::AlignLeft
6164 \o Qt::AlignRight
6165 \o Qt::AlignHCenter
6166 \o Qt::AlignTop
6167 \o Qt::AlignBottom
6168 \o Qt::AlignVCenter
6169 \o Qt::AlignCenter
6170 \o Qt::TextSingleLine
6171 \o Qt::TextExpandTabs
6172 \o Qt::TextShowMnemonic
6173 \o Qt::TextWordWrap
6174 \o Qt::TextIncludeTrailingSpaces
6175 \endlist
6176 If several of the horizontal or several of the vertical alignment
6177 flags are set, the resulting alignment is undefined.
6178
6179 \sa drawText(), Qt::Alignment, Qt::TextFlag
6180*/
6181
6182/*!
6183 \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
6184 const QString &text)
6185
6186 \overload
6187
6188 Returns the bounding rectangle of the \a text as it will appear
6189 when drawn inside the given \a rectangle with the specified \a
6190 flags using the currently set font().
6191*/
6192
6193/*!
6194 \fn QRect QPainter::boundingRect(int x, int y, int w, int h, int flags,
6195 const QString &text);
6196
6197 \overload
6198
6199 Returns the bounding rectangle of the given \a text as it will
6200 appear when drawn inside the rectangle beginning at the point
6201 (\a{x}, \a{y}) with width \a w and height \a h.
6202*/
6203QRect QPainter::boundingRect(const QRect &rect, int flags, const QString &str)
6204{
6205 if (str.isEmpty())
6206 return QRect(rect.x(),rect.y(), 0,0);
6207 QRect brect;
6208 drawText(rect, flags | Qt::TextDontPrint, str, &brect);
6209 return brect;
6210}
6211
6212
6213
6214QRectF QPainter::boundingRect(const QRectF &rect, int flags, const QString &str)
6215{
6216 if (str.isEmpty())
6217 return QRectF(rect.x(),rect.y(), 0,0);
6218 QRectF brect;
6219 drawText(rect, flags | Qt::TextDontPrint, str, &brect);
6220 return brect;
6221}
6222
6223/*!
6224 \fn QRectF QPainter::boundingRect(const QRectF &rectangle,
6225 const QString &text, const QTextOption &option)
6226
6227 \overload
6228
6229 Instead of specifying flags as a bitwise OR of the
6230 Qt::AlignmentFlag and Qt::TextFlag, this overloaded function takes
6231 an \a option argument. The QTextOption class provides a
6232 description of general rich text properties.
6233
6234 \sa QTextOption
6235*/
6236QRectF QPainter::boundingRect(const QRectF &r, const QString &text, const QTextOption &o)
6237{
6238 Q_D(QPainter);
6239
6240 if (!d->engine || text.length() == 0)
6241 return QRectF(r.x(),r.y(), 0,0);
6242
6243 QRectF br;
6244 qt_format_text(d->state->font, r, Qt::TextDontPrint, &o, text, &br, 0, 0, 0, this);
6245 return br;
6246}
6247
6248/*!
6249 \fn void QPainter::drawTiledPixmap(const QRectF &rectangle, const QPixmap &pixmap, const QPointF &position)
6250
6251 Draws a tiled \a pixmap, inside the given \a rectangle with its
6252 origin at the given \a position.
6253
6254 Calling drawTiledPixmap() is similar to calling drawPixmap()
6255 several times to fill (tile) an area with a pixmap, but is
6256 potentially much more efficient depending on the underlying window
6257 system.
6258
6259 \sa drawPixmap()
6260*/
6261void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sp)
6262{
6263#ifdef QT_DEBUG_DRAW
6264 if (qt_show_painter_debug_output)
6265 printf("QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6266 r.x(), r.y(), r.width(), r.height(),
6267 pixmap.width(), pixmap.height(),
6268 sp.x(), sp.y());
6269#endif
6270
6271 Q_D(QPainter);
6272 if (!d->engine || pixmap.isNull() || r.isEmpty())
6273 return;
6274
6275#ifndef QT_NO_DEBUG
6276 qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()");
6277#endif
6278
6279 qreal sw = pixmap.width();
6280 qreal sh = pixmap.height();
6281 qreal sx = sp.x();
6282 qreal sy = sp.y();
6283 if (sx < 0)
6284 sx = qRound(sw) - qRound(-sx) % qRound(sw);
6285 else
6286 sx = qRound(sx) % qRound(sw);
6287 if (sy < 0)
6288 sy = qRound(sh) - -qRound(sy) % qRound(sh);
6289 else
6290 sy = qRound(sy) % qRound(sh);
6291
6292
6293 if (d->extended) {
6294 d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6295 return;
6296 }
6297
6298 if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6299 fillRect(r, d->state->bgBrush);
6300
6301 d->updateState(d->state);
6302 if ((d->state->matrix.type() > QTransform::TxTranslate
6303 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6304 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6305 {
6306 save();
6307 setBackgroundMode(Qt::TransparentMode);
6308 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
6309 setBrush(QBrush(d->state->pen.color(), pixmap));
6310 setPen(Qt::NoPen);
6311
6312 // If there is no scaling or transformation involved we have to make sure we use the
6313 // antialiased and not the aliased coordinate system by rounding the coordinates.
6314 if (d->state->matrix.type() <= QTransform::TxTranslate) {
6315 qreal x = qRound(r.x() + d->state->matrix.dx()) - d->state->matrix.dx();
6316 qreal y = qRound(r.y() + d->state->matrix.dy()) - d->state->matrix.dy();
6317 qreal w = qRound(r.width());
6318 qreal h = qRound(r.height());
6319 sx = qRound(sx);
6320 sy = qRound(sy);
6321 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6322 drawRect(QRectF(x, y, w, h));
6323 } else {
6324 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6325 drawRect(r);
6326 }
6327 restore();
6328 return;
6329 }
6330
6331 qreal x = r.x();
6332 qreal y = r.y();
6333 if (d->state->matrix.type() == QTransform::TxTranslate
6334 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6335 x += d->state->matrix.dx();
6336 y += d->state->matrix.dy();
6337 }
6338
6339 d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
6340}
6341
6342/*!
6343 \fn QPainter::drawTiledPixmap(const QRect &rectangle, const QPixmap &pixmap,
6344 const QPoint &position = QPoint())
6345 \overload
6346
6347 Draws a tiled \a pixmap, inside the given \a rectangle with its
6348 origin at the given \a position.
6349*/
6350
6351/*!
6352 \fn void QPainter::drawTiledPixmap(int x, int y, int width, int height, const
6353 QPixmap &pixmap, int sx, int sy);
6354 \overload
6355
6356 Draws a tiled \a pixmap in the specified rectangle.
6357
6358 (\a{x}, \a{y}) specifies the top-left point in the paint device
6359 that is to be drawn onto; with the given \a width and \a
6360 height. (\a{sx}, \a{sy}) specifies the top-left point in the \a
6361 pixmap that is to be drawn; this defaults to (0, 0).
6362*/
6363
6364#ifndef QT_NO_PICTURE
6365
6366/*!
6367 \fn void QPainter::drawPicture(const QPointF &point, const QPicture &picture)
6368
6369 Replays the given \a picture at the given \a point.
6370
6371 The QPicture class is a paint device that records and replays
6372 QPainter commands. A picture serializes the painter commands to an
6373 IO device in a platform-independent format. Everything that can be
6374 painted on a widget or pixmap can also be stored in a picture.
6375
6376 This function does exactly the same as QPicture::play() when
6377 called with \a point = QPoint(0, 0).
6378
6379 \table 100%
6380 \row
6381 \o
6382 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 18
6383 \endtable
6384
6385 \sa QPicture::play()
6386*/
6387
6388void QPainter::drawPicture(const QPointF &p, const QPicture &picture)
6389{
6390 Q_D(QPainter);
6391
6392 if (!d->engine)
6393 return;
6394
6395 if (!d->extended)
6396 d->updateState(d->state);
6397
6398 save();
6399 translate(p);
6400 const_cast<QPicture *>(&picture)->play(this);
6401 restore();
6402}
6403
6404/*!
6405 \fn void QPainter::drawPicture(const QPoint &point, const QPicture &picture)
6406 \overload
6407
6408 Replays the given \a picture at the given \a point.
6409*/
6410
6411/*!
6412 \fn void QPainter::drawPicture(int x, int y, const QPicture &picture)
6413 \overload
6414
6415 Draws the given \a picture at point (\a x, \a y).
6416*/
6417
6418#endif // QT_NO_PICTURE
6419
6420/*!
6421 \fn void QPainter::eraseRect(const QRectF &rectangle)
6422
6423 Erases the area inside the given \a rectangle. Equivalent to
6424 calling
6425 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 19
6426
6427 \sa fillRect()
6428*/
6429void QPainter::eraseRect(const QRectF &r)
6430{
6431 Q_D(QPainter);
6432
6433 fillRect(r, d->state->bgBrush);
6434}
6435
6436static inline bool needsResolving(const QBrush &brush)
6437{
6438 Qt::BrushStyle s = brush.style();
6439 return ((s == Qt::LinearGradientPattern || s == Qt::RadialGradientPattern ||
6440 s == Qt::ConicalGradientPattern) &&
6441 brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode);
6442}
6443
6444/*!
6445 \fn void QPainter::eraseRect(const QRect &rectangle)
6446 \overload
6447
6448 Erases the area inside the given \a rectangle.
6449*/
6450
6451/*!
6452 \fn void QPainter::eraseRect(int x, int y, int width, int height)
6453 \overload
6454
6455 Erases the area inside the rectangle beginning at (\a x, \a y)
6456 with the given \a width and \a height.
6457*/
6458
6459
6460/*!
6461 \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::BrushStyle style)
6462 \overload
6463
6464 Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6465 width and \a height, using the brush \a style specified.
6466
6467 \since 4.5
6468*/
6469
6470/*!
6471 \fn void QPainter::fillRect(const QRect &rectangle, Qt::BrushStyle style)
6472 \overload
6473
6474 Fills the given \a rectangle with the brush \a style specified.
6475
6476 \since 4.5
6477*/
6478
6479/*!
6480 \fn void QPainter::fillRect(const QRectF &rectangle, Qt::BrushStyle style)
6481 \overload
6482
6483 Fills the given \a rectangle with the brush \a style specified.
6484
6485 \since 4.5
6486*/
6487
6488/*!
6489 \fn void QPainter::fillRect(const QRectF &rectangle, const QBrush &brush)
6490
6491 Fills the given \a rectangle with the \a brush specified.
6492
6493 Alternatively, you can specify a QColor instead of a QBrush; the
6494 QBrush constructor (taking a QColor argument) will automatically
6495 create a solid pattern brush.
6496
6497 \sa drawRect()
6498*/
6499void QPainter::fillRect(const QRectF &r, const QBrush &brush)
6500{
6501 Q_D(QPainter);
6502
6503 if (!d->engine)
6504 return;
6505
6506 if (d->extended) {
6507 const QGradient *g = brush.gradient();
6508 if (!g || g->coordinateMode() == QGradient::LogicalMode) {
6509 d->extended->fillRect(r, brush);
6510 return;
6511 }
6512 }
6513
6514 QPen oldPen = pen();
6515 QBrush oldBrush = this->brush();
6516 setPen(Qt::NoPen);
6517 if (brush.style() == Qt::SolidPattern) {
6518 d->colorBrush.setStyle(Qt::SolidPattern);
6519 d->colorBrush.setColor(brush.color());
6520 setBrush(d->colorBrush);
6521 } else {
6522 setBrush(brush);
6523 }
6524
6525 drawRect(r);
6526 setBrush(oldBrush);
6527 setPen(oldPen);
6528}
6529
6530/*!
6531 \fn void QPainter::fillRect(const QRect &rectangle, const QBrush &brush)
6532 \overload
6533
6534 Fills the given \a rectangle with the specified \a brush.
6535*/
6536
6537void QPainter::fillRect(const QRect &r, const QBrush &brush)
6538{
6539 Q_D(QPainter);
6540
6541 if (!d->engine)
6542 return;
6543
6544 if (d->extended) {
6545 const QGradient *g = brush.gradient();
6546 if (!g || g->coordinateMode() == QGradient::LogicalMode) {
6547 d->extended->fillRect(r, brush);
6548 return;
6549 }
6550 }
6551
6552 QPen oldPen = pen();
6553 QBrush oldBrush = this->brush();
6554 setPen(Qt::NoPen);
6555 if (brush.style() == Qt::SolidPattern) {
6556 d->colorBrush.setStyle(Qt::SolidPattern);
6557 d->colorBrush.setColor(brush.color());
6558 setBrush(d->colorBrush);
6559 } else {
6560 setBrush(brush);
6561 }
6562
6563 drawRect(r);
6564 setBrush(oldBrush);
6565 setPen(oldPen);
6566}
6567
6568
6569
6570/*!
6571 \fn void QPainter::fillRect(const QRect &rectangle, const QColor &color)
6572 \overload
6573
6574 Fills the given \a rectangle with the \a color specified.
6575
6576 \since 4.5
6577*/
6578void QPainter::fillRect(const QRect &r, const QColor &color)
6579{
6580 Q_D(QPainter);
6581
6582 if (!d->engine)
6583 return;
6584
6585 if (d->extended) {
6586 d->extended->fillRect(r, color);
6587 return;
6588 }
6589
6590 fillRect(r, QBrush(color));
6591}
6592
6593
6594/*!
6595 \fn void QPainter::fillRect(const QRectF &rectangle, const QColor &color)
6596 \overload
6597
6598 Fills the given \a rectangle with the \a color specified.
6599
6600 \since 4.5
6601*/
6602void QPainter::fillRect(const QRectF &r, const QColor &color)
6603{
6604 Q_D(QPainter);
6605
6606 if (!d->engine)
6607 return;
6608
6609 if (d->extended) {
6610 d->extended->fillRect(r, color);
6611 return;
6612 }
6613
6614 fillRect(r, QBrush(color));
6615}
6616
6617/*!
6618 \fn void QPainter::fillRect(int x, int y, int width, int height, const QBrush &brush)
6619
6620 \overload
6621
6622 Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6623 width and \a height, using the given \a brush.
6624*/
6625
6626/*!
6627 \fn void QPainter::fillRect(int x, int y, int width, int height, const QColor &color)
6628
6629 \overload
6630
6631 Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6632 width and \a height, using the given \a color.
6633
6634 \since 4.5
6635*/
6636
6637/*!
6638 \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::GlobalColor color)
6639
6640 \overload
6641
6642 Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6643 width and \a height, using the given \a color.
6644
6645 \since 4.5
6646*/
6647
6648/*!
6649 \fn void QPainter::fillRect(const QRect &rectangle, Qt::GlobalColor color);
6650
6651 \overload
6652
6653 Fills the given \a rectangle with the specified \a color.
6654
6655 \since 4.5
6656*/
6657
6658/*!
6659 \fn void QPainter::fillRect(const QRectF &rectangle, Qt::GlobalColor color);
6660
6661 \overload
6662
6663 Fills the given \a rectangle with the specified \a color.
6664
6665 \since 4.5
6666*/
6667
6668/*!
6669 Sets the given render \a hint on the painter if \a on is true;
6670 otherwise clears the render hint.
6671
6672 \sa setRenderHints(), renderHints(), {QPainter#Rendering
6673 Quality}{Rendering Quality}
6674*/
6675void QPainter::setRenderHint(RenderHint hint, bool on)
6676{
6677#ifdef QT_DEBUG_DRAW
6678 if (qt_show_painter_debug_output)
6679 printf("QPainter::setRenderHint: hint=%x, %s\n", hint, on ? "on" : "off");
6680#endif
6681
6682#ifndef QT_NO_DEBUG
6683 static const bool antialiasingDisabled = qgetenv("QT_NO_ANTIALIASING").toInt();
6684 if (hint == QPainter::Antialiasing && antialiasingDisabled)
6685 return;
6686#endif
6687
6688 setRenderHints(hint, on);
6689}
6690
6691/*!
6692 \since 4.2
6693
6694 Sets the given render \a hints on the painter if \a on is true;
6695 otherwise clears the render hints.
6696
6697 \sa setRenderHint(), renderHints(), {QPainter#Rendering
6698 Quality}{Rendering Quality}
6699*/
6700
6701void QPainter::setRenderHints(RenderHints hints, bool on)
6702{
6703 Q_D(QPainter);
6704
6705 if (!d->engine) {
6706 qWarning("QPainter::setRenderHint: Painter must be active to set rendering hints");
6707 return;
6708 }
6709
6710 if (on)
6711 d->state->renderHints |= hints;
6712 else
6713 d->state->renderHints &= ~hints;
6714
6715 if (d->extended)
6716 d->extended->renderHintsChanged();
6717 else
6718 d->state->dirtyFlags |= QPaintEngine::DirtyHints;
6719}
6720
6721/*!
6722 Returns a flag that specifies the rendering hints that are set for
6723 this painter.
6724
6725 \sa testRenderHint(), {QPainter#Rendering Quality}{Rendering Quality}
6726*/
6727QPainter::RenderHints QPainter::renderHints() const
6728{
6729 Q_D(const QPainter);
6730
6731 if (!d->engine)
6732 return 0;
6733
6734 return d->state->renderHints;
6735}
6736
6737/*!
6738 \fn bool QPainter::testRenderHint(RenderHint hint) const
6739 \since 4.3
6740
6741 Returns true if \a hint is set; otherwise returns false.
6742
6743 \sa renderHints(), setRenderHint()
6744*/
6745
6746/*!
6747 Returns true if view transformation is enabled; otherwise returns
6748 false.
6749
6750 \sa setViewTransformEnabled(), worldMatrix()
6751*/
6752
6753bool QPainter::viewTransformEnabled() const
6754{
6755 Q_D(const QPainter);
6756 if (!d->engine) {
6757 qWarning("QPainter::viewTransformEnabled: Painter not active");
6758 return false;
6759 }
6760 return d->state->VxF;
6761}
6762
6763/*!
6764 \fn void QPainter::setWindow(const QRect &rectangle)
6765
6766 Sets the painter's window to the given \a rectangle, and enables
6767 view transformations.
6768
6769 The window rectangle is part of the view transformation. The
6770 window specifies the logical coordinate system. Its sister, the
6771 viewport(), specifies the device coordinate system.
6772
6773 The default window rectangle is the same as the device's
6774 rectangle.
6775
6776 \sa window(), viewTransformEnabled(), {The Coordinate
6777 System#Window-Viewport Conversion}{Window-Viewport Conversion}
6778*/
6779
6780/*!
6781 \fn void QPainter::setWindow(int x, int y, int width, int height)
6782 \overload
6783
6784 Sets the painter's window to the rectangle beginning at (\a x, \a
6785 y) and the given \a width and \a height.
6786*/
6787
6788void QPainter::setWindow(const QRect &r)
6789{
6790#ifdef QT_DEBUG_DRAW
6791 if (qt_show_painter_debug_output)
6792 printf("QPainter::setWindow(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
6793#endif
6794
6795 Q_D(QPainter);
6796
6797 if (!d->engine) {
6798 qWarning("QPainter::setWindow: Painter not active");
6799 return;
6800 }
6801
6802 d->state->wx = r.x();
6803 d->state->wy = r.y();
6804 d->state->ww = r.width();
6805 d->state->wh = r.height();
6806
6807 d->state->VxF = true;
6808 d->updateMatrix();
6809}
6810
6811/*!
6812 Returns the window rectangle.
6813
6814 \sa setWindow(), setViewTransformEnabled()
6815*/
6816
6817QRect QPainter::window() const
6818{
6819 Q_D(const QPainter);
6820 if (!d->engine) {
6821 qWarning("QPainter::window: Painter not active");
6822 return QRect();
6823 }
6824 return QRect(d->state->wx, d->state->wy, d->state->ww, d->state->wh);
6825}
6826
6827/*!
6828 \fn void QPainter::setViewport(const QRect &rectangle)
6829
6830 Sets the painter's viewport rectangle to the given \a rectangle,
6831 and enables view transformations.
6832
6833 The viewport rectangle is part of the view transformation. The
6834 viewport specifies the device coordinate system. Its sister, the
6835 window(), specifies the logical coordinate system.
6836
6837 The default viewport rectangle is the same as the device's
6838 rectangle.
6839
6840 \sa viewport(), viewTransformEnabled() {The Coordinate
6841 System#Window-Viewport Conversion}{Window-Viewport Conversion}
6842*/
6843
6844/*!
6845 \fn void QPainter::setViewport(int x, int y, int width, int height)
6846 \overload
6847
6848 Sets the painter's viewport rectangle to be the rectangle
6849 beginning at (\a x, \a y) with the given \a width and \a height.
6850*/
6851
6852void QPainter::setViewport(const QRect &r)
6853{
6854#ifdef QT_DEBUG_DRAW
6855 if (qt_show_painter_debug_output)
6856 printf("QPainter::setViewport(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
6857#endif
6858
6859 Q_D(QPainter);
6860
6861 if (!d->engine) {
6862 qWarning("QPainter::setViewport: Painter not active");
6863 return;
6864 }
6865
6866 d->state->vx = r.x();
6867 d->state->vy = r.y();
6868 d->state->vw = r.width();
6869 d->state->vh = r.height();
6870
6871 d->state->VxF = true;
6872 d->updateMatrix();
6873}
6874
6875/*!
6876 Returns the viewport rectangle.
6877
6878 \sa setViewport(), setViewTransformEnabled()
6879*/
6880
6881QRect QPainter::viewport() const
6882{
6883 Q_D(const QPainter);
6884 if (!d->engine) {
6885 qWarning("QPainter::viewport: Painter not active");
6886 return QRect();
6887 }
6888 return QRect(d->state->vx, d->state->vy, d->state->vw, d->state->vh);
6889}
6890
6891/*! \fn bool QPainter::hasViewXForm() const
6892 \compat
6893
6894 Use viewTransformEnabled() instead.
6895*/
6896
6897/*! \fn bool QPainter::hasWorldXForm() const
6898 \compat
6899
6900 Use worldMatrixEnabled() instead.
6901*/
6902
6903/*! \fn void QPainter::resetXForm()
6904 \compat
6905
6906 Use resetMatrix() instead.
6907*/
6908
6909/*! \fn void QPainter::setViewXForm(bool enabled)
6910 \compat
6911
6912 Use setViewTransformEnabled() instead.
6913*/
6914
6915/*! \fn void QPainter::setWorldXForm(bool enabled)
6916 \compat
6917
6918 Use setWorldMatrixEnabled() instead.
6919*/
6920/*!
6921 Enables view transformations if \a enable is true, or disables
6922 view transformations if \a enable is false.
6923
6924 \sa viewTransformEnabled(), {The Coordinate System#Window-Viewport
6925 Conversion}{Window-Viewport Conversion}
6926*/
6927
6928void QPainter::setViewTransformEnabled(bool enable)
6929{
6930#ifdef QT_DEBUG_DRAW
6931 if (qt_show_painter_debug_output)
6932 printf("QPainter::setViewTransformEnabled(), enable=%d\n", enable);
6933#endif
6934
6935 Q_D(QPainter);
6936
6937 if (!d->engine) {
6938 qWarning("QPainter::setViewTransformEnabled: Painter not active");
6939 return;
6940 }
6941
6942 if (enable == d->state->VxF)
6943 return;
6944
6945 d->state->VxF = enable;
6946 d->updateMatrix();
6947}
6948
6949#ifdef QT3_SUPPORT
6950
6951/*!
6952 Use the worldMatrix() combined with QMatrix::dx() instead.
6953
6954 \oldcode
6955 QPainter painter(this);
6956 qreal x = painter.translationX();
6957 \newcode
6958 QPainter painter(this);
6959 qreal x = painter.worldMatrix().dx();
6960 \endcode
6961*/
6962qreal QPainter::translationX() const
6963{
6964 Q_D(const QPainter);
6965 if (!d->engine) {
6966 qWarning("QPainter::translationX: Painter not active");
6967 return 0.0;
6968 }
6969 return d->state->worldMatrix.dx();
6970}
6971
6972/*!
6973 Use the worldMatrix() combined with QMatrix::dy() instead.
6974
6975 \oldcode
6976 QPainter painter(this);
6977 qreal y = painter.translationY();
6978 \newcode
6979 QPainter painter(this);
6980 qreal y = painter.worldMatrix().dy();
6981 \endcode
6982*/
6983qreal QPainter::translationY() const
6984{
6985 Q_D(const QPainter);
6986 if (!d->engine) {
6987 qWarning("QPainter::translationY: Painter not active");
6988 return 0.0;
6989 }
6990 return d->state->worldMatrix.dy();
6991}
6992
6993/*!
6994 \fn void QPainter::map(int x, int y, int *rx, int *ry) const
6995
6996 \internal
6997
6998 Sets (\a{rx}, \a{ry}) to the point that results from applying the
6999 painter's current transformation on the point (\a{x}, \a{y}).
7000*/
7001void QPainter::map(int x, int y, int *rx, int *ry) const
7002{
7003 QPoint p(x, y);
7004 p = p * combinedMatrix();
7005 *rx = p.x();
7006 *ry = p.y();
7007}
7008
7009/*!
7010 \fn QPoint QPainter::xForm(const QPoint &point) const
7011
7012 Use combinedTransform() instead.
7013*/
7014
7015QPoint QPainter::xForm(const QPoint &p) const
7016{
7017 Q_D(const QPainter);
7018 if (!d->engine) {
7019 qWarning("QPainter::xForm: Painter not active");
7020 return QPoint();
7021 }
7022 if (d->state->matrix.type() == QTransform::TxNone)
7023 return p;
7024 return p * combinedMatrix();
7025}
7026
7027
7028/*!
7029 \fn QRect QPainter::xForm(const QRect &rectangle) const
7030 \overload
7031
7032 Use combinedTransform() instead of this function and call
7033 mapRect() on the result to obtain a QRect.
7034*/
7035
7036QRect QPainter::xForm(const QRect &r) const
7037{
7038 Q_D(const QPainter);
7039 if (!d->engine) {
7040 qWarning("QPainter::xForm: Painter not active");
7041 return QRect();
7042 }
7043 if (d->state->matrix.type() == QTransform::TxNone)
7044 return r;
7045 return combinedMatrix().mapRect(r);
7046}
7047
7048/*!
7049 \fn QPolygon QPainter::xForm(const QPolygon &polygon) const
7050 \overload
7051
7052 Use combinedTransform() instead.
7053*/
7054
7055QPolygon QPainter::xForm(const QPolygon &a) const
7056{
7057 Q_D(const QPainter);
7058 if (!d->engine) {
7059 qWarning("QPainter::xForm: Painter not active");
7060 return QPolygon();
7061 }
7062 if (d->state->matrix.type() == QTransform::TxNone)
7063 return a;
7064 return a * combinedMatrix();
7065}
7066
7067/*!
7068 \fn QPolygon QPainter::xForm(const QPolygon &polygon, int index, int count) const
7069 \overload
7070
7071 Use combinedTransform() combined with QPolygon::mid() instead.
7072
7073 \oldcode
7074 QPainter painter(this);
7075 QPolygon transformed = painter.xForm(polygon, index, count)
7076 \newcode
7077 QPainter painter(this);
7078 QPolygon transformed = polygon.mid(index, count) * painter.combinedMatrix();
7079 \endcode
7080*/
7081
7082QPolygon QPainter::xForm(const QPolygon &av, int index, int npoints) const
7083{
7084 int lastPoint = npoints < 0 ? av.size() : index+npoints;
7085 QPolygon a(lastPoint-index);
7086 memcpy(a.data(), av.data()+index, (lastPoint-index)*sizeof(QPoint));
7087 return a * combinedMatrix();
7088}
7089
7090/*!
7091 \fn QPoint QPainter::xFormDev(const QPoint &point) const
7092 \overload
7093
7094 Use combinedTransform() combined with QMatrix::inverted() instead.
7095
7096 \oldcode
7097 QPainter painter(this);
7098 QPoint transformed = painter.xFormDev(point);
7099 \newcode
7100 QPainter painter(this);
7101 QPoint transformed = point * painter.combinedMatrix().inverted();
7102 \endcode
7103*/
7104
7105QPoint QPainter::xFormDev(const QPoint &p) const
7106{
7107 Q_D(const QPainter);
7108 if (!d->engine) {
7109 qWarning("QPainter::xFormDev: Painter not active");
7110 return QPoint();
7111 }
7112 if(d->state->matrix.type() == QTransform::TxNone)
7113 return p;
7114 return p * combinedMatrix().inverted();
7115}
7116
7117/*!
7118 \fn QRect QPainter::xFormDev(const QRect &rectangle) const
7119 \overload
7120
7121 Use combineMatrix() combined with QMatrix::inverted() instead.
7122
7123 \oldcode
7124 QPainter painter(this);
7125 QRect transformed = painter.xFormDev(rectangle);
7126 \newcode
7127 QPainter painter(this);
7128 QRect transformed = rectangle * painter.combinedMatrix().inverted();
7129 \endcode
7130*/
7131
7132QRect QPainter::xFormDev(const QRect &r) const
7133{
7134 Q_D(const QPainter);
7135 if (!d->engine) {
7136 qWarning("QPainter::xFormDev: Painter not active");
7137 return QRect();
7138 }
7139 if (d->state->matrix.type() == QTransform::TxNone)
7140 return r;
7141 return combinedMatrix().inverted().mapRect(r);
7142}
7143
7144/*!
7145 \overload
7146
7147 \fn QPoint QPainter::xFormDev(const QPolygon &polygon) const
7148 \overload
7149
7150 Use combinedMatrix() combined with QMatrix::inverted() instead.
7151
7152 \oldcode
7153 QPainter painter(this);
7154 QPolygon transformed = painter.xFormDev(rectangle);
7155 \newcode
7156 QPainter painter(this);
7157 QPolygon transformed = polygon * painter.combinedMatrix().inverted();
7158 \endcode
7159*/
7160
7161QPolygon QPainter::xFormDev(const QPolygon &a) const
7162{
7163 Q_D(const QPainter);
7164 if (!d->engine) {
7165 qWarning("QPainter::xFormDev: Painter not active");
7166 return QPolygon();
7167 }
7168 if (d->state->matrix.type() == QTransform::TxNone)
7169 return a;
7170 return a * combinedMatrix().inverted();
7171}
7172
7173/*!
7174 \fn QPolygon QPainter::xFormDev(const QPolygon &polygon, int index, int count) const
7175 \overload
7176
7177 Use combinedMatrix() combined with QPolygon::mid() and QMatrix::inverted() instead.
7178
7179 \oldcode
7180 QPainter painter(this);
7181 QPolygon transformed = painter.xFormDev(polygon, index, count);
7182 \newcode
7183 QPainter painter(this);
7184 QPolygon transformed = polygon.mid(index, count) * painter.combinedMatrix().inverted();
7185 \endcode
7186*/
7187
7188QPolygon QPainter::xFormDev(const QPolygon &ad, int index, int npoints) const
7189{
7190 Q_D(const QPainter);
7191 int lastPoint = npoints < 0 ? ad.size() : index+npoints;
7192 QPolygon a(lastPoint-index);
7193 memcpy(a.data(), ad.data()+index, (lastPoint-index)*sizeof(QPoint));
7194 if (d->state->matrix.type() == QTransform::TxNone)
7195 return a;
7196 return a * combinedMatrix().inverted();
7197}
7198
7199/*!
7200 \fn void QPainter::drawCubicBezier(const QPolygon &controlPoints, int index)
7201
7202 Draws a cubic Bezier curve defined by the \a controlPoints,
7203 starting at \a{controlPoints}\e{[index]} (\a index defaults to 0).
7204 Points after \a{controlPoints}\e{[index + 3]} are ignored. Nothing
7205 happens if there aren't enough control points.
7206
7207 Use strokePath() instead.
7208
7209 \oldcode
7210 QPainter painter(this);
7211 painter.drawCubicBezier(controlPoints, index)
7212 \newcode
7213 QPainterPath path;
7214 path.moveTo(controlPoints.at(index));
7215 path.cubicTo(controlPoints.at(index+1),
7216 controlPoints.at(index+2),
7217 controlPoints.at(index+3));
7218
7219 QPainter painter(this);
7220 painter.strokePath(path, painter.pen());
7221 \endcode
7222*/
7223void QPainter::drawCubicBezier(const QPolygon &a, int index)
7224{
7225 Q_D(QPainter);
7226
7227 if (!d->engine)
7228 return;
7229
7230 if ((int)a.size() - index < 4) {
7231 qWarning("QPainter::drawCubicBezier: Cubic Bezier needs 4 control "
7232 "points");
7233 return;
7234 }
7235
7236 QPainterPath path;
7237 path.moveTo(a.at(index));
7238 path.cubicTo(a.at(index+1), a.at(index+2), a.at(index+3));
7239 strokePath(path, d->state->pen);
7240}
7241#endif
7242
7243struct QPaintDeviceRedirection
7244{
7245 QPaintDeviceRedirection() : device(0), replacement(0), internalWidgetRedirectionIndex(-1) {}
7246 QPaintDeviceRedirection(const QPaintDevice *device, QPaintDevice *replacement,
7247 const QPoint& offset, int internalWidgetRedirectionIndex)
7248 : device(device), replacement(replacement), offset(offset),
7249 internalWidgetRedirectionIndex(internalWidgetRedirectionIndex) { }
7250 const QPaintDevice *device;
7251 QPaintDevice *replacement;
7252 QPoint offset;
7253 int internalWidgetRedirectionIndex;
7254 bool operator==(const QPaintDevice *pdev) const { return device == pdev; }
7255 Q_DUMMY_COMPARISON_OPERATOR(QPaintDeviceRedirection)
7256};
7257
7258typedef QList<QPaintDeviceRedirection> QPaintDeviceRedirectionList;
7259Q_GLOBAL_STATIC(QPaintDeviceRedirectionList, globalRedirections)
7260Q_GLOBAL_STATIC(QMutex, globalRedirectionsMutex)
7261
7262/*!
7263 \threadsafe
7264
7265 Redirects all paint commands for the given paint \a device, to the
7266 \a replacement device. The optional point \a offset defines an
7267 offset within the source device.
7268
7269 The redirection will not be effective until the begin() function
7270 has been called; make sure to call end() for the given \a
7271 device's painter (if any) before redirecting. Call
7272 restoreRedirected() to restore the previous redirection.
7273
7274 In general, you'll probably find that calling
7275 QPixmap::grabWidget() or QPixmap::grabWindow() is an easier
7276 solution.
7277
7278 \sa redirected(), restoreRedirected()
7279*/
7280void QPainter::setRedirected(const QPaintDevice *device,
7281 QPaintDevice *replacement,
7282 const QPoint &offset)
7283{
7284 Q_ASSERT(device != 0);
7285
7286 bool hadInternalWidgetRedirection = false;
7287 if (device->devType() == QInternal::Widget) {
7288 const QWidgetPrivate *widgetPrivate = static_cast<const QWidget *>(device)->d_func();
7289 // This is the case when the widget is in a paint event.
7290 if (widgetPrivate->redirectDev) {
7291 // Remove internal redirection and put it back into the global redirection list.
7292 QPoint oldOffset;
7293 QPaintDevice *oldReplacement = widgetPrivate->redirected(&oldOffset);
7294 const_cast<QWidgetPrivate *>(widgetPrivate)->restoreRedirected();
7295 setRedirected(device, oldReplacement, oldOffset);
7296 hadInternalWidgetRedirection = true;
7297 }
7298 }
7299
7300 QPoint roffset;
7301 QPaintDevice *rdev = redirected(replacement, &roffset);
7302
7303 QMutexLocker locker(globalRedirectionsMutex());
7304 QPaintDeviceRedirectionList *redirections = globalRedirections();
7305 Q_ASSERT(redirections != 0);
7306 *redirections += QPaintDeviceRedirection(device, rdev ? rdev : replacement, offset + roffset,
7307 hadInternalWidgetRedirection ? redirections->size() - 1 : -1);
7308}
7309
7310/*!
7311 \threadsafe
7312
7313 Restores the previous redirection for the given \a device after a
7314 call to setRedirected().
7315
7316 \sa redirected()
7317 */
7318void QPainter::restoreRedirected(const QPaintDevice *device)
7319{
7320 Q_ASSERT(device != 0);
7321 QMutexLocker locker(globalRedirectionsMutex());
7322 QPaintDeviceRedirectionList *redirections = globalRedirections();
7323 Q_ASSERT(redirections != 0);
7324 for (int i = redirections->size()-1; i >= 0; --i) {
7325 if (redirections->at(i) == device) {
7326 const int internalWidgetRedirectionIndex = redirections->at(i).internalWidgetRedirectionIndex;
7327 redirections->removeAt(i);
7328 // Restore the internal widget redirection, i.e. remove it from the global
7329 // redirection list and put it back into QWidgetPrivate. The index is only set when
7330 // someone call QPainter::setRedirected in a widget's paint event and we internally
7331 // have a redirection set (typically set in QWidgetPrivate::drawWidget).
7332 if (internalWidgetRedirectionIndex >= 0) {
7333 Q_ASSERT(internalWidgetRedirectionIndex < redirections->size());
7334 const QPaintDeviceRedirection &redirectionDevice = redirections->at(internalWidgetRedirectionIndex);
7335 QWidget *widget = static_cast<QWidget *>(const_cast<QPaintDevice *>(device));
7336 widget->d_func()->setRedirected(redirectionDevice.replacement, redirectionDevice.offset);
7337 redirections->removeAt(internalWidgetRedirectionIndex);
7338 }
7339 return;
7340 }
7341 }
7342}
7343
7344/*!
7345 \threadsafe
7346
7347 Returns the replacement for given \a device. The optional out
7348 parameter \a offset returns the offset within the replaced device.
7349
7350 \sa setRedirected(), restoreRedirected()
7351*/
7352QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset)
7353{
7354 Q_ASSERT(device != 0);
7355
7356 if (device->devType() == QInternal::Widget) {
7357 const QWidgetPrivate *widgetPrivate = static_cast<const QWidget *>(device)->d_func();
7358 if (widgetPrivate->redirectDev)
7359 return widgetPrivate->redirected(offset);
7360 }
7361
7362 QMutexLocker locker(globalRedirectionsMutex());
7363 QPaintDeviceRedirectionList *redirections = globalRedirections();
7364 Q_ASSERT(redirections != 0);
7365 for (int i = redirections->size()-1; i >= 0; --i)
7366 if (redirections->at(i) == device) {
7367 if (offset)
7368 *offset = redirections->at(i).offset;
7369 return redirections->at(i).replacement;
7370 }
7371 if (offset)
7372 *offset = QPoint(0, 0);
7373 return 0;
7374}
7375
7376
7377void qt_painter_removePaintDevice(QPaintDevice *dev)
7378{
7379 QMutexLocker locker(globalRedirectionsMutex());
7380 if(QPaintDeviceRedirectionList *redirections = globalRedirections()) {
7381 for (int i = 0; i < redirections->size(); ) {
7382 if(redirections->at(i) == dev || redirections->at(i).replacement == dev)
7383 redirections->removeAt(i);
7384 else
7385 ++i;
7386 }
7387 }
7388}
7389
7390void qt_format_text(const QFont &fnt, const QRectF &_r,
7391 int tf, const QString& str, QRectF *brect,
7392 int tabstops, int *ta, int tabarraylen,
7393 QPainter *painter)
7394{
7395 qt_format_text(fnt, _r,
7396 tf, 0, str, brect,
7397 tabstops, ta, tabarraylen,
7398 painter);
7399}
7400void qt_format_text(const QFont &fnt, const QRectF &_r,
7401 int tf, const QTextOption *option, const QString& str, QRectF *brect,
7402 int tabstops, int *, int tabarraylen,
7403 QPainter *painter)
7404{
7405
7406 Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=0) ); // we either have an option or flags
7407
7408 if (option) {
7409 tf |= option->alignment();
7410 if (option->wrapMode() != QTextOption::NoWrap)
7411 tf |= Qt::TextWordWrap;
7412
7413 if (option->flags() & QTextOption::IncludeTrailingSpaces)
7414 tf |= Qt::TextIncludeTrailingSpaces;
7415
7416 if (option->tabStop() >= 0 || !option->tabArray().isEmpty())
7417 tf |= Qt::TextExpandTabs;
7418 }
7419
7420 // we need to copy r here to protect against the case (&r == brect).
7421 QRectF r(_r);
7422
7423 bool dontclip = (tf & Qt::TextDontClip);
7424 bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7425 bool singleline = (tf & Qt::TextSingleLine);
7426 bool showmnemonic = (tf & Qt::TextShowMnemonic);
7427 bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7428
7429 Qt::LayoutDirection layout_direction;
7430 if(option)
7431 layout_direction = option->textDirection();
7432 else if (painter)
7433 layout_direction = painter->layoutDirection();
7434 else
7435 layout_direction = Qt::LeftToRight;
7436
7437 tf = QStyle::visualAlignment(layout_direction, QFlag(tf));
7438
7439 bool isRightToLeft = layout_direction == Qt::RightToLeft;
7440 bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7441 (((tf & Qt::AlignLeft) && !isRightToLeft) ||
7442 ((tf & Qt::AlignRight) && isRightToLeft)));
7443
7444 if (!painter)
7445 tf |= Qt::TextDontPrint;
7446
7447 int maxUnderlines = 0;
7448 int numUnderlines = 0;
7449 int underlinePositionStack[32];
7450 int *underlinePositions = underlinePositionStack;
7451
7452 QFontMetricsF fm(fnt);
7453
7454 QString text = str;
7455 // compatible behaviour to the old implementation. Replace
7456 // tabs by spaces
7457 QChar *chr = text.data();
7458 const QChar *end = chr + str.length();
7459 bool has_tab = false;
7460 while (chr != end) {
7461 if (*chr == QLatin1Char('\r') || (singleline && *chr == QLatin1Char('\n'))) {
7462 *chr = QLatin1Char(' ');
7463 } else if (*chr == QLatin1Char('\n')) {
7464 *chr = QChar::LineSeparator;
7465 } else if (*chr == QLatin1Char('&')) {
7466 ++maxUnderlines;
7467 } else if (*chr == QLatin1Char('\t')) {
7468 has_tab = true;
7469 }
7470 ++chr;
7471 }
7472 if (has_tab) {
7473 if (!expandtabs) {
7474 chr = text.data();
7475 while (chr != end) {
7476 if (*chr == QLatin1Char('\t'))
7477 *chr = QLatin1Char(' ');
7478 ++chr;
7479 }
7480 } else if (!tabarraylen && !tabstops) {
7481 tabstops = qRound(fm.width(QLatin1Char('x'))*8);
7482 }
7483 }
7484
7485 if (hidemnmemonic || showmnemonic) {
7486 if (maxUnderlines > 32)
7487 underlinePositions = new int[maxUnderlines];
7488 QChar *cout = text.data();
7489 QChar *cin = cout;
7490 int l = str.length();
7491 while (l) {
7492 if (*cin == QLatin1Char('&')) {
7493 ++cin;
7494 --l;
7495 if (!l)
7496 break;
7497 if (*cin != QLatin1Char('&') && !hidemnmemonic)
7498 underlinePositions[numUnderlines++] = cout - text.unicode();
7499 }
7500 *cout = *cin;
7501 ++cout;
7502 ++cin;
7503 --l;
7504 }
7505 int newlen = cout - text.unicode();
7506 if (newlen != text.length())
7507 text.resize(newlen);
7508 }
7509
7510 // no need to do extra work for underlines if we don't paint
7511 if (tf & Qt::TextDontPrint)
7512 numUnderlines = 0;
7513
7514 underlinePositions[numUnderlines] = -1;
7515 qreal height = 0;
7516 qreal width = 0;
7517
7518 QStackTextEngine engine(text, fnt);
7519 if (option) {
7520 engine.option = *option;
7521 }
7522
7523
7524
7525 engine.option.setTextDirection(layout_direction);
7526 if (tf & Qt::AlignJustify)
7527 engine.option.setAlignment(Qt::AlignJustify);
7528 else
7529 engine.option.setAlignment(Qt::AlignLeft); // do not do alignment twice
7530
7531 if (!option && (tf & Qt::TextWrapAnywhere))
7532 engine.option.setWrapMode(QTextOption::WrapAnywhere);
7533
7534 if (tf & Qt::TextJustificationForced)
7535 engine.forceJustification = true;
7536 QTextLayout textLayout(&engine);
7537 textLayout.setCacheEnabled(true);
7538 textLayout.engine()->underlinePositions = underlinePositions;
7539
7540 if (text.isEmpty()) {
7541 height = fm.height();
7542 width = 0;
7543 tf |= Qt::TextDontPrint;
7544 } else {
7545 qreal lineWidth = 0x01000000;
7546 if (wordwrap || (tf & Qt::TextJustificationForced))
7547 lineWidth = qMax<qreal>(0, r.width());
7548 if(!wordwrap)
7549 tf |= Qt::TextIncludeTrailingSpaces;
7550 textLayout.engine()->ignoreBidi = bool(tf & Qt::TextDontPrint);
7551 textLayout.beginLayout();
7552
7553 qreal leading = fm.leading();
7554 height = -leading;
7555
7556 while (1) {
7557 QTextLine l = textLayout.createLine();
7558 if (!l.isValid())
7559 break;
7560
7561 l.setLineWidth(lineWidth);
7562 height += leading;
7563 l.setPosition(QPointF(0., height));
7564 height += l.height();
7565 width = qMax(width, l.naturalTextWidth());
7566 if (!brect && height >= r.height())
7567 break;
7568 }
7569 textLayout.endLayout();
7570 }
7571
7572 qreal yoff = 0;
7573 qreal xoff = 0;
7574 if (tf & Qt::AlignBottom) {
7575 yoff = r.height() - height;
7576 } else if (tf & Qt::AlignVCenter) {
7577 yoff = (r.height() - height)/2;
7578 if (painter) {
7579 QTransform::TransformationType type = painter->transform().type();
7580 if (type <= QTransform::TxScale) {
7581 // do the rounding manually to work around inconsistencies
7582 // in the paint engines when drawing on floating point offsets
7583 const qreal scale = painter->transform().m22();
7584 if (scale != 0)
7585 yoff = qRound(yoff * scale) / scale;
7586 }
7587 }
7588 }
7589 if (tf & Qt::AlignRight) {
7590 xoff = r.width() - width;
7591 } else if (tf & Qt::AlignHCenter) {
7592 xoff = (r.width() - width)/2;
7593 if (painter) {
7594 QTransform::TransformationType type = painter->transform().type();
7595 if (type <= QTransform::TxScale) {
7596 // do the rounding manually to work around inconsistencies
7597 // in the paint engines when drawing on floating point offsets
7598 const qreal scale = painter->transform().m11();
7599 if (scale != 0)
7600 xoff = qRound(xoff * scale) / scale;
7601 }
7602 }
7603 }
7604 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7605 if (brect)
7606 *brect = bounds;
7607
7608 if (!(tf & Qt::TextDontPrint)) {
7609 bool restore = false;
7610 if (!dontclip && !r.contains(bounds)) {
7611 restore = true;
7612 painter->save();
7613 painter->setClipRect(r, Qt::IntersectClip);
7614 }
7615
7616 for (int i = 0; i < textLayout.lineCount(); i++) {
7617 QTextLine line = textLayout.lineAt(i);
7618
7619 if (tf & Qt::AlignRight)
7620 xoff = r.width() - line.naturalTextWidth();
7621 else if (tf & Qt::AlignHCenter)
7622 xoff = (r.width() - line.naturalTextWidth())/2;
7623
7624 line.draw(painter, QPointF(r.x() + xoff + line.x(), r.y() + yoff));
7625 }
7626
7627 if (restore) {
7628 painter->restore();
7629 }
7630 }
7631
7632 if (underlinePositions != underlinePositionStack)
7633 delete [] underlinePositions;
7634}
7635
7636/*!
7637 Sets the layout direction used by the painter when drawing text,
7638 to the specified \a direction.
7639
7640 \sa layoutDirection(), drawText(), {QPainter#Settings}{Settings}
7641*/
7642void QPainter::setLayoutDirection(Qt::LayoutDirection direction)
7643{
7644 Q_D(QPainter);
7645 if (d->state)
7646 d->state->layoutDirection = direction;
7647}
7648
7649/*!
7650 Returns the layout direction used by the painter when drawing text.
7651
7652 \sa setLayoutDirection(), drawText(), {QPainter#Settings}{Settings}
7653*/
7654Qt::LayoutDirection QPainter::layoutDirection() const
7655{
7656 Q_D(const QPainter);
7657 return d->state ? d->state->layoutDirection : Qt::LeftToRight;
7658}
7659
7660QPainterState::QPainterState(const QPainterState *s)
7661 : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7662 pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7663 clipRegion(s->clipRegion), clipPath(s->clipPath),
7664 clipOperation(s->clipOperation),
7665 renderHints(s->renderHints), clipInfo(s->clipInfo),
7666 worldMatrix(s->worldMatrix), matrix(s->matrix), redirection_offset(s->redirection_offset),
7667 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7668 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7669 opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7670 clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7671 layoutDirection(s->layoutDirection),
7672 composition_mode(s->composition_mode),
7673 emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7674{
7675 dirtyFlags = s->dirtyFlags;
7676}
7677
7678QPainterState::QPainterState()
7679 : brushOrigin(0, 0), bgBrush(Qt::white), clipOperation(Qt::NoClip),
7680 renderHints(0),
7681 wx(0), wy(0), ww(0), wh(0), vx(0), vy(0), vw(0), vh(0),
7682 opacity(1), WxF(false), VxF(false), clipEnabled(true),
7683 bgMode(Qt::TransparentMode), painter(0),
7684 layoutDirection(QApplication::layoutDirection()),
7685 composition_mode(QPainter::CompositionMode_SourceOver),
7686 emulationSpecifier(0), changeFlags(0)
7687{
7688 dirtyFlags = 0;
7689}
7690
7691QPainterState::~QPainterState()
7692{
7693}
7694
7695void QPainterState::init(QPainter *p) {
7696 bgBrush = Qt::white;
7697 bgMode = Qt::TransparentMode;
7698 WxF = false;
7699 VxF = false;
7700 clipEnabled = true;
7701 wx = wy = ww = wh = 0;
7702 vx = vy = vw = vh = 0;
7703 painter = p;
7704 pen = QPen();
7705 brushOrigin = QPointF(0, 0);
7706 brush = QBrush();
7707 font = deviceFont = QFont();
7708 clipRegion = QRegion();
7709 clipPath = QPainterPath();
7710 clipOperation = Qt::NoClip;
7711 clipInfo.clear();
7712 worldMatrix.reset();
7713 matrix.reset();
7714 layoutDirection = QApplication::layoutDirection();
7715 composition_mode = QPainter::CompositionMode_SourceOver;
7716 emulationSpecifier = 0;
7717 dirtyFlags = 0;
7718 changeFlags = 0;
7719 renderHints = 0;
7720 opacity = 1;
7721}
7722
7723#ifdef QT3_SUPPORT
7724static void bitBlt_helper(QPaintDevice *dst, const QPoint &dp,
7725 const QPaintDevice *src, const QRect &sr, bool)
7726{
7727 Q_ASSERT(dst);
7728 Q_ASSERT(src);
7729
7730 if (src->devType() == QInternal::Pixmap) {
7731 const QPixmap *pixmap = static_cast<const QPixmap *>(src);
7732 QPainter pt(dst);
7733 pt.drawPixmap(dp, *pixmap, sr);
7734
7735 } else {
7736 qWarning("QPainter: bitBlt only works when source is of type pixmap");
7737 }
7738}
7739
7740void bitBlt(QPaintDevice *dst, int dx, int dy,
7741 const QPaintDevice *src, int sx, int sy, int sw, int sh,
7742 bool ignoreMask )
7743{
7744 bitBlt_helper(dst, QPoint(dx, dy), src, QRect(sx, sy, sw, sh), ignoreMask);
7745}
7746
7747void bitBlt(QPaintDevice *dst, const QPoint &dp, const QPaintDevice *src, const QRect &sr, bool ignoreMask)
7748{
7749 bitBlt_helper(dst, dp, src, sr, ignoreMask);
7750}
7751
7752void bitBlt(QPaintDevice *dst, int dx, int dy,
7753 const QImage *src, int sx, int sy, int sw, int sh, int fl)
7754{
7755 Qt::ImageConversionFlags flags(fl);
7756 QPixmap srcPixmap = QPixmap::fromImage(*src, flags);
7757 bitBlt_helper(dst, QPoint(dx, dy), &srcPixmap, QRect(sx, sy, sw, sh), false);
7758}
7759
7760#endif // QT3_SUPPORT
7761
7762/*!
7763 \fn void QPainter::setBackgroundColor(const QColor &color)
7764
7765 Use setBackground() instead.
7766*/
7767
7768/*!
7769 \fn const QColor &QPainter::backgroundColor() const
7770
7771 Use background() and QBrush::color() instead.
7772
7773 \oldcode
7774 QColor myColor = backgroundColor();
7775 \newcode
7776 QColor myColor = background().color();
7777 \endcode
7778
7779 Note that the background can be a complex brush such as a texture
7780 or a gradient.
7781*/
7782
7783/*!
7784 \fn void QPainter::drawText(int x, int y, const QString &text, int pos, int length)
7785 \compat
7786
7787 Use drawText() combined with QString::mid() instead.
7788
7789 \oldcode
7790 QPainter painter(this);
7791 painter.drawText(x, y, text, pos, length);
7792 \newcode
7793 QPainter painter(this);
7794 painter.drawText(x, y, text.mid(pos, length));
7795 \endcode
7796*/
7797
7798/*!
7799 \fn void QPainter::drawText(const QPoint &point, const QString &text, int pos, int length)
7800 \compat
7801
7802 Use drawText() combined with QString::mid() instead.
7803
7804 \oldcode
7805 QPainter painter(this);
7806 painter.drawText(point, text, pos, length);
7807 \newcode
7808 QPainter painter(this);
7809 painter.drawText(point, text.mid(pos, length));
7810 \endcode
7811*/
7812
7813/*!
7814 \fn void QPainter::drawText(int x, int y, const QString &text, int length)
7815 \compat
7816
7817 Use drawText() combined with QString::left() instead.
7818
7819 \oldcode
7820 QPainter painter(this);
7821 painter.drawText(x, y, text, length);
7822 \newcode
7823 QPainter painter(this);
7824 painter.drawText(x, y, text.left(length));
7825 \endcode
7826*/
7827
7828/*!
7829 \fn void QPainter::drawText(const QPoint &point, const QString &text, int length)
7830 \compat
7831
7832 Use drawText() combined with QString::left() instead.
7833
7834 \oldcode
7835 QPainter painter(this);
7836 painter.drawText(point, text, length);
7837 \newcode
7838 QPainter painter(this);
7839 painter.drawText(point, text.left(length));
7840 \endcode
7841*/
7842
7843/*!
7844 \fn bool QPainter::begin(QPaintDevice *device, const QWidget *init)
7845 \compat
7846
7847 Use begin() instead.
7848
7849 If the paint \a device is a QWidget, QPainter is initialized after
7850 the widget's settings automatically. Otherwise, you must call the
7851 initFrom() function to initialize the painters pen, background and
7852 font to the same as any given widget.
7853
7854 \oldcode
7855 QPainter painter(this);
7856 painter.begin(device, init);
7857 \newcode
7858 QPainter painter(this);
7859 painter.begin(device);
7860 painter.initFrom(init);
7861 \endcode
7862*/
7863
7864/*!
7865 \fn void QPainter::drawImage(const QRectF &target, const QImage &image, const QRectF &source,
7866 Qt::ImageConversionFlags flags)
7867
7868 Draws the rectangular portion \a source of the given \a image
7869 into the \a target rectangle in the paint device.
7870
7871 \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7872
7873 If the image needs to be modified to fit in a lower-resolution
7874 result (e.g. converting from 32-bit to 8-bit), use the \a flags to
7875 specify how you would prefer this to happen.
7876
7877 \table 100%
7878 \row
7879 \o
7880 \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 20
7881 \endtable
7882
7883 \sa drawPixmap()
7884*/
7885
7886/*!
7887 \fn void QPainter::drawImage(const QRect &target, const QImage &image, const QRect &source,
7888 Qt::ImageConversionFlags flags)
7889 \overload
7890
7891 Draws the rectangular portion \a source of the given \a image
7892 into the \a target rectangle in the paint device.
7893
7894 \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7895*/
7896
7897/*!
7898 \fn void QPainter::drawImage(const QPointF &point, const QImage &image)
7899
7900 \overload
7901
7902 Draws the given \a image at the given \a point.
7903*/
7904
7905/*!
7906 \fn void QPainter::drawImage(const QPoint &point, const QImage &image)
7907
7908 \overload
7909
7910 Draws the given \a image at the given \a point.
7911*/
7912
7913/*!
7914 \fn void QPainter::drawImage(const QPointF &point, const QImage &image, const QRectF &source,
7915 Qt::ImageConversionFlags flags = 0)
7916
7917 \overload
7918
7919 Draws the rectangular portion \a source of the given \a image with
7920 its origin at the given \a point.
7921*/
7922
7923/*!
7924 \fn void QPainter::drawImage(const QPoint &point, const QImage &image, const QRect &source,
7925 Qt::ImageConversionFlags flags = 0)
7926 \overload
7927
7928 Draws the rectangular portion \a source of the given \a image with
7929 its origin at the given \a point.
7930*/
7931
7932/*!
7933 \fn void QPainter::drawImage(const QRectF &rectangle, const QImage &image)
7934
7935 \overload
7936
7937 Draws the given \a image into the given \a rectangle.
7938
7939 \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7940*/
7941
7942/*!
7943 \fn void QPainter::drawImage(const QRect &rectangle, const QImage &image)
7944
7945 \overload
7946
7947 Draws the given \a image into the given \a rectangle.
7948
7949 \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7950*/
7951
7952/*!
7953 \fn void QPainter::drawImage(int x, int y, const QImage &image,
7954 int sx, int sy, int sw, int sh,
7955 Qt::ImageConversionFlags flags)
7956 \overload
7957
7958 Draws an image at (\a{x}, \a{y}) by copying a part of \a image into
7959 the paint device.
7960
7961 (\a{x}, \a{y}) specifies the top-left point in the paint device that is
7962 to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
7963 image that is to be drawn. The default is (0, 0).
7964
7965 (\a{sw}, \a{sh}) specifies the size of the image that is to be drawn.
7966 The default, (0, 0) (and negative) means all the way to the
7967 bottom-right of the image.
7968*/
7969
7970/*!
7971 \fn void QPainter::redirect(QPaintDevice *pdev, QPaintDevice *replacement)
7972
7973 Use setRedirected() instead.
7974*/
7975
7976/*!
7977 \fn QPaintDevice *QPainter::redirect(QPaintDevice *pdev)
7978
7979 Use redirected() instead.
7980*/
7981
7982/*!
7983 \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
7984 const QString &text, int length)
7985 \compat
7986
7987 Returns the bounding rectangle for the given \a length of the \a
7988 text constrained by the provided \a rectangle.
7989
7990 Use boundingRect() combined with QString::left() instead.
7991
7992 \oldcode
7993 QRect rectangle = boundingRect(rect, flags, text, length);
7994 \newcode
7995 QRect rectangle = boundingRect(rect, flags, text.left(length));
7996 \endcode
7997*/
7998
7999/*!
8000 \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text,
8001 int length, QRect *br)
8002 \compat
8003
8004 Use drawText() combined with QString::left() instead.
8005
8006 \oldcode
8007 QPainter painter(this);
8008 painter.drawText(rectangle, flags, text, length, br );
8009 \newcode
8010 QPainter painter(this);
8011 painter.drawText(rectangle, flags, text.left(length), br );
8012 \endcode
8013*/
8014
8015/*!
8016 \fn QRect QPainter::boundingRect(int x, int y, int width, int height, int flags,
8017 const QString &text, int length);
8018
8019 \compat
8020
8021 Returns the bounding rectangle for the given \a length of the \a
8022 text constrained by the rectangle that begins at point (\a{x},
8023 \a{y}) with the given \a width and \a height.
8024
8025 Use boundingRect() combined with QString::left() instead.
8026
8027 \oldcode
8028 QRect rectangle = boundingRect(x, y, width, height, flags, text, length);
8029 \newcode
8030 QRect rectangle = boundingRect(x, y, width, height, flags, text.left(length));
8031 \endcode
8032*/
8033
8034/*!
8035 \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
8036 const QString &text, int length, QRect *br)
8037
8038 \compat
8039
8040 Use drawText() combined with QString::left() instead.
8041
8042 \oldcode
8043 QPainter painter(this);
8044 painter.drawText(x, y, width, height, flags, text, length, br );
8045 \newcode
8046 QPainter painter(this);
8047 painter.drawText(x, y, width, height, flags, text.left(length), br );
8048 \endcode
8049*/
8050
8051
8052/*!
8053 \class QPaintEngineState
8054 \since 4.1
8055
8056 \brief The QPaintEngineState class provides information about the
8057 active paint engine's current state.
8058 \reentrant
8059
8060 QPaintEngineState records which properties that have changed since
8061 the last time the paint engine was updated, as well as their
8062 current value.
8063
8064 Which properties that have changed can at any time be retrieved
8065 using the state() function. This function returns an instance of
8066 the QPaintEngine::DirtyFlags type which stores an OR combination
8067 of QPaintEngine::DirtyFlag values. The QPaintEngine::DirtyFlag
8068 enum defines whether a property has changed since the last update
8069 or not.
8070
8071 If a property is marked with a dirty flag, its current value can
8072 be retrieved using the corresponding get function:
8073
8074 \target GetFunction
8075
8076 \table
8077 \header \o Property Flag \o Current Property Value
8078 \row \o QPaintEngine::DirtyBackground \o backgroundBrush()
8079 \row \o QPaintEngine::DirtyBackgroundMode \o backgroundMode()
8080 \row \o QPaintEngine::DirtyBrush \o brush()
8081 \row \o QPaintEngine::DirtyBrushOrigin \o brushOrigin()
8082 \row \o QPaintEngine::DirtyClipRegion \e or QPaintEngine::DirtyClipPath
8083 \o clipOperation()
8084 \row \o QPaintEngine::DirtyClipPath \o clipPath()
8085 \row \o QPaintEngine::DirtyClipRegion \o clipRegion()
8086 \row \o QPaintEngine::DirtyCompositionMode \o compositionMode()
8087 \row \o QPaintEngine::DirtyFont \o font()
8088 \row \o QPaintEngine::DirtyTransform \o matrix()
8089 \row \o QPaintEngine::DirtyClipEnabled \o isClipEnabled()
8090 \row \o QPaintEngine::DirtyPen \o pen()
8091 \row \o QPaintEngine::DirtyHints \o renderHints()
8092 \endtable
8093
8094 The QPaintEngineState class also provide the painter() function
8095 which returns a pointer to the painter that is currently updating
8096 the paint engine.
8097
8098 An instance of this class, representing the current state of the
8099 active paint engine, is passed as argument to the
8100 QPaintEngine::updateState() function. The only situation in which
8101 you will have to use this class directly is when implementing your
8102 own paint engine.
8103
8104 \sa QPaintEngine
8105*/
8106
8107
8108/*!
8109 \fn QPaintEngine::DirtyFlags QPaintEngineState::state() const
8110
8111 Returns a combination of flags identifying the set of properties
8112 that need to be updated when updating the paint engine's state
8113 (i.e. during a call to the QPaintEngine::updateState() function).
8114
8115 \sa QPaintEngine::updateState()
8116*/
8117
8118
8119/*!
8120 Returns the pen in the current paint engine state.
8121
8122 This variable should only be used when the state() returns a
8123 combination which includes the QPaintEngine::DirtyPen flag.
8124
8125 \sa state(), QPaintEngine::updateState()
8126*/
8127
8128QPen QPaintEngineState::pen() const
8129{
8130 return static_cast<const QPainterState *>(this)->pen;
8131}
8132
8133/*!
8134 Returns the brush in the current paint engine state.
8135
8136 This variable should only be used when the state() returns a
8137 combination which includes the QPaintEngine::DirtyBrush flag.
8138
8139 \sa state(), QPaintEngine::updateState()
8140*/
8141
8142QBrush QPaintEngineState::brush() const
8143{
8144 return static_cast<const QPainterState *>(this)->brush;
8145}
8146
8147/*!
8148 Returns the brush origin in the current paint engine state.
8149
8150 This variable should only be used when the state() returns a
8151 combination which includes the QPaintEngine::DirtyBrushOrigin flag.
8152
8153 \sa state(), QPaintEngine::updateState()
8154*/
8155
8156QPointF QPaintEngineState::brushOrigin() const
8157{
8158 return static_cast<const QPainterState *>(this)->brushOrigin;
8159}
8160
8161/*!
8162 Returns the background brush in the current paint engine state.
8163
8164 This variable should only be used when the state() returns a
8165 combination which includes the QPaintEngine::DirtyBackground flag.
8166
8167 \sa state(), QPaintEngine::updateState()
8168*/
8169
8170QBrush QPaintEngineState::backgroundBrush() const
8171{
8172 return static_cast<const QPainterState *>(this)->bgBrush;
8173}
8174
8175/*!
8176 Returns the background mode in the current paint engine
8177 state.
8178
8179 This variable should only be used when the state() returns a
8180 combination which includes the QPaintEngine::DirtyBackgroundMode flag.
8181
8182 \sa state(), QPaintEngine::updateState()
8183*/
8184
8185Qt::BGMode QPaintEngineState::backgroundMode() const
8186{
8187 return static_cast<const QPainterState *>(this)->bgMode;
8188}
8189
8190/*!
8191 Returns the font in the current paint engine
8192 state.
8193
8194 This variable should only be used when the state() returns a
8195 combination which includes the QPaintEngine::DirtyFont flag.
8196
8197 \sa state(), QPaintEngine::updateState()
8198*/
8199
8200QFont QPaintEngineState::font() const
8201{
8202 return static_cast<const QPainterState *>(this)->font;
8203}
8204
8205/*!
8206 \since 4.2
8207
8208 Returns the matrix in the current paint engine
8209 state.
8210
8211 This variable should only be used when the state() returns a
8212 combination which includes the QPaintEngine::DirtyTransform flag.
8213
8214 \sa state(), QPaintEngine::updateState()
8215*/
8216
8217QMatrix QPaintEngineState::matrix() const
8218{
8219 const QPainterState *st = static_cast<const QPainterState *>(this);
8220
8221 return st->matrix.toAffine();
8222}
8223
8224/*!
8225 \since 4.3
8226
8227 Returns the matrix in the current paint engine state.
8228
8229 This variable should only be used when the state() returns a
8230 combination which includes the QPaintEngine::DirtyTransform flag.
8231
8232 \sa state(), QPaintEngine::updateState()
8233*/
8234
8235
8236QTransform QPaintEngineState::transform() const
8237{
8238 const QPainterState *st = static_cast<const QPainterState *>(this);
8239
8240 return st->matrix;
8241}
8242
8243
8244/*!
8245 Returns the clip operation in the current paint engine
8246 state.
8247
8248 This variable should only be used when the state() returns a
8249 combination which includes either the QPaintEngine::DirtyClipPath
8250 or the QPaintEngine::DirtyClipRegion flag.
8251
8252 \sa state(), QPaintEngine::updateState()
8253*/
8254
8255Qt::ClipOperation QPaintEngineState::clipOperation() const
8256{
8257 return static_cast<const QPainterState *>(this)->clipOperation;
8258}
8259
8260/*!
8261 \since 4.3
8262
8263 Returns whether the coordinate of the fill have been specified
8264 as bounded by the current rendering operation and have to be
8265 resolved (about the currently rendered primitive).
8266*/
8267bool QPaintEngineState::brushNeedsResolving() const
8268{
8269 const QBrush &brush = static_cast<const QPainterState *>(this)->brush;
8270 return needsResolving(brush);
8271}
8272
8273
8274/*!
8275 \since 4.3
8276
8277 Returns whether the coordinate of the stroke have been specified
8278 as bounded by the current rendering operation and have to be
8279 resolved (about the currently rendered primitive).
8280*/
8281bool QPaintEngineState::penNeedsResolving() const
8282{
8283 const QPen &pen = static_cast<const QPainterState *>(this)->pen;
8284 return needsResolving(pen.brush());
8285}
8286
8287/*!
8288 Returns the clip region in the current paint engine state.
8289
8290 This variable should only be used when the state() returns a
8291 combination which includes the QPaintEngine::DirtyClipRegion flag.
8292
8293 \sa state(), QPaintEngine::updateState()
8294*/
8295
8296QRegion QPaintEngineState::clipRegion() const
8297{
8298 return static_cast<const QPainterState *>(this)->clipRegion;
8299}
8300
8301/*!
8302 Returns the clip path in the current paint engine state.
8303
8304 This variable should only be used when the state() returns a
8305 combination which includes the QPaintEngine::DirtyClipPath flag.
8306
8307 \sa state(), QPaintEngine::updateState()
8308*/
8309
8310QPainterPath QPaintEngineState::clipPath() const
8311{
8312 return static_cast<const QPainterState *>(this)->clipPath;
8313}
8314
8315/*!
8316 Returns wether clipping is enabled or not in the current paint
8317 engine state.
8318
8319 This variable should only be used when the state() returns a
8320 combination which includes the QPaintEngine::DirtyClipEnabled
8321 flag.
8322
8323 \sa state(), QPaintEngine::updateState()
8324*/
8325
8326bool QPaintEngineState::isClipEnabled() const
8327{
8328 return static_cast<const QPainterState *>(this)->clipEnabled;
8329}
8330
8331/*!
8332 Returns the render hints in the current paint engine state.
8333
8334 This variable should only be used when the state() returns a
8335 combination which includes the QPaintEngine::DirtyHints
8336 flag.
8337
8338 \sa state(), QPaintEngine::updateState()
8339*/
8340
8341QPainter::RenderHints QPaintEngineState::renderHints() const
8342{
8343 return static_cast<const QPainterState *>(this)->renderHints;
8344}
8345
8346/*!
8347 Returns the composition mode in the current paint engine state.
8348
8349 This variable should only be used when the state() returns a
8350 combination which includes the QPaintEngine::DirtyCompositionMode
8351 flag.
8352
8353 \sa state(), QPaintEngine::updateState()
8354*/
8355
8356QPainter::CompositionMode QPaintEngineState::compositionMode() const
8357{
8358 return static_cast<const QPainterState *>(this)->composition_mode;
8359}
8360
8361
8362/*!
8363 Returns a pointer to the painter currently updating the paint
8364 engine.
8365*/
8366
8367QPainter *QPaintEngineState::painter() const
8368{
8369 return static_cast<const QPainterState *>(this)->painter;
8370}
8371
8372
8373/*!
8374 \since 4.2
8375
8376 Returns the opacity in the current paint engine state.
8377*/
8378
8379qreal QPaintEngineState::opacity() const
8380{
8381 return static_cast<const QPainterState *>(this)->opacity;
8382}
8383
8384/*!
8385 \since 4.3
8386
8387 Sets the world transformation matrix.
8388 If \a combine is true, the specified \a transform is combined with
8389 the current matrix; otherwise it replaces the current matrix.
8390
8391 This function has been added for compatibility with setMatrix(),
8392 but as with setMatrix() the preferred method of setting a
8393 transformation on the painter is through setWorldTransform().
8394
8395 \sa transform()
8396*/
8397
8398void QPainter::setTransform(const QTransform &transform, bool combine )
8399{
8400 setWorldTransform(transform, combine);
8401}
8402
8403/*!
8404 Returns the world transformation matrix.
8405*/
8406
8407const QTransform & QPainter::transform() const
8408{
8409 return worldTransform();
8410}
8411
8412
8413/*!
8414 Returns the matrix that transforms from logical coordinates to
8415 device coordinates of the platform dependent paint device.
8416
8417 This function is \e only needed when using platform painting
8418 commands on the platform dependent handle (Qt::HANDLE), and the
8419 platform does not do transformations nativly.
8420
8421 The QPaintEngine::PaintEngineFeature enum can be queried to
8422 determine whether the platform performs the transformations or
8423 not.
8424
8425 \sa worldTransform(), QPaintEngine::hasFeature(),
8426*/
8427
8428const QTransform & QPainter::deviceTransform() const
8429{
8430 Q_D(const QPainter);
8431 if (!d->engine) {
8432 qWarning("QPainter::deviceTransform: Painter not active");
8433 return d->fakeState()->transform;
8434 }
8435 return d->state->matrix;
8436}
8437
8438
8439/*!
8440 Resets any transformations that were made using translate(),
8441 scale(), shear(), rotate(), setWorldTransform(), setViewport()
8442 and setWindow().
8443
8444 \sa {Coordinate Transformations}
8445*/
8446
8447void QPainter::resetTransform()
8448{
8449 Q_D(QPainter);
8450#ifdef QT_DEBUG_DRAW
8451 if (qt_show_painter_debug_output)
8452 printf("QPainter::resetMatrix()\n");
8453#endif
8454 if (!d->engine) {
8455 qWarning("QPainter::resetMatrix: Painter not active");
8456 return;
8457 }
8458
8459 d->state->wx = d->state->wy = d->state->vx = d->state->vy = 0; // default view origins
8460 d->state->ww = d->state->vw = d->device->metric(QPaintDevice::PdmWidth);
8461 d->state->wh = d->state->vh = d->device->metric(QPaintDevice::PdmHeight);
8462 d->state->worldMatrix = QTransform();
8463 setMatrixEnabled(false);
8464 setViewTransformEnabled(false);
8465 if (d->extended)
8466 d->extended->transformChanged();
8467 else
8468 d->state->dirtyFlags |= QPaintEngine::DirtyTransform;
8469}
8470
8471/*!
8472 Sets the world transformation matrix.
8473 If \a combine is true, the specified \a matrix is combined with the current matrix;
8474 otherwise it replaces the current matrix.
8475
8476 \sa transform(), setTransform()
8477*/
8478
8479void QPainter::setWorldTransform(const QTransform &matrix, bool combine )
8480{
8481 Q_D(QPainter);
8482
8483 if (!d->engine) {
8484 qWarning("QPainter::setWorldTransform: Painter not active");
8485 return;
8486 }
8487
8488 if (combine)
8489 d->state->worldMatrix = matrix * d->state->worldMatrix; // combines
8490 else
8491 d->state->worldMatrix = matrix; // set new matrix
8492
8493 d->state->WxF = true;
8494 d->updateMatrix();
8495}
8496
8497/*!
8498 Returns the world transformation matrix.
8499*/
8500
8501const QTransform & QPainter::worldTransform() const
8502{
8503 Q_D(const QPainter);
8504 if (!d->engine) {
8505 qWarning("QPainter::worldTransform: Painter not active");
8506 return d->fakeState()->transform;
8507 }
8508 return d->state->worldMatrix;
8509}
8510
8511/*!
8512 Returns the transformation matrix combining the current
8513 window/viewport and world transformation.
8514
8515 \sa setWorldMatrix(), setWindow(), setViewport()
8516*/
8517
8518QTransform QPainter::combinedTransform() const
8519{
8520 Q_D(const QPainter);
8521 if (!d->engine) {
8522 qWarning("QPainter::combinedTransform: Painter not active");
8523 return QTransform();
8524 }
8525 return d->state->worldMatrix * d->viewTransform();
8526}
8527
8528void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
8529{
8530 p->draw_helper(path, operation);
8531}
8532
8533QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.