PageRenderTime 109ms CodeModel.GetById 50ms RepoModel.GetById 0ms app.codeStats 1ms

/src/gui/painting/qpainter.cpp

https://bitbucket.org/manctl/qt
C++ | 9658 lines | 4457 code | 1149 blank | 4052 comment | 1337 complexity | e90d1e4df250518317650084385ab757 MD5 | raw file
Possible License(s): CC0-1.0, CC-BY-SA-4.0, LGPL-2.1, GPL-3.0, Apache-2.0, LGPL-2.0, LGPL-3.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  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 Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. // QtCore
  42. #include <qdebug.h>
  43. #include <qmath.h>
  44. #include <qmutex.h>
  45. // QtGui
  46. #include "qbitmap.h"
  47. #include "qimage.h"
  48. #include "qpaintdevice.h"
  49. #include "qpaintengine.h"
  50. #include "qpainter.h"
  51. #include "qpainter_p.h"
  52. #include "qpainterpath.h"
  53. #include "qpicture.h"
  54. #include "qpixmapcache.h"
  55. #include "qpolygon.h"
  56. #include "qtextlayout.h"
  57. #include "qwidget.h"
  58. #include "qapplication.h"
  59. #include "qstyle.h"
  60. #include "qthread.h"
  61. #include "qvarlengtharray.h"
  62. #include "qstatictext.h"
  63. #include "qglyphrun.h"
  64. #include <private/qfontengine_p.h>
  65. #include <private/qpaintengine_p.h>
  66. #include <private/qemulationpaintengine_p.h>
  67. #include <private/qpainterpath_p.h>
  68. #include <private/qtextengine_p.h>
  69. #include <private/qwidget_p.h>
  70. #include <private/qpaintengine_raster_p.h>
  71. #include <private/qmath_p.h>
  72. #include <private/qstatictext_p.h>
  73. #include <private/qglyphrun_p.h>
  74. #include <private/qstylehelper_p.h>
  75. #include <private/qrawfont_p.h>
  76. QT_BEGIN_NAMESPACE
  77. #define QGradient_StretchToDevice 0x10000000
  78. #define QPaintEngine_OpaqueBackground 0x40000000
  79. // #define QT_DEBUG_DRAW
  80. #ifdef QT_DEBUG_DRAW
  81. bool qt_show_painter_debug_output = true;
  82. #endif
  83. extern QPixmap qt_pixmapForBrush(int style, bool invert);
  84. void qt_format_text(const QFont &font,
  85. const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
  86. int tabstops, int* tabarray, int tabarraylen,
  87. QPainter *painter);
  88. static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe,
  89. QTextCharFormat::UnderlineStyle underlineStyle,
  90. QTextItem::RenderFlags flags, qreal width,
  91. const QTextCharFormat &charFormat);
  92. // Helper function to calculate left most position, width and flags for decoration drawing
  93. Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
  94. const QFixedPoint *positions, int glyphCount,
  95. QFontEngine *fontEngine, const QFont &font,
  96. const QTextCharFormat &charFormat);
  97. static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
  98. {
  99. switch (brush.style()) {
  100. case Qt::LinearGradientPattern:
  101. case Qt::RadialGradientPattern:
  102. case Qt::ConicalGradientPattern:
  103. return brush.gradient()->coordinateMode();
  104. default:
  105. ;
  106. }
  107. return QGradient::LogicalMode;
  108. }
  109. /* Returns true if the gradient requires stretch to device...*/
  110. static inline bool check_gradient(const QBrush &brush)
  111. {
  112. return coordinateMode(brush) == QGradient::StretchToDeviceMode;
  113. }
  114. extern bool qHasPixmapTexture(const QBrush &);
  115. static inline bool is_brush_transparent(const QBrush &brush) {
  116. Qt::BrushStyle s = brush.style();
  117. bool brushBitmap = qHasPixmapTexture(brush)
  118. ? brush.texture().isQBitmap()
  119. : (brush.textureImage().depth() == 1);
  120. return ((s >= Qt::Dense1Pattern && s <= Qt::DiagCrossPattern)
  121. || (s == Qt::TexturePattern && brushBitmap));
  122. }
  123. static inline bool is_pen_transparent(const QPen &pen) {
  124. return pen.style() > Qt::SolidLine || is_brush_transparent(pen.brush());
  125. }
  126. /* Discards the emulation flags that are not relevant for line drawing
  127. and returns the result
  128. */
  129. static inline uint line_emulation(uint emulation)
  130. {
  131. return emulation & (QPaintEngine::PrimitiveTransform
  132. | QPaintEngine::AlphaBlend
  133. | QPaintEngine::Antialiasing
  134. | QPaintEngine::BrushStroke
  135. | QPaintEngine::ConstantOpacity
  136. | QGradient_StretchToDevice
  137. | QPaintEngine::ObjectBoundingModeGradients
  138. | QPaintEngine_OpaqueBackground);
  139. }
  140. #ifndef QT_NO_DEBUG
  141. static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false)
  142. {
  143. switch (devType) {
  144. case QInternal::Image:
  145. case QInternal::Printer:
  146. case QInternal::Picture:
  147. // can be drawn onto these devices safely from any thread
  148. #ifndef Q_WS_WIN
  149. if (extraCondition)
  150. #endif
  151. break;
  152. default:
  153. #ifdef Q_WS_X11
  154. if (QApplication::testAttribute(Qt::AA_X11InitThreads))
  155. return true;
  156. #endif
  157. if (!extraCondition && QThread::currentThread() != qApp->thread()) {
  158. qWarning("QPainter: It is not safe to use %s outside the GUI thread", what);
  159. return false;
  160. }
  161. break;
  162. }
  163. return true;
  164. }
  165. #endif
  166. void QPainterPrivate::checkEmulation()
  167. {
  168. Q_ASSERT(extended);
  169. if (extended->flags() & QPaintEngineEx::DoNotEmulate)
  170. return;
  171. bool doEmulation = false;
  172. if (state->bgMode == Qt::OpaqueMode)
  173. doEmulation = true;
  174. const QGradient *bg = state->brush.gradient();
  175. if (bg && bg->coordinateMode() > QGradient::LogicalMode)
  176. doEmulation = true;
  177. const QGradient *pg = qpen_brush(state->pen).gradient();
  178. if (pg && pg->coordinateMode() > QGradient::LogicalMode)
  179. doEmulation = true;
  180. if (doEmulation) {
  181. if (extended != emulationEngine) {
  182. if (!emulationEngine)
  183. emulationEngine = new QEmulationPaintEngine(extended);
  184. extended = emulationEngine;
  185. extended->setState(state);
  186. }
  187. } else if (emulationEngine == extended) {
  188. extended = emulationEngine->real_engine;
  189. }
  190. }
  191. QPainterPrivate::~QPainterPrivate()
  192. {
  193. delete emulationEngine;
  194. for (int i=0; i<states.size(); ++i)
  195. delete states.at(i);
  196. if (dummyState)
  197. delete dummyState;
  198. }
  199. QTransform QPainterPrivate::viewTransform() const
  200. {
  201. if (state->VxF) {
  202. qreal scaleW = qreal(state->vw)/qreal(state->ww);
  203. qreal scaleH = qreal(state->vh)/qreal(state->wh);
  204. return QTransform(scaleW, 0, 0, scaleH,
  205. state->vx - state->wx*scaleW, state->vy - state->wy*scaleH);
  206. }
  207. return QTransform();
  208. }
  209. /*
  210. \internal
  211. Returns true if using a shared painter; otherwise false.
  212. */
  213. bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
  214. {
  215. Q_ASSERT(q);
  216. Q_ASSERT(pdev);
  217. if (pdev->devType() != QInternal::Widget)
  218. return false;
  219. QWidget *widget = static_cast<QWidget *>(pdev);
  220. Q_ASSERT(widget);
  221. // Someone either called QPainter::setRedirected in the widget's paint event
  222. // right before this painter was created (or begin was called) or
  223. // sent a paint event directly to the widget.
  224. if (!widget->d_func()->redirectDev)
  225. return false;
  226. QPainter *sp = widget->d_func()->sharedPainter();
  227. if (!sp || !sp->isActive())
  228. return false;
  229. if (sp->paintEngine()->paintDevice() != widget->d_func()->redirectDev)
  230. return false;
  231. // Check if we're attempting to paint outside a paint event.
  232. if (!sp->d_ptr->engine->hasFeature(QPaintEngine::PaintOutsidePaintEvent)
  233. && !widget->testAttribute(Qt::WA_PaintOutsidePaintEvent)
  234. && !widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
  235. qWarning("QPainter::begin: Widget painting can only begin as a result of a paintEvent");
  236. return false;
  237. }
  238. // Save the current state of the shared painter and assign
  239. // the current d_ptr to the shared painter's d_ptr.
  240. sp->save();
  241. if (!sp->d_ptr->d_ptrs) {
  242. // Allocate space for 4 d-pointers (enough for up to 4 sub-sequent
  243. // redirections within the same paintEvent(), which should be enough
  244. // in 99% of all cases). E.g: A renders B which renders C which renders D.
  245. sp->d_ptr->d_ptrs_size = 4;
  246. sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *));
  247. Q_CHECK_PTR(sp->d_ptr->d_ptrs);
  248. } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) {
  249. // However, to support corner cases we grow the array dynamically if needed.
  250. sp->d_ptr->d_ptrs_size <<= 1;
  251. const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *);
  252. sp->d_ptr->d_ptrs = q_check_ptr((QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize));
  253. }
  254. sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr.data();
  255. q->d_ptr.take();
  256. q->d_ptr.reset(sp->d_ptr.data());
  257. Q_ASSERT(q->d_ptr->state);
  258. // Now initialize the painter with correct widget properties.
  259. q->initFrom(widget);
  260. QPoint offset;
  261. widget->d_func()->redirected(&offset);
  262. offset += q->d_ptr->engine->coordinateOffset();
  263. // Update system rect.
  264. q->d_ptr->state->ww = q->d_ptr->state->vw = widget->width();
  265. q->d_ptr->state->wh = q->d_ptr->state->vh = widget->height();
  266. // Update matrix.
  267. if (q->d_ptr->state->WxF) {
  268. q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix;
  269. q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y());
  270. q->d_ptr->state->worldMatrix = QTransform();
  271. q->d_ptr->state->WxF = false;
  272. } else {
  273. q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y());
  274. }
  275. q->d_ptr->updateMatrix();
  276. QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
  277. if (enginePrivate->currentClipWidget == widget) {
  278. enginePrivate->systemStateChanged();
  279. return true;
  280. }
  281. // Update system transform and clip.
  282. enginePrivate->currentClipWidget = widget;
  283. enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
  284. return true;
  285. }
  286. void QPainterPrivate::detachPainterPrivate(QPainter *q)
  287. {
  288. Q_ASSERT(refcount > 1);
  289. Q_ASSERT(q);
  290. QPainterPrivate *original = d_ptrs[--refcount - 1];
  291. if (inDestructor) {
  292. inDestructor = false;
  293. if (original)
  294. original->inDestructor = true;
  295. } else if (!original) {
  296. original = new QPainterPrivate(q);
  297. }
  298. d_ptrs[refcount - 1] = 0;
  299. q->restore();
  300. q->d_ptr.take();
  301. q->d_ptr.reset(original);
  302. if (emulationEngine) {
  303. extended = emulationEngine->real_engine;
  304. delete emulationEngine;
  305. emulationEngine = 0;
  306. }
  307. }
  308. void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperation op)
  309. {
  310. #ifdef QT_DEBUG_DRAW
  311. if (qt_show_painter_debug_output) {
  312. printf("QPainter::drawHelper\n");
  313. }
  314. #endif
  315. if (originalPath.isEmpty())
  316. return;
  317. QPaintEngine::PaintEngineFeatures gradientStretch =
  318. QPaintEngine::PaintEngineFeatures(QGradient_StretchToDevice
  319. | QPaintEngine::ObjectBoundingModeGradients);
  320. const bool mustEmulateObjectBoundingModeGradients = extended
  321. || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
  322. && !engine->hasFeature(QPaintEngine::PatternTransform));
  323. if (!(state->emulationSpecifier & ~gradientStretch)
  324. && !mustEmulateObjectBoundingModeGradients) {
  325. drawStretchedGradient(originalPath, op);
  326. return;
  327. } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) {
  328. drawOpaqueBackground(originalPath, op);
  329. return;
  330. }
  331. Q_Q(QPainter);
  332. qreal strokeOffsetX = 0, strokeOffsetY = 0;
  333. QPainterPath path = originalPath * state->matrix;
  334. QRectF pathBounds = path.boundingRect();
  335. QRectF strokeBounds;
  336. bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
  337. if (doStroke) {
  338. qreal penWidth = state->pen.widthF();
  339. if (penWidth == 0) {
  340. strokeOffsetX = 1;
  341. strokeOffsetY = 1;
  342. } else {
  343. // In case of complex xform
  344. if (state->matrix.type() > QTransform::TxScale) {
  345. QPainterPathStroker stroker;
  346. stroker.setWidth(penWidth);
  347. stroker.setJoinStyle(state->pen.joinStyle());
  348. stroker.setCapStyle(state->pen.capStyle());
  349. QPainterPath stroke = stroker.createStroke(originalPath);
  350. strokeBounds = (stroke * state->matrix).boundingRect();
  351. } else {
  352. strokeOffsetX = qAbs(penWidth * state->matrix.m11() / qreal(2.0));
  353. strokeOffsetY = qAbs(penWidth * state->matrix.m22() / qreal(2.0));
  354. }
  355. }
  356. }
  357. QRect absPathRect;
  358. if (!strokeBounds.isEmpty()) {
  359. absPathRect = strokeBounds.intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
  360. } else {
  361. absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
  362. .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
  363. }
  364. if (q->hasClipping()) {
  365. bool hasPerspectiveTransform = false;
  366. for (int i = 0; i < state->clipInfo.size(); ++i) {
  367. const QPainterClipInfo &info = state->clipInfo.at(i);
  368. if (info.matrix.type() == QTransform::TxProject) {
  369. hasPerspectiveTransform = true;
  370. break;
  371. }
  372. }
  373. // avoid mapping QRegions with perspective transforms
  374. if (!hasPerspectiveTransform) {
  375. // The trick with txinv and invMatrix is done in order to
  376. // avoid transforming the clip to logical coordinates, and
  377. // then back to device coordinates. This is a problem with
  378. // QRegion/QRect based clips, since they use integer
  379. // coordinates and converting to/from logical coordinates will
  380. // lose precision.
  381. bool old_txinv = txinv;
  382. QTransform old_invMatrix = invMatrix;
  383. txinv = true;
  384. invMatrix = QTransform();
  385. QPainterPath clipPath = q->clipPath();
  386. QRectF r = clipPath.boundingRect().intersected(absPathRect);
  387. absPathRect = r.toAlignedRect();
  388. txinv = old_txinv;
  389. invMatrix = old_invMatrix;
  390. }
  391. }
  392. // qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",
  393. // devMinX, devMinY, device->width(), device->height());
  394. // qDebug() << " - matrix" << state->matrix;
  395. // qDebug() << " - originalPath.bounds" << originalPath.boundingRect();
  396. // qDebug() << " - path.bounds" << path.boundingRect();
  397. if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
  398. return;
  399. QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
  400. image.fill(0);
  401. QPainter p(&image);
  402. p.d_ptr->helper_device = helper_device;
  403. p.setOpacity(state->opacity);
  404. p.translate(-absPathRect.x(), -absPathRect.y());
  405. p.setTransform(state->matrix, true);
  406. p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
  407. p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
  408. p.setBackground(state->bgBrush);
  409. p.setBackgroundMode(state->bgMode);
  410. p.setBrushOrigin(state->brushOrigin);
  411. p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
  412. p.setRenderHint(QPainter::SmoothPixmapTransform,
  413. state->renderHints & QPainter::SmoothPixmapTransform);
  414. p.drawPath(originalPath);
  415. #ifndef QT_NO_DEBUG
  416. static bool do_fallback_overlay = qgetenv("QT_PAINT_FALLBACK_OVERLAY").size() > 0;
  417. if (do_fallback_overlay) {
  418. QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
  419. QPainter pt(&block);
  420. pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
  421. pt.drawLine(0, 0, 8, 8);
  422. pt.end();
  423. p.resetTransform();
  424. p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
  425. p.setOpacity(0.5);
  426. p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
  427. }
  428. #endif
  429. p.end();
  430. q->save();
  431. state->matrix = QTransform();
  432. if (extended) {
  433. extended->transformChanged();
  434. } else {
  435. state->dirtyFlags |= QPaintEngine::DirtyTransform;
  436. updateState(state);
  437. }
  438. engine->drawImage(absPathRect,
  439. image,
  440. QRectF(0, 0, absPathRect.width(), absPathRect.height()),
  441. Qt::OrderedDither | Qt::OrderedAlphaDither);
  442. q->restore();
  443. }
  444. void QPainterPrivate::drawOpaqueBackground(const QPainterPath &path, DrawOperation op)
  445. {
  446. Q_Q(QPainter);
  447. q->setBackgroundMode(Qt::TransparentMode);
  448. if (op & FillDraw && state->brush.style() != Qt::NoBrush) {
  449. q->fillPath(path, state->bgBrush.color());
  450. q->fillPath(path, state->brush);
  451. }
  452. if (op & StrokeDraw && state->pen.style() != Qt::NoPen) {
  453. q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width()));
  454. q->strokePath(path, state->pen);
  455. }
  456. q->setBackgroundMode(Qt::OpaqueMode);
  457. }
  458. static inline QBrush stretchGradientToUserSpace(const QBrush &brush, const QRectF &boundingRect)
  459. {
  460. Q_ASSERT(brush.style() >= Qt::LinearGradientPattern
  461. && brush.style() <= Qt::ConicalGradientPattern);
  462. QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
  463. boundingRect.x(), boundingRect.y());
  464. QGradient g = *brush.gradient();
  465. g.setCoordinateMode(QGradient::LogicalMode);
  466. QBrush b(g);
  467. b.setTransform(gradientToUser * b.transform());
  468. return b;
  469. }
  470. void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperation op)
  471. {
  472. Q_Q(QPainter);
  473. const qreal sw = helper_device->width();
  474. const qreal sh = helper_device->height();
  475. bool changedPen = false;
  476. bool changedBrush = false;
  477. bool needsFill = false;
  478. const QPen pen = state->pen;
  479. const QBrush brush = state->brush;
  480. const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
  481. const QGradient::CoordinateMode brushMode = coordinateMode(brush);
  482. QRectF boundingRect;
  483. // Draw the xformed fill if the brush is a stretch gradient.
  484. if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
  485. if (brushMode == QGradient::StretchToDeviceMode) {
  486. q->setPen(Qt::NoPen);
  487. changedPen = pen.style() != Qt::NoPen;
  488. q->scale(sw, sh);
  489. updateState(state);
  490. const qreal isw = 1.0 / sw;
  491. const qreal ish = 1.0 / sh;
  492. QTransform inv(isw, 0, 0, ish, 0, 0);
  493. engine->drawPath(path * inv);
  494. q->scale(isw, ish);
  495. } else {
  496. needsFill = true;
  497. if (brushMode == QGradient::ObjectBoundingMode) {
  498. Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
  499. boundingRect = path.boundingRect();
  500. q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
  501. changedBrush = true;
  502. }
  503. }
  504. }
  505. if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
  506. // Draw the xformed outline if the pen is a stretch gradient.
  507. if (penMode == QGradient::StretchToDeviceMode) {
  508. q->setPen(Qt::NoPen);
  509. changedPen = true;
  510. if (needsFill) {
  511. updateState(state);
  512. engine->drawPath(path);
  513. }
  514. q->scale(sw, sh);
  515. q->setBrush(pen.brush());
  516. changedBrush = true;
  517. updateState(state);
  518. QPainterPathStroker stroker;
  519. stroker.setDashPattern(pen.style());
  520. stroker.setWidth(pen.widthF());
  521. stroker.setJoinStyle(pen.joinStyle());
  522. stroker.setCapStyle(pen.capStyle());
  523. stroker.setMiterLimit(pen.miterLimit());
  524. QPainterPath stroke = stroker.createStroke(path);
  525. const qreal isw = 1.0 / sw;
  526. const qreal ish = 1.0 / sh;
  527. QTransform inv(isw, 0, 0, ish, 0, 0);
  528. engine->drawPath(stroke * inv);
  529. q->scale(isw, ish);
  530. } else {
  531. if (!needsFill && brush.style() != Qt::NoBrush) {
  532. q->setBrush(Qt::NoBrush);
  533. changedBrush = true;
  534. }
  535. if (penMode == QGradient::ObjectBoundingMode) {
  536. Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
  537. // avoid computing the bounding rect twice
  538. if (!needsFill || brushMode != QGradient::ObjectBoundingMode)
  539. boundingRect = path.boundingRect();
  540. QPen p = pen;
  541. p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
  542. q->setPen(p);
  543. changedPen = true;
  544. } else if (changedPen) {
  545. q->setPen(pen);
  546. changedPen = false;
  547. }
  548. updateState(state);
  549. engine->drawPath(path);
  550. }
  551. } else if (needsFill) {
  552. if (pen.style() != Qt::NoPen) {
  553. q->setPen(Qt::NoPen);
  554. changedPen = true;
  555. }
  556. updateState(state);
  557. engine->drawPath(path);
  558. }
  559. if (changedPen)
  560. q->setPen(pen);
  561. if (changedBrush)
  562. q->setBrush(brush);
  563. }
  564. void QPainterPrivate::updateMatrix()
  565. {
  566. state->matrix = state->WxF ? state->worldMatrix : QTransform();
  567. if (state->VxF)
  568. state->matrix *= viewTransform();
  569. txinv = false; // no inverted matrix
  570. state->matrix *= state->redirectionMatrix;
  571. if (extended)
  572. extended->transformChanged();
  573. else
  574. state->dirtyFlags |= QPaintEngine::DirtyTransform;
  575. // printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
  576. // qDebug() << " --- using matrix" << state->matrix << redirection_offset;
  577. }
  578. /*! \internal */
  579. void QPainterPrivate::updateInvMatrix()
  580. {
  581. Q_ASSERT(txinv == false);
  582. txinv = true; // creating inverted matrix
  583. invMatrix = state->matrix.inverted();
  584. }
  585. Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush);
  586. void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
  587. {
  588. bool alpha = false;
  589. bool linearGradient = false;
  590. bool radialGradient = false;
  591. bool extendedRadialGradient = false;
  592. bool conicalGradient = false;
  593. bool patternBrush = false;
  594. bool xform = false;
  595. bool complexXform = false;
  596. bool skip = true;
  597. // Pen and brush properties (we have to check both if one changes because the
  598. // one that's unchanged can still be in a state which requires emulation)
  599. if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
  600. // Check Brush stroke emulation
  601. if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
  602. s->emulationSpecifier |= QPaintEngine::BrushStroke;
  603. else
  604. s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
  605. skip = false;
  606. QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
  607. Qt::BrushStyle brushStyle = qbrush_style(s->brush);
  608. Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
  609. alpha = (penBrushStyle != Qt::NoBrush
  610. && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
  611. && !penBrush.isOpaque())
  612. || (brushStyle != Qt::NoBrush
  613. && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
  614. && !s->brush.isOpaque());
  615. linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
  616. (brushStyle == Qt::LinearGradientPattern));
  617. radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
  618. (brushStyle == Qt::RadialGradientPattern));
  619. extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
  620. conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
  621. (brushStyle == Qt::ConicalGradientPattern));
  622. patternBrush = (((penBrushStyle > Qt::SolidPattern
  623. && penBrushStyle < Qt::LinearGradientPattern)
  624. || penBrushStyle == Qt::TexturePattern) ||
  625. ((brushStyle > Qt::SolidPattern
  626. && brushStyle < Qt::LinearGradientPattern)
  627. || brushStyle == Qt::TexturePattern));
  628. bool penTextureAlpha = false;
  629. if (penBrush.style() == Qt::TexturePattern)
  630. penTextureAlpha = qHasPixmapTexture(penBrush)
  631. ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
  632. : penBrush.textureImage().hasAlphaChannel();
  633. bool brushTextureAlpha = false;
  634. if (s->brush.style() == Qt::TexturePattern) {
  635. brushTextureAlpha = qHasPixmapTexture(s->brush)
  636. ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
  637. : s->brush.textureImage().hasAlphaChannel();
  638. }
  639. if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
  640. || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
  641. && !engine->hasFeature(QPaintEngine::MaskedBrush))
  642. s->emulationSpecifier |= QPaintEngine::MaskedBrush;
  643. else
  644. s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
  645. }
  646. if (s->state() & (QPaintEngine::DirtyHints
  647. | QPaintEngine::DirtyOpacity
  648. | QPaintEngine::DirtyBackgroundMode)) {
  649. skip = false;
  650. }
  651. if (skip)
  652. return;
  653. #if 0
  654. qDebug("QPainterPrivate::updateEmulationSpecifier, state=%p\n"
  655. " - alpha: %d\n"
  656. " - linearGradient: %d\n"
  657. " - radialGradient: %d\n"
  658. " - conicalGradient: %d\n"
  659. " - patternBrush: %d\n"
  660. " - hints: %x\n"
  661. " - xform: %d\n",
  662. s,
  663. alpha,
  664. linearGradient,
  665. radialGradient,
  666. conicalGradient,
  667. patternBrush,
  668. uint(s->renderHints),
  669. xform);
  670. #endif
  671. // XForm properties
  672. if (s->state() & QPaintEngine::DirtyTransform) {
  673. xform = !s->matrix.isIdentity();
  674. complexXform = !s->matrix.isAffine();
  675. } else if (s->matrix.type() >= QTransform::TxTranslate) {
  676. xform = true;
  677. complexXform = !s->matrix.isAffine();
  678. }
  679. const bool brushXform = (!s->brush.transform().type() == QTransform::TxNone);
  680. const bool penXform = (!s->pen.brush().transform().type() == QTransform::TxNone);
  681. const bool patternXform = patternBrush && (xform || brushXform || penXform);
  682. // Check alphablending
  683. if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
  684. s->emulationSpecifier |= QPaintEngine::AlphaBlend;
  685. else
  686. s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
  687. // Linear gradient emulation
  688. if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
  689. s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
  690. else
  691. s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
  692. // Radial gradient emulation
  693. if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
  694. s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
  695. else
  696. s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
  697. // Conical gradient emulation
  698. if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
  699. s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
  700. else
  701. s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
  702. // Pattern brushes
  703. if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
  704. s->emulationSpecifier |= QPaintEngine::PatternBrush;
  705. else
  706. s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
  707. // Pattern XForms
  708. if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
  709. s->emulationSpecifier |= QPaintEngine::PatternTransform;
  710. else
  711. s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
  712. // Primitive XForms
  713. if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
  714. s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
  715. else
  716. s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
  717. // Perspective XForms
  718. if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
  719. s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
  720. else
  721. s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
  722. // Constant opacity
  723. if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
  724. s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
  725. else
  726. s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
  727. bool gradientStretch = false;
  728. bool objectBoundingMode = false;
  729. if (linearGradient || conicalGradient || radialGradient) {
  730. QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
  731. QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
  732. gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
  733. gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
  734. objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode);
  735. objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode);
  736. }
  737. if (gradientStretch)
  738. s->emulationSpecifier |= QGradient_StretchToDevice;
  739. else
  740. s->emulationSpecifier &= ~QGradient_StretchToDevice;
  741. if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
  742. s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
  743. else
  744. s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
  745. // Opaque backgrounds...
  746. if (s->bgMode == Qt::OpaqueMode &&
  747. (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
  748. s->emulationSpecifier |= QPaintEngine_OpaqueBackground;
  749. else
  750. s->emulationSpecifier &= ~QPaintEngine_OpaqueBackground;
  751. #if 0
  752. //won't be correct either way because the device can already have
  753. // something rendered to it in which case subsequent emulation
  754. // on a fully transparent qimage and then blitting the results
  755. // won't produce correct results
  756. // Blend modes
  757. if (state->composition_mode > QPainter::CompositionMode_Xor &&
  758. !engine->hasFeature(QPaintEngine::BlendModes))
  759. s->emulationSpecifier |= QPaintEngine::BlendModes;
  760. else
  761. s->emulationSpecifier &= ~QPaintEngine::BlendModes;
  762. #endif
  763. }
  764. void QPainterPrivate::updateStateImpl(QPainterState *newState)
  765. {
  766. // ### we might have to call QPainter::begin() here...
  767. if (!engine->state) {
  768. engine->state = newState;
  769. engine->setDirty(QPaintEngine::AllDirty);
  770. }
  771. if (engine->state->painter() != newState->painter)
  772. // ### this could break with clip regions vs paths.
  773. engine->setDirty(QPaintEngine::AllDirty);
  774. // Upon restore, revert all changes since last save
  775. else if (engine->state != newState)
  776. newState->dirtyFlags |= QPaintEngine::DirtyFlags(static_cast<QPainterState *>(engine->state)->changeFlags);
  777. // We need to store all changes made so that restore can deal with them
  778. else
  779. newState->changeFlags |= newState->dirtyFlags;
  780. updateEmulationSpecifier(newState);
  781. // Unset potential dirty background mode
  782. newState->dirtyFlags &= ~(QPaintEngine::DirtyBackgroundMode
  783. | QPaintEngine::DirtyBackground);
  784. engine->state = newState;
  785. engine->updateState(*newState);
  786. engine->clearDirty(QPaintEngine::AllDirty);
  787. }
  788. void QPainterPrivate::updateState(QPainterState *newState)
  789. {
  790. if (!newState) {
  791. engine->state = newState;
  792. } else if (newState->state() || engine->state!=newState) {
  793. bool setNonCosmeticPen = (newState->renderHints & QPainter::NonCosmeticDefaultPen)
  794. && newState->pen.widthF() == 0;
  795. if (setNonCosmeticPen) {
  796. // Override the default pen's cosmetic state if the
  797. // NonCosmeticDefaultPen render hint is used.
  798. QPen oldPen = newState->pen;
  799. newState->pen.setWidth(1);
  800. newState->pen.setCosmetic(false);
  801. newState->dirtyFlags |= QPaintEngine::DirtyPen;
  802. updateStateImpl(newState);
  803. // Restore the state pen back to its default to preserve visible
  804. // state.
  805. newState->pen = oldPen;
  806. } else {
  807. updateStateImpl(newState);
  808. }
  809. }
  810. }
  811. /*!
  812. \class QPainter
  813. \brief The QPainter class performs low-level painting on widgets and
  814. other paint devices.
  815. \ingroup painting
  816. \reentrant
  817. QPainter provides highly optimized functions to do most of the
  818. drawing GUI programs require. It can draw everything from simple
  819. lines to complex shapes like pies and chords. It can also draw
  820. aligned text and pixmaps. Normally, it draws in a "natural"
  821. coordinate system, but it can also do view and world
  822. transformation. QPainter can operate on any object that inherits
  823. the QPaintDevice class.
  824. The common use of QPainter is inside a widget's paint event:
  825. Construct and customize (e.g. set the pen or the brush) the
  826. painter. Then draw. Remember to destroy the QPainter object after
  827. drawing. For example:
  828. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 0
  829. The core functionality of QPainter is drawing, but the class also
  830. provide several functions that allows you to customize QPainter's
  831. settings and its rendering quality, and others that enable
  832. clipping. In addition you can control how different shapes are
  833. merged together by specifying the painter's composition mode.
  834. The isActive() function indicates whether the painter is active. A
  835. painter is activated by the begin() function and the constructor
  836. that takes a QPaintDevice argument. The end() function, and the
  837. destructor, deactivates it.
  838. Together with the QPaintDevice and QPaintEngine classes, QPainter
  839. form the basis for Qt's paint system. QPainter is the class used
  840. to perform drawing operations. QPaintDevice represents a device
  841. that can be painted on using a QPainter. QPaintEngine provides the
  842. interface that the painter uses to draw onto different types of
  843. devices. If the painter is active, device() returns the paint
  844. device on which the painter paints, and paintEngine() returns the
  845. paint engine that the painter is currently operating on. For more
  846. information, see the \l {Paint System}.
  847. Sometimes it is desirable to make someone else paint on an unusual
  848. QPaintDevice. QPainter supports a static function to do this,
  849. setRedirected().
  850. \warning When the paintdevice is a widget, QPainter can only be
  851. used inside a paintEvent() function or in a function called by
  852. paintEvent(); that is unless the Qt::WA_PaintOutsidePaintEvent
  853. widget attribute is set. On Mac OS X and Windows, you can only
  854. paint in a paintEvent() function regardless of this attribute's
  855. setting.
  856. \tableofcontents
  857. \section1 Settings
  858. There are several settings that you can customize to make QPainter
  859. draw according to your preferences:
  860. \list
  861. \o font() is the font used for drawing text. If the painter
  862. isActive(), you can retrieve information about the currently set
  863. font, and its metrics, using the fontInfo() and fontMetrics()
  864. functions respectively.
  865. \o brush() defines the color or pattern that is used for filling
  866. shapes.
  867. \o pen() defines the color or stipple that is used for drawing
  868. lines or boundaries.
  869. \o backgroundMode() defines whether there is a background() or
  870. not, i.e it is either Qt::OpaqueMode or Qt::TransparentMode.
  871. \o background() only applies when backgroundMode() is \l
  872. Qt::OpaqueMode and pen() is a stipple. In that case, it
  873. describes the color of the background pixels in the stipple.
  874. \o brushOrigin() defines the origin of the tiled brushes, normally
  875. the origin of widget's background.
  876. \o viewport(), window(), worldTransform() make up the painter's coordinate
  877. transformation system. For more information, see the \l
  878. {Coordinate Transformations} section and the \l {Coordinate
  879. System} documentation.
  880. \o hasClipping() tells whether the painter clips at all. (The paint
  881. device clips, too.) If the painter clips, it clips to clipRegion().
  882. \o layoutDirection() defines the layout direction used by the
  883. painter when drawing text.
  884. \o worldMatrixEnabled() tells whether world transformation is enabled.
  885. \o viewTransformEnabled() tells whether view transformation is
  886. enabled.
  887. \endlist
  888. Note that some of these settings mirror settings in some paint
  889. devices, e.g. QWidget::font(). The QPainter::begin() function (or
  890. equivalently the QPainter constructor) copies these attributes
  891. from the paint device.
  892. You can at any time save the QPainter's state by calling the
  893. save() function which saves all the available settings on an
  894. internal stack. The restore() function pops them back.
  895. \section1 Drawing
  896. QPainter provides functions to draw most primitives: drawPoint(),
  897. drawPoints(), drawLine(), drawRect(), drawRoundedRect(),
  898. drawEllipse(), drawArc(), drawPie(), drawChord(), drawPolyline(),
  899. drawPolygon(), drawConvexPolygon() and drawCubicBezier(). The two
  900. convenience functions, drawRects() and drawLines(), draw the given
  901. number of rectangles or lines in the given array of \l
  902. {QRect}{QRects} or \l {QLine}{QLines} using the current pen and
  903. brush.
  904. The QPainter class also provides the fillRect() function which
  905. fills the given QRect, with the given QBrush, and the eraseRect()
  906. function that erases the area inside the given rectangle.
  907. All of these functions have both integer and floating point
  908. versions.
  909. \table 100%
  910. \row
  911. \o \inlineimage qpainter-basicdrawing.png
  912. \o
  913. \bold {Basic Drawing Example}
  914. The \l {painting/basicdrawing}{Basic Drawing} example shows how to
  915. display basic graphics primitives in a variety of styles using the
  916. QPainter class.
  917. \endtable
  918. If you need to draw a complex shape, especially if you need to do
  919. so repeatedly, consider creating a QPainterPath and drawing it
  920. using drawPath().
  921. \table 100%
  922. \row
  923. \o
  924. \bold {Painter Paths example}
  925. The QPainterPath class provides a container for painting
  926. operations, enabling graphical shapes to be constructed and
  927. reused.
  928. The \l {painting/painterpaths}{Painter Paths} example shows how
  929. painter paths can be used to build complex shapes for rendering.
  930. \o \inlineimage qpainter-painterpaths.png
  931. \endtable
  932. QPainter also provides the fillPath() function which fills the
  933. given QPainterPath with the given QBrush, and the strokePath()
  934. function that draws the outline of the given path (i.e. strokes
  935. the path).
  936. See also the \l {demos/deform}{Vector Deformation} demo which
  937. shows how to use advanced vector techniques to draw text using a
  938. QPainterPath, the \l {demos/gradients}{Gradients} demo which shows
  939. the different types of gradients that are available in Qt, and the \l
  940. {demos/pathstroke}{Path Stroking} demo which shows Qt's built-in
  941. dash patterns and shows how custom patterns can be used to extend
  942. the range of available patterns.
  943. \table
  944. \header
  945. \o \l {demos/deform}{Vector Deformation}
  946. \o \l {demos/gradients}{Gradients}
  947. \o \l {demos/pathstroke}{Path Stroking}
  948. \row
  949. \o \inlineimage qpainter-vectordeformation.png
  950. \o \inlineimage qpainter-gradients.png
  951. \o \inlineimage qpainter-pathstroking.png
  952. \endtable
  953. There are functions to draw pixmaps/images, namely drawPixmap(),
  954. drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
  955. produce the same result, except that drawPixmap() is faster
  956. on-screen while drawImage() may be faster on a QPrinter or other
  957. devices.
  958. Text drawing is done using drawText(). When you need
  959. fine-grained positioning, boundingRect() tells you where a given
  960. drawText() command will draw.
  961. There is a drawPicture() function that draws the contents of an
  962. entire QPicture. The drawPicture() function is the only function
  963. that disregards all the painter's settings as QPicture has its own
  964. settings.
  965. \section1 Rendering Quality
  966. To get the optimal rendering result using QPainter, you should use
  967. the platform independent QImage as paint device; i.e. using QImage
  968. will ensure that the result has an identical pixel representation
  969. on any platform.
  970. The QPainter class also provides a means of controlling the
  971. rendering quality through its RenderHint enum and the support for
  972. floating point precision: All the functions for drawing primitives
  973. has a floating point version. These are often used in combination
  974. with the \l {RenderHint}{QPainter::Antialiasing} render hint.
  975. \table 100%
  976. \row
  977. \o \inlineimage qpainter-concentriccircles.png
  978. \o
  979. \bold {Concentric Circles Example}
  980. The \l {painting/concentriccircles}{Concentric Circles} example
  981. shows the improved rendering quality that can be obtained using
  982. floating point precision and anti-aliasing when drawing custom
  983. widgets.
  984. The application's main window displays several widgets which are
  985. drawn using the various combinations of precision and
  986. anti-aliasing.
  987. \endtable
  988. The RenderHint enum specifies flags to QPainter that may or may
  989. not be respected by any given engine. \l
  990. {RenderHint}{QPainter::Antialiasing} indicates that the engine
  991. should antialias edges of primitives if possible, \l
  992. {RenderHint}{QPainter::TextAntialiasing} indicates that the engine
  993. should antialias text if possible, and the \l
  994. {RenderHint}{QPainter::SmoothPixmapTransform} indicates that the
  995. engine should use a smooth pixmap transformation algorithm.
  996. \l {RenderHint}{HighQualityAntialiasing} is an OpenGL-specific rendering hint
  997. indicating that the engine should use fragment programs and offscreen
  998. rendering for antialiasing.
  999. The renderHints() function returns a flag that specifies the
  1000. rendering hints that are set for this painter. Use the
  1001. setRenderHint() function to set or clear the currently set
  1002. RenderHints.
  1003. \section1 Coordinate Transformations
  1004. Normally, the QPainter operates on the device's own coordinate
  1005. system (usually pixels), but QPainter has good support for
  1006. coordinate transformations.
  1007. \table
  1008. \header
  1009. \o nop \o rotate() \o scale() \o translate()
  1010. \row
  1011. \o \inlineimage qpainter-clock.png
  1012. \o \inlineimage qpainter-rotation.png
  1013. \o \inlineimage qpainter-scale.png
  1014. \o \inlineimage qpainter-translation.png
  1015. \endtable
  1016. The most commonly used transformations are scaling, rotation,
  1017. translation and shearing. Use the scale() function to scale the
  1018. coordinate system by a given offset, the rotate() function to
  1019. rotate it clockwise and translate() to translate it (i.e. adding a
  1020. given offset to the points). You can also twist the coordinate
  1021. system around the origin using the shear() function. See the \l
  1022. {demos/affine}{Affine Transformations} demo for a visualization of
  1023. a sheared coordinate system.
  1024. See also the \l {painting/transformations}{Transformations}
  1025. example which shows how transformations influence the way that
  1026. QPainter renders graphics primitives. In particular it shows how
  1027. the order of transformations affects the result.
  1028. \table 100%
  1029. \row
  1030. \o
  1031. \bold {Affine Transformations Demo}
  1032. The \l {demos/affine}{Affine Transformations} demo show Qt's
  1033. ability to perform affine transformations on painting
  1034. operations. The demo also allows the user to experiment with the
  1035. transformation operations and see the results immediately.
  1036. \o \inlineimage qpainter-affinetransformations.png
  1037. \endtable
  1038. All the tranformation operations operate on the transformation
  1039. worldTransform(). A matrix transforms a point in the plane to another
  1040. point. For more information about the transformation matrix, see
  1041. the \l {Coordinate System} and QTransform documentation.
  1042. The setWorldTransform() function can replace or add to the currently
  1043. set worldTransform(). The resetTransform() function resets any
  1044. transformations that were made using translate(), scale(),
  1045. shear(), rotate(), setWorldTransform(), setViewport() and setWindow()
  1046. functions. The deviceTransform() returns the matrix that transforms
  1047. from logical coordinates to device coordinates of the platform
  1048. dependent paint device. The latter function is only needed when
  1049. using platform painting commands on the platform dependent handle,
  1050. and the platform does not do transformations nativly.
  1051. When drawing with QPainter, we specify points using logical
  1052. coordinates which then are converted into the physical coordinates
  1053. of the paint device. The mapping of the logical coordinates to the
  1054. physical coordinates are handled by QPainter's combinedTransform(), a
  1055. combination of viewport() and window() and worldTransform(). The
  1056. viewport() represents the physical coordinates specifying an
  1057. arbitrary rectangle, the window() describes the same rectangle in
  1058. logical coordinates, and the worldTransform() is identical with the
  1059. transformation matrix.
  1060. See also \l {Coordinate System}
  1061. \section1 Clipping
  1062. QPainter can clip any drawing operation to a rectangle, a region,
  1063. or a vector path. The current clip is available using the
  1064. functions clipRegion() and clipPath(). Whether paths or regions are
  1065. preferred (faster) depends on the underlying paintEngine(). For
  1066. example, the QImage paint engine prefers paths while the X11 paint
  1067. engine prefers regions. Setting a clip is done in the painters
  1068. logical coordinates.
  1069. After QPainter's clipping, the paint device may also clip. For
  1070. example, most widgets clip away the pixels used by child widgets,
  1071. and most printers clip away an area near the edges of the paper.
  1072. This additional clipping is not reflected by the return value of
  1073. clipRegion() or hasClipping().
  1074. \section1 Composition Modes
  1075. \target Composition Modes
  1076. QPainter provides the CompositionMode enum which defines the
  1077. Porter-Duff rules for digital image compositing; it describes a
  1078. model for combining the pixels in one image, the source, with the
  1079. pixels in another image, the destination.
  1080. The two most common forms of composition are \l
  1081. {QPainter::CompositionMode}{Source} and \l
  1082. {QPainter::CompositionMode}{SourceOver}. \l
  1083. {QPainter::CompositionMode}{Source} is used to draw opaque objects
  1084. onto a paint device. In this mode, each pixel in the source
  1085. replaces the corresponding pixel in the destination. In \l
  1086. {QPainter::CompositionMode}{SourceOver} composition mode, the
  1087. source object is transparent and is drawn on top of the
  1088. destination.
  1089. Note that composition transformation operates pixelwise. For that
  1090. reason, there is a difference between using the graphic primitive
  1091. itself and its bounding rectangle: The bounding rect contains
  1092. pixels with alpha == 0 (i.e the pixels surrounding the
  1093. primitive). These pixels will overwrite the other image's pixels,
  1094. affectively clearing those, while the primitive only overwrites
  1095. its own area.
  1096. \table 100%
  1097. \row
  1098. \o \inlineimage qpainter-compositiondemo.png
  1099. \o
  1100. \bold {Composition Modes Demo}
  1101. The \l {demos/composition}{Composition Modes} demo, avaiā€¦

Large files files are truncated, but you can click here to view the full file