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