PageRenderTime 114ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 2ms

/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
  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, available in
  1102. Qt's demo directory, allows you to experiment with the various
  1103. composition modes and see the results immediately.
  1104. \endtable
  1105. \section1 Limitations
  1106. \target Limitations
  1107. If you are using coordinates with Qt's raster-based paint engine, it is
  1108. important to note that, while coordinates greater than +/- 2\sup 15 can
  1109. be used, any painting performed with coordinates outside this range is not
  1110. guaranteed to be shown; the drawing may be clipped. This is due to the
  1111. use of \c{short int} in the implementation.
  1112. The outlines generated by Qt's stroker are only an approximation when dealing
  1113. with curved shapes. It is in most cases impossible to represent the outline of
  1114. a bezier curve segment using another bezier curve segment, and so Qt approximates
  1115. the curve outlines by using several smaller curves. For performance reasons there
  1116. is a limit to how many curves Qt uses for these outlines, and thus when using
  1117. large pen widths or scales the outline error increases. To generate outlines with
  1118. smaller errors it is possible to use the QPainterPathStroker class, which has the
  1119. setCurveThreshold member function which let's the user specify the error tolerance.
  1120. Another workaround is to convert the paths to polygons first and then draw the
  1121. polygons instead.
  1122. \section1 Performance
  1123. QPainter is a rich framework that allows developers to do a great
  1124. variety of graphical operations, such as gradients, composition
  1125. modes and vector graphics. And QPainter can do this across a
  1126. variety of different hardware and software stacks. Naturally the
  1127. underlying combination of hardware and software has some
  1128. implications for performance, and ensuring that every single
  1129. operation is fast in combination with all the various combinations
  1130. of composition modes, brushes, clipping, transformation, etc, is
  1131. close to an impossible task because of the number of
  1132. permutations. As a compromise we have selected a subset of the
  1133. QPainter API and backends, where performance is guaranteed to be as
  1134. good as we can sensibly get it for the given combination of
  1135. hardware and software.
  1136. The backends we focus on as high-performance engines are:
  1137. \list
  1138. \o Raster - This backend implements all rendering in pure software
  1139. and is always used to render into QImages. For optimal performance
  1140. only use the format types QImage::Format_ARGB32_Premultiplied,
  1141. QImage::Format_RGB32 or QImage::Format_RGB16. Any other format,
  1142. including QImage::Format_ARGB32, has significantly worse
  1143. performance. This engine is also used by default on Windows and on
  1144. QWS. It can be used as default graphics system on any
  1145. OS/hardware/software combination by passing \c {-graphicssystem
  1146. raster} on the command line
  1147. \o OpenGL 2.0 (ES) - This backend is the primary backend for
  1148. hardware accelerated graphics. It can be run on desktop machines
  1149. and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0
  1150. specification. This includes most graphics chips produced in the
  1151. last couple of years. The engine can be enabled by using QPainter
  1152. onto a QGLWidget or by passing \c {-graphicssystem opengl} on the
  1153. command line when the underlying system supports it.
  1154. \o OpenVG - This backend implements the Khronos standard for 2D
  1155. and Vector Graphics. It is primarily for embedded devices with
  1156. hardware support for OpenVG. The engine can be enabled by
  1157. passing \c {-graphicssystem openvg} on the command line when
  1158. the underlying system supports it.
  1159. \endlist
  1160. These operations are:
  1161. \list
  1162. \o Simple transformations, meaning translation and scaling, pluss
  1163. 0, 90, 180, 270 degree rotations.
  1164. \o \c drawPixmap() in combination with simple transformations and
  1165. opacity with non-smooth transformation mode
  1166. (\c QPainter::SmoothPixmapTransform not enabled as a render hint).
  1167. \o Rectangle fills with solid color, two-color linear gradients
  1168. and simple transforms.
  1169. \o Rectangular clipping with simple transformations and intersect
  1170. clip.
  1171. \o Composition Modes \c QPainter::CompositionMode_Source and
  1172. QPainter::CompositionMode_SourceOver
  1173. \o Rounded rectangle filling using solid color and two-color
  1174. linear gradients fills.
  1175. \o 3x3 patched pixmaps, via qDrawBorderPixmap.
  1176. \endlist
  1177. This list gives an indication of which features to safely use in
  1178. an application where performance is critical. For certain setups,
  1179. other operations may be fast too, but before making extensive use
  1180. of them, it is recommended to benchmark and verify them on the
  1181. system where the software will run in the end. There are also
  1182. cases where expensive operations are ok to use, for instance when
  1183. the result is cached in a QPixmap.
  1184. \sa QPaintDevice, QPaintEngine, {QtSvg Module}, {Basic Drawing Example},
  1185. {Drawing Utility Functions}
  1186. */
  1187. /*!
  1188. \enum QPainter::RenderHint
  1189. Renderhints are used to specify flags to QPainter that may or
  1190. may not be respected by any given engine.
  1191. \value Antialiasing Indicates that the engine should antialias
  1192. edges of primitives if possible.
  1193. \value TextAntialiasing Indicates that the engine should antialias
  1194. text if possible. To forcibly disable antialiasing for text, do not
  1195. use this hint. Instead, set QFont::NoAntialias on your font's style
  1196. strategy.
  1197. \value SmoothPixmapTransform Indicates that the engine should use
  1198. a smooth pixmap transformation algorithm (such as bilinear) rather
  1199. than nearest neighbor.
  1200. \value HighQualityAntialiasing An OpenGL-specific rendering hint
  1201. indicating that the engine should use fragment programs and offscreen
  1202. rendering for antialiasing.
  1203. \value NonCosmeticDefaultPen The engine should interpret pens with a width
  1204. of 0 (which otherwise enables QPen::isCosmetic()) as being a non-cosmetic
  1205. pen with a width of 1.
  1206. \sa renderHints(), setRenderHint(), {QPainter#Rendering
  1207. Quality}{Rendering Quality}, {Concentric Circles Example}
  1208. */
  1209. /*!
  1210. Constructs a painter.
  1211. \sa begin(), end()
  1212. */
  1213. QPainter::QPainter()
  1214. : d_ptr(new QPainterPrivate(this))
  1215. {
  1216. }
  1217. /*!
  1218. \fn QPainter::QPainter(QPaintDevice *device)
  1219. Constructs a painter that begins painting the paint \a device
  1220. immediately.
  1221. This constructor is convenient for short-lived painters, e.g. in a
  1222. QWidget::paintEvent() and should be used only once. The
  1223. constructor calls begin() for you and the QPainter destructor
  1224. automatically calls end().
  1225. Here's an example using begin() and end():
  1226. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 1
  1227. The same example using this constructor:
  1228. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 2
  1229. Since the constructor cannot provide feedback when the initialization
  1230. of the painter failed you should rather use begin() and end() to paint
  1231. on external devices, e.g. printers.
  1232. \sa begin(), end()
  1233. */
  1234. QPainter::QPainter(QPaintDevice *pd)
  1235. : d_ptr(0)
  1236. {
  1237. Q_ASSERT(pd != 0);
  1238. if (!QPainterPrivate::attachPainterPrivate(this, pd)) {
  1239. d_ptr.reset(new QPainterPrivate(this));
  1240. begin(pd);
  1241. }
  1242. Q_ASSERT(d_ptr);
  1243. }
  1244. /*!
  1245. Destroys the painter.
  1246. */
  1247. QPainter::~QPainter()
  1248. {
  1249. d_ptr->inDestructor = true;
  1250. QT_TRY {
  1251. if (isActive())
  1252. end();
  1253. else if (d_ptr->refcount > 1)
  1254. d_ptr->detachPainterPrivate(this);
  1255. } QT_CATCH(...) {
  1256. // don't throw anything in the destructor.
  1257. }
  1258. if (d_ptr) {
  1259. // Make sure we haven't messed things up.
  1260. Q_ASSERT(d_ptr->inDestructor);
  1261. d_ptr->inDestructor = false;
  1262. Q_ASSERT(d_ptr->refcount == 1);
  1263. if (d_ptr->d_ptrs)
  1264. free(d_ptr->d_ptrs);
  1265. }
  1266. }
  1267. /*!
  1268. Returns the paint device on which this painter is currently
  1269. painting, or 0 if the painter is not active.
  1270. \sa isActive()
  1271. */
  1272. QPaintDevice *QPainter::device() const
  1273. {
  1274. Q_D(const QPainter);
  1275. if (isActive() && d->engine->d_func()->currentClipWidget)
  1276. return d->engine->d_func()->currentClipWidget;
  1277. return d->original_device;
  1278. }
  1279. /*!
  1280. Returns true if begin() has been called and end() has not yet been
  1281. called; otherwise returns false.
  1282. \sa begin(), QPaintDevice::paintingActive()
  1283. */
  1284. bool QPainter::isActive() const
  1285. {
  1286. Q_D(const QPainter);
  1287. return d->engine;
  1288. }
  1289. /*!
  1290. Initializes the painters pen, background and font to the same as
  1291. the given \a widget. This function is called automatically when the
  1292. painter is opened on a QWidget.
  1293. \sa begin(), {QPainter#Settings}{Settings}
  1294. */
  1295. void QPainter::initFrom(const QWidget *widget)
  1296. {
  1297. Q_ASSERT_X(widget, "QPainter::initFrom(const QWidget *widget)", "Widget cannot be 0");
  1298. Q_D(QPainter);
  1299. if (!d->engine) {
  1300. qWarning("QPainter::initFrom: Painter not active, aborted");
  1301. return;
  1302. }
  1303. const QPalette &pal = widget->palette();
  1304. d->state->pen = QPen(pal.brush(widget->foregroundRole()), 0);
  1305. d->state->bgBrush = pal.brush(widget->backgroundRole());
  1306. d->state->deviceFont = QFont(widget->font(), const_cast<QWidget*> (widget));
  1307. d->state->font = d->state->deviceFont;
  1308. if (d->extended) {
  1309. d->extended->penChanged();
  1310. } else if (d->engine) {
  1311. d->engine->setDirty(QPaintEngine::DirtyPen);
  1312. d->engine->setDirty(QPaintEngine::DirtyBrush);
  1313. d->engine->setDirty(QPaintEngine::DirtyFont);
  1314. }
  1315. }
  1316. /*!
  1317. Saves the current painter state (pushes the state onto a stack). A
  1318. save() must be followed by a corresponding restore(); the end()
  1319. function unwinds the stack.
  1320. \sa restore()
  1321. */
  1322. void QPainter::save()
  1323. {
  1324. #ifdef QT_DEBUG_DRAW
  1325. if (qt_show_painter_debug_output)
  1326. printf("QPainter::save()\n");
  1327. #endif
  1328. Q_D(QPainter);
  1329. if (!d->engine) {
  1330. qWarning("QPainter::save: Painter not active");
  1331. return;
  1332. }
  1333. if (d->extended) {
  1334. d->state = d->extended->createState(d->states.back());
  1335. d->extended->setState(d->state);
  1336. } else {
  1337. d->updateState(d->state);
  1338. d->state = new QPainterState(d->states.back());
  1339. d->engine->state = d->state;
  1340. }
  1341. d->states.push_back(d->state);
  1342. }
  1343. /*!
  1344. Restores the current painter state (pops a saved state off the
  1345. stack).
  1346. \sa save()
  1347. */
  1348. void QPainter::restore()
  1349. {
  1350. #ifdef QT_DEBUG_DRAW
  1351. if (qt_show_painter_debug_output)
  1352. printf("QPainter::restore()\n");
  1353. #endif
  1354. Q_D(QPainter);
  1355. if (d->states.size()<=1) {
  1356. qWarning("QPainter::restore: Unbalanced save/restore");
  1357. return;
  1358. } else if (!d->engine) {
  1359. qWarning("QPainter::restore: Painter not active");
  1360. return;
  1361. }
  1362. QPainterState *tmp = d->state;
  1363. d->states.pop_back();
  1364. d->state = d->states.back();
  1365. d->txinv = false;
  1366. if (d->extended) {
  1367. d->checkEmulation();
  1368. d->extended->setState(d->state);
  1369. delete tmp;
  1370. return;
  1371. }
  1372. // trigger clip update if the clip path/region has changed since
  1373. // last save
  1374. if (!d->state->clipInfo.isEmpty()
  1375. && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
  1376. // reuse the tmp state to avoid any extra allocs...
  1377. tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
  1378. tmp->clipOperation = Qt::NoClip;
  1379. tmp->clipPath = QPainterPath();
  1380. d->engine->updateState(*tmp);
  1381. // replay the list of clip states,
  1382. for (int i=0; i<d->state->clipInfo.size(); ++i) {
  1383. const QPainterClipInfo &info = d->state->clipInfo.at(i);
  1384. tmp->matrix = info.matrix;
  1385. tmp->matrix *= d->state->redirectionMatrix;
  1386. tmp->clipOperation = info.operation;
  1387. if (info.clipType == QPainterClipInfo::RectClip) {
  1388. tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
  1389. tmp->clipRegion = info.rect;
  1390. } else if (info.clipType == QPainterClipInfo::RegionClip) {
  1391. tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
  1392. tmp->clipRegion = info.region;
  1393. } else { // clipType == QPainterClipInfo::PathClip
  1394. tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
  1395. tmp->clipPath = info.path;
  1396. }
  1397. d->engine->updateState(*tmp);
  1398. }
  1399. //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
  1400. d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
  1401. tmp->changeFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
  1402. tmp->changeFlags |= QPaintEngine::DirtyTransform;
  1403. }
  1404. d->updateState(d->state);
  1405. delete tmp;
  1406. }
  1407. /*!
  1408. \fn bool QPainter::begin(QPaintDevice *device)
  1409. Begins painting the paint \a device and returns true if
  1410. successful; otherwise returns false.
  1411. Notice that all painter settings (setPen(), setBrush() etc.) are reset
  1412. to default values when begin() is called.
  1413. The errors that can occur are serious problems, such as these:
  1414. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 3
  1415. Note that most of the time, you can use one of the constructors
  1416. instead of begin(), and that end() is automatically done at
  1417. destruction.
  1418. \warning A paint device can only be painted by one painter at a
  1419. time.
  1420. \warning Painting on a QImage with the format
  1421. QImage::Format_Indexed8 is not supported.
  1422. \sa end(), QPainter()
  1423. */
  1424. static inline void qt_cleanup_painter_state(QPainterPrivate *d)
  1425. {
  1426. d->states.clear();
  1427. delete d->state;
  1428. d->state = 0;
  1429. d->engine = 0;
  1430. d->device = 0;
  1431. }
  1432. bool QPainter::begin(QPaintDevice *pd)
  1433. {
  1434. Q_ASSERT(pd);
  1435. if (pd->painters > 0) {
  1436. qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
  1437. return false;
  1438. }
  1439. if (d_ptr->engine) {
  1440. qWarning("QPainter::begin: Painter already active");
  1441. return false;
  1442. }
  1443. if (QPainterPrivate::attachPainterPrivate(this, pd))
  1444. return true;
  1445. Q_D(QPainter);
  1446. d->helper_device = pd;
  1447. d->original_device = pd;
  1448. QPaintDevice *rpd = 0;
  1449. QPoint redirectionOffset;
  1450. // We know for sure that redirection is broken when the widget is inside
  1451. // its paint event, so it's safe to use our hard-coded redirection. However,
  1452. // there IS one particular case we still need to support, and that's
  1453. // when people call QPainter::setRedirected in the widget's paint event right
  1454. // before any painter is created (or QPainter::begin is called). In that
  1455. // particular case our hard-coded redirection is restored and the redirection
  1456. // is retrieved from QPainter::redirected (as before).
  1457. if (pd->devType() == QInternal::Widget)
  1458. rpd = static_cast<QWidget *>(pd)->d_func()->redirected(&redirectionOffset);
  1459. if (!rpd)
  1460. rpd = redirected(pd, &redirectionOffset);
  1461. if (rpd)
  1462. pd = rpd;
  1463. #ifdef QT_DEBUG_DRAW
  1464. if (qt_show_painter_debug_output)
  1465. printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
  1466. #endif
  1467. if (pd->devType() == QInternal::Pixmap)
  1468. static_cast<QPixmap *>(pd)->detach();
  1469. else if (pd->devType() == QInternal::Image)
  1470. static_cast<QImage *>(pd)->detach();
  1471. d->engine = pd->paintEngine();
  1472. if (!d->engine) {
  1473. qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
  1474. return false;
  1475. }
  1476. d->device = pd;
  1477. d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : 0;
  1478. if (d->emulationEngine)
  1479. d->emulationEngine->real_engine = d->extended;
  1480. // Setup new state...
  1481. Q_ASSERT(!d->state);
  1482. d->state = d->extended ? d->extended->createState(0) : new QPainterState;
  1483. d->state->painter = this;
  1484. d->states.push_back(d->state);
  1485. d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
  1486. d->state->brushOrigin = QPointF();
  1487. // Slip a painter state into the engine before we do any other operations
  1488. if (d->extended)
  1489. d->extended->setState(d->state);
  1490. else
  1491. d->engine->state = d->state;
  1492. switch (pd->devType()) {
  1493. case QInternal::Widget:
  1494. {
  1495. const QWidget *widget = static_cast<const QWidget *>(pd);
  1496. Q_ASSERT(widget);
  1497. const bool paintOutsidePaintEvent = widget->testAttribute(Qt::WA_PaintOutsidePaintEvent);
  1498. const bool inPaintEvent = widget->testAttribute(Qt::WA_WState_InPaintEvent);
  1499. if(!d->engine->hasFeature(QPaintEngine::PaintOutsidePaintEvent)
  1500. && !paintOutsidePaintEvent && !inPaintEvent) {
  1501. qWarning("QPainter::begin: Widget painting can only begin as a "
  1502. "result of a paintEvent");
  1503. qt_cleanup_painter_state(d);
  1504. return false;
  1505. }
  1506. // Adjust offset for alien widgets painting outside the paint event.
  1507. if (!inPaintEvent && paintOutsidePaintEvent && !widget->internalWinId()
  1508. && widget->testAttribute(Qt::WA_WState_Created)) {
  1509. const QPoint offset = widget->mapTo(widget->nativeParentWidget(), QPoint());
  1510. d->state->redirectionMatrix.translate(offset.x(), offset.y());
  1511. }
  1512. break;
  1513. }
  1514. case QInternal::Pixmap:
  1515. {
  1516. QPixmap *pm = static_cast<QPixmap *>(pd);
  1517. Q_ASSERT(pm);
  1518. if (pm->isNull()) {
  1519. qWarning("QPainter::begin: Cannot paint on a null pixmap");
  1520. qt_cleanup_painter_state(d);
  1521. return false;
  1522. }
  1523. if (pm->depth() == 1) {
  1524. d->state->pen = QPen(Qt::color1);
  1525. d->state->brush = QBrush(Qt::color0);
  1526. }
  1527. break;
  1528. }
  1529. case QInternal::Image:
  1530. {
  1531. QImage *img = static_cast<QImage *>(pd);
  1532. Q_ASSERT(img);
  1533. if (img->isNull()) {
  1534. qWarning("QPainter::begin: Cannot paint on a null image");
  1535. qt_cleanup_painter_state(d);
  1536. return false;
  1537. } else if (img->format() == QImage::Format_Indexed8) {
  1538. // Painting on indexed8 images is not supported.
  1539. qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format");
  1540. qt_cleanup_painter_state(d);
  1541. return false;
  1542. }
  1543. if (img->depth() == 1) {
  1544. d->state->pen = QPen(Qt::color1);
  1545. d->state->brush = QBrush(Qt::color0);
  1546. }
  1547. break;
  1548. }
  1549. default:
  1550. break;
  1551. }
  1552. if (d->state->ww == 0) // For compat with 3.x painter defaults
  1553. d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
  1554. d->engine->setPaintDevice(pd);
  1555. bool begun = d->engine->begin(pd);
  1556. if (!begun) {
  1557. qWarning("QPainter::begin(): Returned false");
  1558. if (d->engine->isActive()) {
  1559. end();
  1560. } else {
  1561. qt_cleanup_painter_state(d);
  1562. }
  1563. return false;
  1564. } else {
  1565. d->engine->setActive(begun);
  1566. }
  1567. // Copy painter properties from original paint device,
  1568. // required for QPixmap::grabWidget()
  1569. if (d->original_device->devType() == QInternal::Widget) {
  1570. QWidget *widget = static_cast<QWidget *>(d->original_device);
  1571. initFrom(widget);
  1572. } else {
  1573. d->state->layoutDirection = Qt::LayoutDirectionAuto;
  1574. // make sure we have a font compatible with the paintdevice
  1575. d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
  1576. }
  1577. QRect systemRect = d->engine->systemRect();
  1578. if (!systemRect.isEmpty()) {
  1579. d->state->ww = d->state->vw = systemRect.width();
  1580. d->state->wh = d->state->vh = systemRect.height();
  1581. } else {
  1582. d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
  1583. d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
  1584. }
  1585. const QPoint coordinateOffset = d->engine->coordinateOffset();
  1586. d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
  1587. Q_ASSERT(d->engine->isActive());
  1588. if (!d->state->redirectionMatrix.isIdentity())
  1589. d->updateMatrix();
  1590. Q_ASSERT(d->engine->isActive());
  1591. d->state->renderHints = QPainter::TextAntialiasing;
  1592. ++d->device->painters;
  1593. d->state->emulationSpecifier = 0;
  1594. return true;
  1595. }
  1596. /*!
  1597. Ends painting. Any resources used while painting are released. You
  1598. don't normally need to call this since it is called by the
  1599. destructor.
  1600. Returns true if the painter is no longer active; otherwise returns false.
  1601. \sa begin(), isActive()
  1602. */
  1603. bool QPainter::end()
  1604. {
  1605. #ifdef QT_DEBUG_DRAW
  1606. if (qt_show_painter_debug_output)
  1607. printf("QPainter::end()\n");
  1608. #endif
  1609. Q_D(QPainter);
  1610. if (!d->engine) {
  1611. qWarning("QPainter::end: Painter not active, aborted");
  1612. qt_cleanup_painter_state(d);
  1613. return false;
  1614. }
  1615. if (d->refcount > 1) {
  1616. d->detachPainterPrivate(this);
  1617. return true;
  1618. }
  1619. bool ended = true;
  1620. if (d->engine->isActive()) {
  1621. ended = d->engine->end();
  1622. d->updateState(0);
  1623. --d->device->painters;
  1624. if (d->device->painters == 0) {
  1625. d->engine->setPaintDevice(0);
  1626. d->engine->setActive(false);
  1627. }
  1628. }
  1629. if (d->states.size() > 1) {
  1630. qWarning("QPainter::end: Painter ended with %d saved states",
  1631. d->states.size());
  1632. }
  1633. if (d->engine->autoDestruct()) {
  1634. delete d->engine;
  1635. }
  1636. if (d->emulationEngine) {
  1637. delete d->emulationEngine;
  1638. d->emulationEngine = 0;
  1639. }
  1640. if (d->extended) {
  1641. d->extended = 0;
  1642. }
  1643. qt_cleanup_painter_state(d);
  1644. return ended;
  1645. }
  1646. /*!
  1647. Returns the paint engine that the painter is currently operating
  1648. on if the painter is active; otherwise 0.
  1649. \sa isActive()
  1650. */
  1651. QPaintEngine *QPainter::paintEngine() const
  1652. {
  1653. Q_D(const QPainter);
  1654. return d->engine;
  1655. }
  1656. /*!
  1657. \since 4.6
  1658. Flushes the painting pipeline and prepares for the user issuing commands
  1659. directly to the underlying graphics context. Must be followed by a call to
  1660. endNativePainting().
  1661. Note that only the states the underlying paint engine changes will be reset
  1662. to their respective default states. The states we reset may change from
  1663. release to release. The following states are currently reset in the OpenGL
  1664. 2 engine:
  1665. \list
  1666. \i blending is disabled
  1667. \i the depth, stencil and scissor tests are disabled
  1668. \i the active texture unit is reset to 0
  1669. \i the depth mask, depth function and the clear depth are reset to their
  1670. default values
  1671. \i the stencil mask, stencil operation and stencil function are reset to
  1672. their default values
  1673. \i the current color is reset to solid white
  1674. \endlist
  1675. If, for example, the OpenGL polygon mode is changed by the user inside a
  1676. beginNativePaint()/endNativePainting() block, it will not be reset to the
  1677. default state by endNativePainting(). Here is an example that shows
  1678. intermixing of painter commands and raw OpenGL commands:
  1679. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 21
  1680. \sa endNativePainting()
  1681. */
  1682. void QPainter::beginNativePainting()
  1683. {
  1684. Q_D(QPainter);
  1685. if (!d->engine) {
  1686. qWarning("QPainter::beginNativePainting: Painter not active");
  1687. return;
  1688. }
  1689. if (d->extended)
  1690. d->extended->beginNativePainting();
  1691. }
  1692. /*!
  1693. \since 4.6
  1694. Restores the painter after manually issuing native painting commands. Lets
  1695. the painter restore any native state that it relies on before calling any
  1696. other painter commands.
  1697. \sa beginNativePainting()
  1698. */
  1699. void QPainter::endNativePainting()
  1700. {
  1701. Q_D(const QPainter);
  1702. if (!d->engine) {
  1703. qWarning("QPainter::beginNativePainting: Painter not active");
  1704. return;
  1705. }
  1706. if (d->extended)
  1707. d->extended->endNativePainting();
  1708. else
  1709. d->engine->syncState();
  1710. }
  1711. /*!
  1712. Returns the font metrics for the painter if the painter is
  1713. active. Otherwise, the return value is undefined.
  1714. \sa font(), isActive(), {QPainter#Settings}{Settings}
  1715. */
  1716. QFontMetrics QPainter::fontMetrics() const
  1717. {
  1718. Q_D(const QPainter);
  1719. if (!d->engine) {
  1720. qWarning("QPainter::fontMetrics: Painter not active");
  1721. return QFontMetrics(QFont());
  1722. }
  1723. return QFontMetrics(d->state->font);
  1724. }
  1725. /*!
  1726. Returns the font info for the painter if the painter is
  1727. active. Otherwise, the return value is undefined.
  1728. \sa font(), isActive(), {QPainter#Settings}{Settings}
  1729. */
  1730. QFontInfo QPainter::fontInfo() const
  1731. {
  1732. Q_D(const QPainter);
  1733. if (!d->engine) {
  1734. qWarning("QPainter::fontInfo: Painter not active");
  1735. return QFontInfo(QFont());
  1736. }
  1737. return QFontInfo(d->state->font);
  1738. }
  1739. /*!
  1740. \since 4.2
  1741. Returns the opacity of the painter. The default value is
  1742. 1.
  1743. */
  1744. qreal QPainter::opacity() const
  1745. {
  1746. Q_D(const QPainter);
  1747. if (!d->engine) {
  1748. qWarning("QPainter::opacity: Painter not active");
  1749. return 1.0;
  1750. }
  1751. return d->state->opacity;
  1752. }
  1753. /*!
  1754. \since 4.2
  1755. Sets the opacity of the painter to \a opacity. The value should
  1756. be in the range 0.0 to 1.0, where 0.0 is fully transparent and
  1757. 1.0 is fully opaque.
  1758. Opacity set on the painter will apply to all drawing operations
  1759. individually.
  1760. */
  1761. void QPainter::setOpacity(qreal opacity)
  1762. {
  1763. Q_D(QPainter);
  1764. if (!d->engine) {
  1765. qWarning("QPainter::setOpacity: Painter not active");
  1766. return;
  1767. }
  1768. opacity = qMin(qreal(1), qMax(qreal(0), opacity));
  1769. if (opacity == d->state->opacity)
  1770. return;
  1771. d->state->opacity = opacity;
  1772. if (d->extended)
  1773. d->extended->opacityChanged();
  1774. else
  1775. d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
  1776. }
  1777. /*!
  1778. Returns the currently set brush origin.
  1779. \sa setBrushOrigin(), {QPainter#Settings}{Settings}
  1780. */
  1781. QPoint QPainter::brushOrigin() const
  1782. {
  1783. Q_D(const QPainter);
  1784. if (!d->engine) {
  1785. qWarning("QPainter::brushOrigin: Painter not active");
  1786. return QPoint();
  1787. }
  1788. return QPointF(d->state->brushOrigin).toPoint();
  1789. }
  1790. /*!
  1791. \fn void QPainter::setBrushOrigin(const QPointF &position)
  1792. Sets the brush origin to \a position.
  1793. The brush origin specifies the (0, 0) coordinate of the painter's
  1794. brush.
  1795. Note that while the brushOrigin() was necessary to adopt the
  1796. parent's background for a widget in Qt 3, this is no longer the
  1797. case since the Qt 4 painter doesn't paint the background unless
  1798. you explicitly tell it to do so by setting the widget's \l
  1799. {QWidget::autoFillBackground}{autoFillBackground} property to
  1800. true.
  1801. \sa brushOrigin(), {QPainter#Settings}{Settings}
  1802. */
  1803. void QPainter::setBrushOrigin(const QPointF &p)
  1804. {
  1805. Q_D(QPainter);
  1806. #ifdef QT_DEBUG_DRAW
  1807. if (qt_show_painter_debug_output)
  1808. printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
  1809. #endif
  1810. if (!d->engine) {
  1811. qWarning("QPainter::setBrushOrigin: Painter not active");
  1812. return;
  1813. }
  1814. d->state->brushOrigin = p;
  1815. if (d->extended) {
  1816. d->extended->brushOriginChanged();
  1817. return;
  1818. }
  1819. d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
  1820. }
  1821. /*!
  1822. \fn void QPainter::setBrushOrigin(const QPoint &position)
  1823. \overload
  1824. Sets the brush's origin to the given \a position.
  1825. */
  1826. /*!
  1827. \fn void QPainter::setBrushOrigin(int x, int y)
  1828. \overload
  1829. Sets the brush's origin to point (\a x, \a y).
  1830. */
  1831. /*!
  1832. \enum QPainter::CompositionMode
  1833. Defines the modes supported for digital image compositing.
  1834. Composition modes are used to specify how the pixels in one image,
  1835. the source, are merged with the pixel in another image, the
  1836. destination.
  1837. Please note that the bitwise raster operation modes, denoted with
  1838. a RasterOp prefix, are only natively supported in the X11 and
  1839. raster paint engines. This means that the only way to utilize
  1840. these modes on the Mac is via a QImage. The RasterOp denoted blend
  1841. modes are \e not supported for pens and brushes with alpha
  1842. components. Also, turning on the QPainter::Antialiasing render
  1843. hint will effectively disable the RasterOp modes.
  1844. \image qpainter-compositionmode1.png
  1845. \image qpainter-compositionmode2.png
  1846. The most common type is SourceOver (often referred to as just
  1847. alpha blending) where the source pixel is blended on top of the
  1848. destination pixel in such a way that the alpha component of the
  1849. source defines the translucency of the pixel.
  1850. When the paint device is a QImage, the image format must be set to
  1851. \l {QImage::Format}{Format_ARGB32Premultiplied} or
  1852. \l {QImage::Format}{Format_ARGB32} for the composition modes to have
  1853. any effect. For performance the premultiplied version is the preferred
  1854. format.
  1855. When a composition mode is set it applies to all painting
  1856. operator, pens, brushes, gradients and pixmap/image drawing.
  1857. \value CompositionMode_SourceOver This is the default mode. The
  1858. alpha of the source is used to blend the pixel on top of the
  1859. destination.
  1860. \value CompositionMode_DestinationOver The alpha of the
  1861. destination is used to blend it on top of the source pixels. This
  1862. mode is the inverse of CompositionMode_SourceOver.
  1863. \value CompositionMode_Clear The pixels in the destination are
  1864. cleared (set to fully transparent) independent of the source.
  1865. \value CompositionMode_Source The output is the source
  1866. pixel. (This means a basic copy operation and is identical to
  1867. SourceOver when the source pixel is opaque).
  1868. \value CompositionMode_Destination The output is the destination
  1869. pixel. This means that the blending has no effect. This mode is
  1870. the inverse of CompositionMode_Source.
  1871. \value CompositionMode_SourceIn The output is the source, where
  1872. the alpha is reduced by that of the destination.
  1873. \value CompositionMode_DestinationIn The output is the
  1874. destination, where the alpha is reduced by that of the
  1875. source. This mode is the inverse of CompositionMode_SourceIn.
  1876. \value CompositionMode_SourceOut The output is the source, where
  1877. the alpha is reduced by the inverse of destination.
  1878. \value CompositionMode_DestinationOut The output is the
  1879. destination, where the alpha is reduced by the inverse of the
  1880. source. This mode is the inverse of CompositionMode_SourceOut.
  1881. \value CompositionMode_SourceAtop The source pixel is blended on
  1882. top of the destination, with the alpha of the source pixel reduced
  1883. by the alpha of the destination pixel.
  1884. \value CompositionMode_DestinationAtop The destination pixel is
  1885. blended on top of the source, with the alpha of the destination
  1886. pixel is reduced by the alpha of the destination pixel. This mode
  1887. is the inverse of CompositionMode_SourceAtop.
  1888. \value CompositionMode_Xor The source, whose alpha is reduced with
  1889. the inverse of the destination alpha, is merged with the
  1890. destination, whose alpha is reduced by the inverse of the source
  1891. alpha. CompositionMode_Xor is not the same as the bitwise Xor.
  1892. \value CompositionMode_Plus Both the alpha and color of the source
  1893. and destination pixels are added together.
  1894. \value CompositionMode_Multiply The output is the source color
  1895. multiplied by the destination. Multiplying a color with white
  1896. leaves the color unchanged, while multiplying a color
  1897. with black produces black.
  1898. \value CompositionMode_Screen The source and destination colors
  1899. are inverted and then multiplied. Screening a color with white
  1900. produces white, whereas screening a color with black leaves the
  1901. color unchanged.
  1902. \value CompositionMode_Overlay Multiplies or screens the colors
  1903. depending on the destination color. The destination color is mixed
  1904. with the source color to reflect the lightness or darkness of the
  1905. destination.
  1906. \value CompositionMode_Darken The darker of the source and
  1907. destination colors is selected.
  1908. \value CompositionMode_Lighten The lighter of the source and
  1909. destination colors is selected.
  1910. \value CompositionMode_ColorDodge The destination color is
  1911. brightened to reflect the source color. A black source color
  1912. leaves the destination color unchanged.
  1913. \value CompositionMode_ColorBurn The destination color is darkened
  1914. to reflect the source color. A white source color leaves the
  1915. destination color unchanged.
  1916. \value CompositionMode_HardLight Multiplies or screens the colors
  1917. depending on the source color. A light source color will lighten
  1918. the destination color, whereas a dark source color will darken the
  1919. destination color.
  1920. \value CompositionMode_SoftLight Darkens or lightens the colors
  1921. depending on the source color. Similar to
  1922. CompositionMode_HardLight.
  1923. \value CompositionMode_Difference Subtracts the darker of the
  1924. colors from the lighter. Painting with white inverts the
  1925. destination color, whereas painting with black leaves the
  1926. destination color unchanged.
  1927. \value CompositionMode_Exclusion Similar to
  1928. CompositionMode_Difference, but with a lower contrast. Painting
  1929. with white inverts the destination color, whereas painting with
  1930. black leaves the destination color unchanged.
  1931. \value RasterOp_SourceOrDestination Does a bitwise OR operation on
  1932. the source and destination pixels (src OR dst).
  1933. \value RasterOp_SourceAndDestination Does a bitwise AND operation
  1934. on the source and destination pixels (src AND dst).
  1935. \value RasterOp_SourceXorDestination Does a bitwise XOR operation
  1936. on the source and destination pixels (src XOR dst).
  1937. \value RasterOp_NotSourceAndNotDestination Does a bitwise NOR
  1938. operation on the source and destination pixels ((NOT src) AND (NOT
  1939. dst)).
  1940. \value RasterOp_NotSourceOrNotDestination Does a bitwise NAND
  1941. operation on the source and destination pixels ((NOT src) OR (NOT
  1942. dst)).
  1943. \value RasterOp_NotSourceXorDestination Does a bitwise operation
  1944. where the source pixels are inverted and then XOR'ed with the
  1945. destination ((NOT src) XOR dst).
  1946. \value RasterOp_NotSource Does a bitwise operation where the
  1947. source pixels are inverted (NOT src).
  1948. \value RasterOp_NotSourceAndDestination Does a bitwise operation
  1949. where the source is inverted and then AND'ed with the destination
  1950. ((NOT src) AND dst).
  1951. \value RasterOp_SourceAndNotDestination Does a bitwise operation
  1952. where the source is AND'ed with the inverted destination pixels
  1953. (src AND (NOT dst)).
  1954. \sa compositionMode(), setCompositionMode(), {QPainter#Composition
  1955. Modes}{Composition Modes}, {Image Composition Example}
  1956. */
  1957. /*!
  1958. Sets the composition mode to the given \a mode.
  1959. \warning Only a QPainter operating on a QImage fully supports all
  1960. composition modes. The RasterOp modes are supported for X11 as
  1961. described in compositionMode().
  1962. \sa compositionMode()
  1963. */
  1964. void QPainter::setCompositionMode(CompositionMode mode)
  1965. {
  1966. Q_D(QPainter);
  1967. if (!d->engine) {
  1968. qWarning("QPainter::setCompositionMode: Painter not active");
  1969. return;
  1970. }
  1971. if (d->state->composition_mode == mode)
  1972. return;
  1973. if (d->extended) {
  1974. d->state->composition_mode = mode;
  1975. d->extended->compositionModeChanged();
  1976. return;
  1977. }
  1978. if (mode >= QPainter::RasterOp_SourceOrDestination) {
  1979. if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
  1980. qWarning("QPainter::setCompositionMode: "
  1981. "Raster operation modes not supported on device");
  1982. return;
  1983. }
  1984. } else if (mode >= QPainter::CompositionMode_Plus) {
  1985. if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
  1986. qWarning("QPainter::setCompositionMode: "
  1987. "Blend modes not supported on device");
  1988. return;
  1989. }
  1990. } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
  1991. if (mode != CompositionMode_Source && mode != CompositionMode_SourceOver) {
  1992. qWarning("QPainter::setCompositionMode: "
  1993. "PorterDuff modes not supported on device");
  1994. return;
  1995. }
  1996. }
  1997. d->state->composition_mode = mode;
  1998. d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
  1999. }
  2000. /*!
  2001. Returns the current composition mode.
  2002. \sa CompositionMode, setCompositionMode()
  2003. */
  2004. QPainter::CompositionMode QPainter::compositionMode() const
  2005. {
  2006. Q_D(const QPainter);
  2007. if (!d->engine) {
  2008. qWarning("QPainter::compositionMode: Painter not active");
  2009. return QPainter::CompositionMode_SourceOver;
  2010. }
  2011. return d->state->composition_mode;
  2012. }
  2013. /*!
  2014. Returns the current background brush.
  2015. \sa setBackground(), {QPainter#Settings}{Settings}
  2016. */
  2017. const QBrush &QPainter::background() const
  2018. {
  2019. Q_D(const QPainter);
  2020. if (!d->engine) {
  2021. qWarning("QPainter::background: Painter not active");
  2022. return d->fakeState()->brush;
  2023. }
  2024. return d->state->bgBrush;
  2025. }
  2026. /*!
  2027. Returns true if clipping has been set; otherwise returns false.
  2028. \sa setClipping(), {QPainter#Clipping}{Clipping}
  2029. */
  2030. bool QPainter::hasClipping() const
  2031. {
  2032. Q_D(const QPainter);
  2033. if (!d->engine) {
  2034. qWarning("QPainter::hasClipping: Painter not active");
  2035. return false;
  2036. }
  2037. return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
  2038. }
  2039. /*!
  2040. Enables clipping if \a enable is true, or disables clipping if \a
  2041. enable is false.
  2042. \sa hasClipping(), {QPainter#Clipping}{Clipping}
  2043. */
  2044. void QPainter::setClipping(bool enable)
  2045. {
  2046. Q_D(QPainter);
  2047. #ifdef QT_DEBUG_DRAW
  2048. if (qt_show_painter_debug_output)
  2049. printf("QPainter::setClipping(), enable=%s, was=%s\n",
  2050. enable ? "on" : "off",
  2051. hasClipping() ? "on" : "off");
  2052. #endif
  2053. if (!d->engine) {
  2054. qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
  2055. return;
  2056. }
  2057. if (hasClipping() == enable)
  2058. return;
  2059. // we can't enable clipping if we don't have a clip
  2060. if (enable
  2061. && (d->state->clipInfo.isEmpty() || d->state->clipInfo.last().operation == Qt::NoClip))
  2062. return;
  2063. d->state->clipEnabled = enable;
  2064. if (d->extended) {
  2065. d->extended->clipEnabledChanged();
  2066. return;
  2067. }
  2068. d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
  2069. d->updateState(d->state);
  2070. }
  2071. /*!
  2072. Returns the currently set clip region. Note that the clip region
  2073. is given in logical coordinates.
  2074. \warning QPainter does not store the combined clip explicitly as
  2075. this is handled by the underlying QPaintEngine, so the path is
  2076. recreated on demand and transformed to the current logical
  2077. coordinate system. This is potentially an expensive operation.
  2078. \sa setClipRegion(), clipPath(), setClipping()
  2079. */
  2080. QRegion QPainter::clipRegion() const
  2081. {
  2082. Q_D(const QPainter);
  2083. if (!d->engine) {
  2084. qWarning("QPainter::clipRegion: Painter not active");
  2085. return QRegion();
  2086. }
  2087. QRegion region;
  2088. bool lastWasNothing = true;
  2089. if (!d->txinv)
  2090. const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
  2091. // ### Falcon: Use QPainterPath
  2092. for (int i=0; i<d->state->clipInfo.size(); ++i) {
  2093. const QPainterClipInfo &info = d->state->clipInfo.at(i);
  2094. switch (info.clipType) {
  2095. case QPainterClipInfo::RegionClip: {
  2096. QTransform matrix = (info.matrix * d->invMatrix);
  2097. if (lastWasNothing) {
  2098. region = info.region * matrix;
  2099. lastWasNothing = false;
  2100. continue;
  2101. }
  2102. if (info.operation == Qt::IntersectClip)
  2103. region &= info.region * matrix;
  2104. else if (info.operation == Qt::UniteClip)
  2105. region |= info.region * matrix;
  2106. else if (info.operation == Qt::NoClip) {
  2107. lastWasNothing = true;
  2108. region = QRegion();
  2109. } else
  2110. region = info.region * matrix;
  2111. break;
  2112. }
  2113. case QPainterClipInfo::PathClip: {
  2114. QTransform matrix = (info.matrix * d->invMatrix);
  2115. if (lastWasNothing) {
  2116. region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
  2117. info.path.fillRule());
  2118. lastWasNothing = false;
  2119. continue;
  2120. }
  2121. if (info.operation == Qt::IntersectClip) {
  2122. region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
  2123. info.path.fillRule());
  2124. } else if (info.operation == Qt::UniteClip) {
  2125. region |= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
  2126. info.path.fillRule());
  2127. } else if (info.operation == Qt::NoClip) {
  2128. lastWasNothing = true;
  2129. region = QRegion();
  2130. } else {
  2131. region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
  2132. info.path.fillRule());
  2133. }
  2134. break;
  2135. }
  2136. case QPainterClipInfo::RectClip: {
  2137. QTransform matrix = (info.matrix * d->invMatrix);
  2138. if (lastWasNothing) {
  2139. region = QRegion(info.rect) * matrix;
  2140. lastWasNothing = false;
  2141. continue;
  2142. }
  2143. if (info.operation == Qt::IntersectClip) {
  2144. // Use rect intersection if possible.
  2145. if (matrix.type() <= QTransform::TxScale)
  2146. region &= matrix.mapRect(info.rect);
  2147. else
  2148. region &= matrix.map(QRegion(info.rect));
  2149. } else if (info.operation == Qt::UniteClip) {
  2150. region |= QRegion(info.rect) * matrix;
  2151. } else if (info.operation == Qt::NoClip) {
  2152. lastWasNothing = true;
  2153. region = QRegion();
  2154. } else {
  2155. region = QRegion(info.rect) * matrix;
  2156. }
  2157. break;
  2158. }
  2159. case QPainterClipInfo::RectFClip: {
  2160. QTransform matrix = (info.matrix * d->invMatrix);
  2161. if (lastWasNothing) {
  2162. region = QRegion(info.rectf.toRect()) * matrix;
  2163. lastWasNothing = false;
  2164. continue;
  2165. }
  2166. if (info.operation == Qt::IntersectClip) {
  2167. // Use rect intersection if possible.
  2168. if (matrix.type() <= QTransform::TxScale)
  2169. region &= matrix.mapRect(info.rectf.toRect());
  2170. else
  2171. region &= matrix.map(QRegion(info.rectf.toRect()));
  2172. } else if (info.operation == Qt::UniteClip) {
  2173. region |= QRegion(info.rectf.toRect()) * matrix;
  2174. } else if (info.operation == Qt::NoClip) {
  2175. lastWasNothing = true;
  2176. region = QRegion();
  2177. } else {
  2178. region = QRegion(info.rectf.toRect()) * matrix;
  2179. }
  2180. break;
  2181. }
  2182. }
  2183. }
  2184. return region;
  2185. }
  2186. extern Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion &region);
  2187. /*!
  2188. Returns the currently clip as a path. Note that the clip path is
  2189. given in logical coordinates.
  2190. \warning QPainter does not store the combined clip explicitly as
  2191. this is handled by the underlying QPaintEngine, so the path is
  2192. recreated on demand and transformed to the current logical
  2193. coordinate system. This is potentially an expensive operation.
  2194. \sa setClipPath(), clipRegion(), setClipping()
  2195. */
  2196. QPainterPath QPainter::clipPath() const
  2197. {
  2198. Q_D(const QPainter);
  2199. // ### Since we do not support path intersections and path unions yet,
  2200. // we just use clipRegion() here...
  2201. if (!d->engine) {
  2202. qWarning("QPainter::clipPath: Painter not active");
  2203. return QPainterPath();
  2204. }
  2205. // No clip, return empty
  2206. if (d->state->clipInfo.size() == 0) {
  2207. return QPainterPath();
  2208. } else {
  2209. // Update inverse matrix, used below.
  2210. if (!d->txinv)
  2211. const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
  2212. // For the simple case avoid conversion.
  2213. if (d->state->clipInfo.size() == 1
  2214. && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
  2215. QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
  2216. return d->state->clipInfo.at(0).path * matrix;
  2217. } else if (d->state->clipInfo.size() == 1
  2218. && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
  2219. QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
  2220. QPainterPath path;
  2221. path.addRect(d->state->clipInfo.at(0).rect);
  2222. return path * matrix;
  2223. } else {
  2224. // Fallback to clipRegion() for now, since we don't have isect/unite for paths
  2225. return qt_regionToPath(clipRegion());
  2226. }
  2227. }
  2228. }
  2229. /*!
  2230. Returns the bounding rectangle of the current clip if there is a clip;
  2231. otherwise returns an empty rectangle. Note that the clip region is
  2232. given in logical coordinates.
  2233. The bounding rectangle is not guaranteed to be tight.
  2234. \sa setClipRect(), setClipPath(), setClipRegion()
  2235. \since 4.8
  2236. */
  2237. QRectF QPainter::clipBoundingRect() const
  2238. {
  2239. Q_D(const QPainter);
  2240. if (!d->engine) {
  2241. qWarning("QPainter::clipBoundingRect: Painter not active");
  2242. return QRectF();
  2243. }
  2244. // Accumulate the bounding box in device space. This is not 100%
  2245. // precise, but it fits within the guarantee and it is reasonably
  2246. // fast.
  2247. QRectF bounds;
  2248. for (int i=0; i<d->state->clipInfo.size(); ++i) {
  2249. QRectF r;
  2250. const QPainterClipInfo &info = d->state->clipInfo.at(i);
  2251. if (info.clipType == QPainterClipInfo::RectClip)
  2252. r = info.rect;
  2253. else if (info.clipType == QPainterClipInfo::RectFClip)
  2254. r = info.rectf;
  2255. else if (info.clipType == QPainterClipInfo::RegionClip)
  2256. r = info.region.boundingRect();
  2257. else
  2258. r = info.path.boundingRect();
  2259. r = info.matrix.mapRect(r);
  2260. if (i == 0)
  2261. bounds = r;
  2262. else if (info.operation == Qt::IntersectClip)
  2263. bounds &= r;
  2264. else if (info.operation == Qt::UniteClip)
  2265. bounds |= r;
  2266. }
  2267. // Map the rectangle back into logical space using the inverse
  2268. // matrix.
  2269. if (!d->txinv)
  2270. const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
  2271. return d->invMatrix.mapRect(bounds);
  2272. }
  2273. /*!
  2274. \fn void QPainter::setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
  2275. Enables clipping, and sets the clip region to the given \a
  2276. rectangle using the given clip \a operation. The default operation
  2277. is to replace the current clip rectangle.
  2278. Note that the clip rectangle is specified in logical (painter)
  2279. coordinates.
  2280. \sa clipRegion(), setClipping(), {QPainter#Clipping}{Clipping}
  2281. */
  2282. void QPainter::setClipRect(const QRectF &rect, Qt::ClipOperation op)
  2283. {
  2284. Q_D(QPainter);
  2285. if (d->extended) {
  2286. if ((!d->state->clipEnabled && op != Qt::NoClip) || (d->state->clipOperation == Qt::NoClip && op == Qt::UniteClip))
  2287. op = Qt::ReplaceClip;
  2288. if (!d->engine) {
  2289. qWarning("QPainter::setClipRect: Painter not active");
  2290. return;
  2291. }
  2292. qreal right = rect.x() + rect.width();
  2293. qreal bottom = rect.y() + rect.height();
  2294. qreal pts[] = { rect.x(), rect.y(),
  2295. right, rect.y(),
  2296. right, bottom,
  2297. rect.x(), bottom };
  2298. QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
  2299. d->state->clipEnabled = true;
  2300. d->extended->clip(vp, op);
  2301. if (op == Qt::ReplaceClip || op == Qt::NoClip)
  2302. d->state->clipInfo.clear();
  2303. d->state->clipInfo << QPainterClipInfo(rect, op, d->state->matrix);
  2304. d->state->clipOperation = op;
  2305. return;
  2306. }
  2307. if (qreal(int(rect.top())) == rect.top()
  2308. && qreal(int(rect.bottom())) == rect.bottom()
  2309. && qreal(int(rect.left())) == rect.left()
  2310. && qreal(int(rect.right())) == rect.right())
  2311. {
  2312. setClipRect(rect.toRect(), op);
  2313. return;
  2314. }
  2315. if (rect.isEmpty()) {
  2316. setClipRegion(QRegion(), op);
  2317. return;
  2318. }
  2319. QPainterPath path;
  2320. path.addRect(rect);
  2321. setClipPath(path, op);
  2322. }
  2323. /*!
  2324. \fn void QPainter::setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
  2325. \overload
  2326. Enables clipping, and sets the clip region to the given \a rectangle using the given
  2327. clip \a operation.
  2328. */
  2329. void QPainter::setClipRect(const QRect &rect, Qt::ClipOperation op)
  2330. {
  2331. Q_D(QPainter);
  2332. if (!d->engine) {
  2333. qWarning("QPainter::setClipRect: Painter not active");
  2334. return;
  2335. }
  2336. if ((!d->state->clipEnabled && op != Qt::NoClip) || (d->state->clipOperation == Qt::NoClip && op == Qt::UniteClip))
  2337. op = Qt::ReplaceClip;
  2338. if (d->extended) {
  2339. d->state->clipEnabled = true;
  2340. d->extended->clip(rect, op);
  2341. if (op == Qt::ReplaceClip || op == Qt::NoClip)
  2342. d->state->clipInfo.clear();
  2343. d->state->clipInfo << QPainterClipInfo(rect, op, d->state->matrix);
  2344. d->state->clipOperation = op;
  2345. return;
  2346. }
  2347. if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
  2348. op = Qt::ReplaceClip;
  2349. d->state->clipRegion = rect;
  2350. d->state->clipOperation = op;
  2351. if (op == Qt::NoClip || op == Qt::ReplaceClip)
  2352. d->state->clipInfo.clear();
  2353. d->state->clipInfo << QPainterClipInfo(rect, op, d->state->matrix);
  2354. d->state->clipEnabled = true;
  2355. d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
  2356. d->updateState(d->state);
  2357. }
  2358. /*!
  2359. \fn void QPainter::setClipRect(int x, int y, int width, int height, Qt::ClipOperation operation)
  2360. Enables clipping, and sets the clip region to the rectangle beginning at (\a x, \a y)
  2361. with the given \a width and \a height.
  2362. */
  2363. /*!
  2364. \fn void QPainter::setClipRegion(const QRegion &region, Qt::ClipOperation operation)
  2365. Sets the clip region to the given \a region using the specified clip
  2366. \a operation. The default clip operation is to replace the current
  2367. clip region.
  2368. Note that the clip region is given in logical coordinates.
  2369. \sa clipRegion(), setClipRect(), {QPainter#Clipping}{Clipping}
  2370. */
  2371. void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
  2372. {
  2373. Q_D(QPainter);
  2374. #ifdef QT_DEBUG_DRAW
  2375. QRect rect = r.boundingRect();
  2376. if (qt_show_painter_debug_output)
  2377. printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
  2378. r.rects().size(), rect.x(), rect.y(), rect.width(), rect.height());
  2379. #endif
  2380. if (!d->engine) {
  2381. qWarning("QPainter::setClipRegion: Painter not active");
  2382. return;
  2383. }
  2384. if ((!d->state->clipEnabled && op != Qt::NoClip) || (d->state->clipOperation == Qt::NoClip && op == Qt::UniteClip))
  2385. op = Qt::ReplaceClip;
  2386. if (d->extended) {
  2387. d->state->clipEnabled = true;
  2388. d->extended->clip(r, op);
  2389. if (op == Qt::NoClip || op == Qt::ReplaceClip)
  2390. d->state->clipInfo.clear();
  2391. d->state->clipInfo << QPainterClipInfo(r, op, d->state->matrix);
  2392. d->state->clipOperation = op;
  2393. return;
  2394. }
  2395. if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
  2396. op = Qt::ReplaceClip;
  2397. d->state->clipRegion = r;
  2398. d->state->clipOperation = op;
  2399. if (op == Qt::NoClip || op == Qt::ReplaceClip)
  2400. d->state->clipInfo.clear();
  2401. d->state->clipInfo << QPainterClipInfo(r, op, d->state->matrix);
  2402. d->state->clipEnabled = true;
  2403. d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
  2404. d->updateState(d->state);
  2405. }
  2406. /*!
  2407. \since 4.2
  2408. \obsolete
  2409. Sets the transformation matrix to \a matrix and enables transformations.
  2410. \note It is advisable to use setWorldTransform() instead of this function to
  2411. preserve the properties of perspective transformations.
  2412. If \a combine is true, then \a matrix is combined with the current
  2413. transformation matrix; otherwise \a matrix replaces the current
  2414. transformation matrix.
  2415. If \a matrix is the identity matrix and \a combine is false, this
  2416. function calls setWorldMatrixEnabled(false). (The identity matrix is the
  2417. matrix where QMatrix::m11() and QMatrix::m22() are 1.0 and the
  2418. rest are 0.0.)
  2419. The following functions can transform the coordinate system without using
  2420. a QMatrix:
  2421. \list
  2422. \i translate()
  2423. \i scale()
  2424. \i shear()
  2425. \i rotate()
  2426. \endlist
  2427. They operate on the painter's worldMatrix() and are implemented like this:
  2428. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 4
  2429. Note that when using setWorldMatrix() function you should always have
  2430. \a combine be true when you are drawing into a QPicture. Otherwise
  2431. it may not be possible to replay the picture with additional
  2432. transformations; using the translate(), scale(), etc. convenience
  2433. functions is safe.
  2434. For more information about the coordinate system, transformations
  2435. and window-viewport conversion, see \l {Coordinate System}.
  2436. \sa setWorldTransform(), QTransform
  2437. */
  2438. void QPainter::setWorldMatrix(const QMatrix &matrix, bool combine)
  2439. {
  2440. setWorldTransform(QTransform(matrix), combine);
  2441. }
  2442. /*!
  2443. \since 4.2
  2444. \obsolete
  2445. Returns the world transformation matrix.
  2446. It is advisable to use worldTransform() because worldMatrix() does not
  2447. preserve the properties of perspective transformations.
  2448. \sa {QPainter#Coordinate Transformations}{Coordinate Transformations},
  2449. {Coordinate System}
  2450. */
  2451. const QMatrix &QPainter::worldMatrix() const
  2452. {
  2453. Q_D(const QPainter);
  2454. if (!d->engine) {
  2455. qWarning("QPainter::worldMatrix: Painter not active");
  2456. return d->fakeState()->transform.toAffine();
  2457. }
  2458. return d->state->worldMatrix.toAffine();
  2459. }
  2460. /*!
  2461. \obsolete
  2462. Use setWorldTransform() instead.
  2463. \sa setWorldTransform()
  2464. */
  2465. void QPainter::setMatrix(const QMatrix &matrix, bool combine)
  2466. {
  2467. setWorldTransform(QTransform(matrix), combine);
  2468. }
  2469. /*!
  2470. \obsolete
  2471. Use worldTransform() instead.
  2472. \sa worldTransform()
  2473. */
  2474. const QMatrix &QPainter::matrix() const
  2475. {
  2476. return worldMatrix();
  2477. }
  2478. /*!
  2479. \since 4.2
  2480. \obsolete
  2481. Returns the transformation matrix combining the current
  2482. window/viewport and world transformation.
  2483. It is advisable to use combinedTransform() instead of this
  2484. function to preserve the properties of perspective transformations.
  2485. \sa setWorldTransform(), setWindow(), setViewport()
  2486. */
  2487. QMatrix QPainter::combinedMatrix() const
  2488. {
  2489. return combinedTransform().toAffine();
  2490. }
  2491. /*!
  2492. \obsolete
  2493. Returns the matrix that transforms from logical coordinates to
  2494. device coordinates of the platform dependent paint device.
  2495. \note It is advisable to use deviceTransform() instead of this
  2496. function to preserve the properties of perspective transformations.
  2497. This function is \e only needed when using platform painting
  2498. commands on the platform dependent handle (Qt::HANDLE), and the
  2499. platform does not do transformations nativly.
  2500. The QPaintEngine::PaintEngineFeature enum can be queried to
  2501. determine whether the platform performs the transformations or
  2502. not.
  2503. \sa worldMatrix(), QPaintEngine::hasFeature(),
  2504. */
  2505. const QMatrix &QPainter::deviceMatrix() const
  2506. {
  2507. Q_D(const QPainter);
  2508. if (!d->engine) {
  2509. qWarning("QPainter::deviceMatrix: Painter not active");
  2510. return d->fakeState()->transform.toAffine();
  2511. }
  2512. return d->state->matrix.toAffine();
  2513. }
  2514. /*!
  2515. \obsolete
  2516. Resets any transformations that were made using translate(), scale(),
  2517. shear(), rotate(), setWorldMatrix(), setViewport() and
  2518. setWindow().
  2519. It is advisable to use resetTransform() instead of this function
  2520. to preserve the properties of perspective transformations.
  2521. \sa {QPainter#Coordinate Transformations}{Coordinate
  2522. Transformations}
  2523. */
  2524. void QPainter::resetMatrix()
  2525. {
  2526. resetTransform();
  2527. }
  2528. /*!
  2529. \since 4.2
  2530. Enables transformations if \a enable is true, or disables
  2531. transformations if \a enable is false. The world transformation
  2532. matrix is not changed.
  2533. \sa worldMatrixEnabled(), worldTransform(), {QPainter#Coordinate
  2534. Transformations}{Coordinate Transformations}
  2535. */
  2536. void QPainter::setWorldMatrixEnabled(bool enable)
  2537. {
  2538. Q_D(QPainter);
  2539. #ifdef QT_DEBUG_DRAW
  2540. if (qt_show_painter_debug_output)
  2541. printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
  2542. #endif
  2543. if (!d->engine) {
  2544. qWarning("QPainter::setMatrixEnabled: Painter not active");
  2545. return;
  2546. }
  2547. if (enable == d->state->WxF)
  2548. return;
  2549. d->state->WxF = enable;
  2550. d->updateMatrix();
  2551. }
  2552. /*!
  2553. \since 4.2
  2554. Returns true if world transformation is enabled; otherwise returns
  2555. false.
  2556. \sa setWorldMatrixEnabled(), worldTransform(), {Coordinate System}
  2557. */
  2558. bool QPainter::worldMatrixEnabled() const
  2559. {
  2560. Q_D(const QPainter);
  2561. if (!d->engine) {
  2562. qWarning("QPainter::worldMatrixEnabled: Painter not active");
  2563. return false;
  2564. }
  2565. return d->state->WxF;
  2566. }
  2567. /*!
  2568. \obsolete
  2569. Use setWorldMatrixEnabled() instead.
  2570. \sa setWorldMatrixEnabled()
  2571. */
  2572. void QPainter::setMatrixEnabled(bool enable)
  2573. {
  2574. setWorldMatrixEnabled(enable);
  2575. }
  2576. /*!
  2577. \obsolete
  2578. Use worldMatrixEnabled() instead
  2579. \sa worldMatrixEnabled()
  2580. */
  2581. bool QPainter::matrixEnabled() const
  2582. {
  2583. return worldMatrixEnabled();
  2584. }
  2585. /*!
  2586. Scales the coordinate system by (\a{sx}, \a{sy}).
  2587. \sa setWorldTransform() {QPainter#Coordinate Transformations}{Coordinate
  2588. Transformations}
  2589. */
  2590. void QPainter::scale(qreal sx, qreal sy)
  2591. {
  2592. #ifdef QT_DEBUG_DRAW
  2593. if (qt_show_painter_debug_output)
  2594. printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
  2595. #endif
  2596. Q_D(QPainter);
  2597. if (!d->engine) {
  2598. qWarning("QPainter::scale: Painter not active");
  2599. return;
  2600. }
  2601. d->state->worldMatrix.scale(sx,sy);
  2602. d->state->WxF = true;
  2603. d->updateMatrix();
  2604. }
  2605. /*!
  2606. Shears the coordinate system by (\a{sh}, \a{sv}).
  2607. \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate
  2608. Transformations}
  2609. */
  2610. void QPainter::shear(qreal sh, qreal sv)
  2611. {
  2612. #ifdef QT_DEBUG_DRAW
  2613. if (qt_show_painter_debug_output)
  2614. printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
  2615. #endif
  2616. Q_D(QPainter);
  2617. if (!d->engine) {
  2618. qWarning("QPainter::shear: Painter not active");
  2619. return;
  2620. }
  2621. d->state->worldMatrix.shear(sh, sv);
  2622. d->state->WxF = true;
  2623. d->updateMatrix();
  2624. }
  2625. /*!
  2626. \fn void QPainter::rotate(qreal angle)
  2627. Rotates the coordinate system the given \a angle clockwise.
  2628. \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate
  2629. Transformations}
  2630. */
  2631. void QPainter::rotate(qreal a)
  2632. {
  2633. #ifdef QT_DEBUG_DRAW
  2634. if (qt_show_painter_debug_output)
  2635. printf("QPainter::rotate(), angle=%f\n", a);
  2636. #endif
  2637. Q_D(QPainter);
  2638. if (!d->engine) {
  2639. qWarning("QPainter::rotate: Painter not active");
  2640. return;
  2641. }
  2642. d->state->worldMatrix.rotate(a);
  2643. d->state->WxF = true;
  2644. d->updateMatrix();
  2645. }
  2646. /*!
  2647. Translates the coordinate system by the given \a offset; i.e. the
  2648. given \a offset is added to points.
  2649. \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate
  2650. Transformations}
  2651. */
  2652. void QPainter::translate(const QPointF &offset)
  2653. {
  2654. qreal dx = offset.x();
  2655. qreal dy = offset.y();
  2656. #ifdef QT_DEBUG_DRAW
  2657. if (qt_show_painter_debug_output)
  2658. printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
  2659. #endif
  2660. Q_D(QPainter);
  2661. if (!d->engine) {
  2662. qWarning("QPainter::translate: Painter not active");
  2663. return;
  2664. }
  2665. d->state->worldMatrix.translate(dx, dy);
  2666. d->state->WxF = true;
  2667. d->updateMatrix();
  2668. }
  2669. /*!
  2670. \fn void QPainter::translate(const QPoint &offset)
  2671. \overload
  2672. Translates the coordinate system by the given \a offset.
  2673. */
  2674. /*!
  2675. \fn void QPainter::translate(qreal dx, qreal dy)
  2676. \overload
  2677. Translates the coordinate system by the vector (\a dx, \a dy).
  2678. */
  2679. /*!
  2680. \fn void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
  2681. Enables clipping, and sets the clip path for the painter to the
  2682. given \a path, with the clip \a operation.
  2683. Note that the clip path is specified in logical (painter)
  2684. coordinates.
  2685. \sa clipPath(), clipRegion(), {QPainter#Clipping}{Clipping}
  2686. */
  2687. void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
  2688. {
  2689. #ifdef QT_DEBUG_DRAW
  2690. if (qt_show_painter_debug_output) {
  2691. QRectF b = path.boundingRect();
  2692. printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
  2693. path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
  2694. }
  2695. #endif
  2696. Q_D(QPainter);
  2697. if (!d->engine) {
  2698. qWarning("QPainter::setClipPath: Painter not active");
  2699. return;
  2700. }
  2701. if ((!d->state->clipEnabled && op != Qt::NoClip) || (d->state->clipOperation == Qt::NoClip && op == Qt::UniteClip))
  2702. op = Qt::ReplaceClip;
  2703. if (d->extended) {
  2704. d->state->clipEnabled = true;
  2705. d->extended->clip(path, op);
  2706. if (op == Qt::NoClip || op == Qt::ReplaceClip)
  2707. d->state->clipInfo.clear();
  2708. d->state->clipInfo << QPainterClipInfo(path, op, d->state->matrix);
  2709. d->state->clipOperation = op;
  2710. return;
  2711. }
  2712. if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
  2713. op = Qt::ReplaceClip;
  2714. d->state->clipPath = path;
  2715. d->state->clipOperation = op;
  2716. if (op == Qt::NoClip || op == Qt::ReplaceClip)
  2717. d->state->clipInfo.clear();
  2718. d->state->clipInfo << QPainterClipInfo(path, op, d->state->matrix);
  2719. d->state->clipEnabled = true;
  2720. d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
  2721. d->updateState(d->state);
  2722. }
  2723. /*!
  2724. Draws the outline (strokes) the path \a path with the pen specified
  2725. by \a pen
  2726. \sa fillPath(), {QPainter#Drawing}{Drawing}
  2727. */
  2728. void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
  2729. {
  2730. Q_D(QPainter);
  2731. if (!d->engine) {
  2732. qWarning("QPainter::strokePath: Painter not active");
  2733. return;
  2734. }
  2735. if (path.isEmpty())
  2736. return;
  2737. if (d->extended) {
  2738. const QGradient *g = qpen_brush(pen).gradient();
  2739. if (!g || g->coordinateMode() == QGradient::LogicalMode) {
  2740. d->extended->stroke(qtVectorPathForPath(path), pen);
  2741. return;
  2742. }
  2743. }
  2744. QBrush oldBrush = d->state->brush;
  2745. QPen oldPen = d->state->pen;
  2746. setPen(pen);
  2747. setBrush(Qt::NoBrush);
  2748. drawPath(path);
  2749. // Reset old state
  2750. setPen(oldPen);
  2751. setBrush(oldBrush);
  2752. }
  2753. /*!
  2754. Fills the given \a path using the given \a brush. The outline is
  2755. not drawn.
  2756. Alternatively, you can specify a QColor instead of a QBrush; the
  2757. QBrush constructor (taking a QColor argument) will automatically
  2758. create a solid pattern brush.
  2759. \sa drawPath()
  2760. */
  2761. void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
  2762. {
  2763. Q_D(QPainter);
  2764. if (!d->engine) {
  2765. qWarning("QPainter::fillPath: Painter not active");
  2766. return;
  2767. }
  2768. if (path.isEmpty())
  2769. return;
  2770. if (d->extended) {
  2771. const QGradient *g = brush.gradient();
  2772. if (!g || g->coordinateMode() == QGradient::LogicalMode) {
  2773. d->extended->fill(qtVectorPathForPath(path), brush);
  2774. return;
  2775. }
  2776. }
  2777. QBrush oldBrush = d->state->brush;
  2778. QPen oldPen = d->state->pen;
  2779. setPen(Qt::NoPen);
  2780. setBrush(brush);
  2781. drawPath(path);
  2782. // Reset old state
  2783. setPen(oldPen);
  2784. setBrush(oldBrush);
  2785. }
  2786. /*!
  2787. Draws the given painter \a path using the current pen for outline
  2788. and the current brush for filling.
  2789. \table 100%
  2790. \row
  2791. \o \inlineimage qpainter-path.png
  2792. \o
  2793. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 5
  2794. \endtable
  2795. \sa {painting/painterpaths}{the Painter Paths
  2796. example},{demos/deform}{the Vector Deformation demo}
  2797. */
  2798. void QPainter::drawPath(const QPainterPath &path)
  2799. {
  2800. #ifdef QT_DEBUG_DRAW
  2801. QRectF pathBounds = path.boundingRect();
  2802. if (qt_show_painter_debug_output)
  2803. printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
  2804. path.elementCount(),
  2805. pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
  2806. #endif
  2807. Q_D(QPainter);
  2808. if (!d->engine) {
  2809. qWarning("QPainter::drawPath: Painter not active");
  2810. return;
  2811. }
  2812. if (d->extended) {
  2813. d->extended->drawPath(path);
  2814. return;
  2815. }
  2816. d->updateState(d->state);
  2817. if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
  2818. d->engine->drawPath(path);
  2819. } else {
  2820. d->draw_helper(path);
  2821. }
  2822. }
  2823. /*!
  2824. \fn void QPainter::drawLine(const QLineF &line)
  2825. Draws a line defined by \a line.
  2826. \table 100%
  2827. \row
  2828. \o \inlineimage qpainter-line.png
  2829. \o
  2830. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 6
  2831. \endtable
  2832. \sa drawLines(), drawPolyline(), {Coordinate System}
  2833. */
  2834. /*!
  2835. \fn void QPainter::drawLine(const QLine &line)
  2836. \overload
  2837. Draws a line defined by \a line.
  2838. */
  2839. /*!
  2840. \fn void QPainter::drawLine(const QPoint &p1, const QPoint &p2)
  2841. \overload
  2842. Draws a line from \a p1 to \a p2.
  2843. */
  2844. /*!
  2845. \fn void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
  2846. \overload
  2847. Draws a line from \a p1 to \a p2.
  2848. */
  2849. /*!
  2850. \fn void QPainter::drawLine(int x1, int y1, int x2, int y2)
  2851. \overload
  2852. Draws a line from (\a x1, \a y1) to (\a x2, \a y2) and sets the
  2853. current pen position to (\a x2, \a y2).
  2854. */
  2855. /*!
  2856. \fn void QPainter::drawRect(const QRectF &rectangle)
  2857. Draws the current \a rectangle with the current pen and brush.
  2858. A filled rectangle has a size of \a{rectangle}.size(). A stroked
  2859. rectangle has a size of \a{rectangle}.size() plus the pen width.
  2860. \table 100%
  2861. \row
  2862. \o \inlineimage qpainter-rectangle.png
  2863. \o
  2864. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 7
  2865. \endtable
  2866. \sa drawRects(), drawPolygon(), {Coordinate System}
  2867. */
  2868. /*!
  2869. \fn void QPainter::drawRect(const QRect &rectangle)
  2870. \overload
  2871. Draws the current \a rectangle with the current pen and brush.
  2872. */
  2873. /*!
  2874. \fn void QPainter::drawRect(int x, int y, int width, int height)
  2875. \overload
  2876. Draws a rectangle with upper left corner at (\a{x}, \a{y}) and
  2877. with the given \a width and \a height.
  2878. */
  2879. /*!
  2880. \fn void QPainter::drawRects(const QRectF *rectangles, int rectCount)
  2881. Draws the first \a rectCount of the given \a rectangles using the
  2882. current pen and brush.
  2883. \sa drawRect()
  2884. */
  2885. void QPainter::drawRects(const QRectF *rects, int rectCount)
  2886. {
  2887. #ifdef QT_DEBUG_DRAW
  2888. if (qt_show_painter_debug_output)
  2889. printf("QPainter::drawRects(), count=%d\n", rectCount);
  2890. #endif
  2891. Q_D(QPainter);
  2892. if (!d->engine) {
  2893. qWarning("QPainter::drawRects: Painter not active");
  2894. return;
  2895. }
  2896. if (rectCount <= 0)
  2897. return;
  2898. if (d->extended) {
  2899. d->extended->drawRects(rects, rectCount);
  2900. return;
  2901. }
  2902. d->updateState(d->state);
  2903. if (!d->state->emulationSpecifier) {
  2904. d->engine->drawRects(rects, rectCount);
  2905. return;
  2906. }
  2907. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  2908. && d->state->matrix.type() == QTransform::TxTranslate) {
  2909. for (int i=0; i<rectCount; ++i) {
  2910. QRectF r(rects[i].x() + d->state->matrix.dx(),
  2911. rects[i].y() + d->state->matrix.dy(),
  2912. rects[i].width(),
  2913. rects[i].height());
  2914. d->engine->drawRects(&r, 1);
  2915. }
  2916. } else {
  2917. if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
  2918. for (int i=0; i<rectCount; ++i) {
  2919. QPainterPath rectPath;
  2920. rectPath.addRect(rects[i]);
  2921. d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
  2922. }
  2923. } else {
  2924. QPainterPath rectPath;
  2925. for (int i=0; i<rectCount; ++i)
  2926. rectPath.addRect(rects[i]);
  2927. d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
  2928. }
  2929. }
  2930. }
  2931. /*!
  2932. \fn void QPainter::drawRects(const QRect *rectangles, int rectCount)
  2933. \overload
  2934. Draws the first \a rectCount of the given \a rectangles using the
  2935. current pen and brush.
  2936. */
  2937. void QPainter::drawRects(const QRect *rects, int rectCount)
  2938. {
  2939. #ifdef QT_DEBUG_DRAW
  2940. if (qt_show_painter_debug_output)
  2941. printf("QPainter::drawRects(), count=%d\n", rectCount);
  2942. #endif
  2943. Q_D(QPainter);
  2944. if (!d->engine) {
  2945. qWarning("QPainter::drawRects: Painter not active");
  2946. return;
  2947. }
  2948. if (rectCount <= 0)
  2949. return;
  2950. if (d->extended) {
  2951. d->extended->drawRects(rects, rectCount);
  2952. return;
  2953. }
  2954. d->updateState(d->state);
  2955. if (!d->state->emulationSpecifier) {
  2956. d->engine->drawRects(rects, rectCount);
  2957. return;
  2958. }
  2959. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  2960. && d->state->matrix.type() == QTransform::TxTranslate) {
  2961. for (int i=0; i<rectCount; ++i) {
  2962. QRectF r(rects[i].x() + d->state->matrix.dx(),
  2963. rects[i].y() + d->state->matrix.dy(),
  2964. rects[i].width(),
  2965. rects[i].height());
  2966. d->engine->drawRects(&r, 1);
  2967. }
  2968. } else {
  2969. if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
  2970. for (int i=0; i<rectCount; ++i) {
  2971. QPainterPath rectPath;
  2972. rectPath.addRect(rects[i]);
  2973. d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
  2974. }
  2975. } else {
  2976. QPainterPath rectPath;
  2977. for (int i=0; i<rectCount; ++i)
  2978. rectPath.addRect(rects[i]);
  2979. d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
  2980. }
  2981. }
  2982. }
  2983. /*!
  2984. \fn void QPainter::drawRects(const QVector<QRectF> &rectangles)
  2985. \overload
  2986. Draws the given \a rectangles using the current pen and brush.
  2987. */
  2988. /*!
  2989. \fn void QPainter::drawRects(const QVector<QRect> &rectangles)
  2990. \overload
  2991. Draws the given \a rectangles using the current pen and brush.
  2992. */
  2993. /*!
  2994. \fn void QPainter::drawPoint(const QPointF &position)
  2995. Draws a single point at the given \a position using the current
  2996. pen's color.
  2997. \sa {Coordinate System}
  2998. */
  2999. /*!
  3000. \fn void QPainter::drawPoint(const QPoint &position)
  3001. \overload
  3002. Draws a single point at the given \a position using the current
  3003. pen's color.
  3004. */
  3005. /*! \fn void QPainter::drawPoint(int x, int y)
  3006. \overload
  3007. Draws a single point at position (\a x, \a y).
  3008. */
  3009. /*!
  3010. Draws the first \a pointCount points in the array \a points using
  3011. the current pen's color.
  3012. \sa {Coordinate System}
  3013. */
  3014. void QPainter::drawPoints(const QPointF *points, int pointCount)
  3015. {
  3016. #ifdef QT_DEBUG_DRAW
  3017. if (qt_show_painter_debug_output)
  3018. printf("QPainter::drawPoints(), count=%d\n", pointCount);
  3019. #endif
  3020. Q_D(QPainter);
  3021. if (!d->engine) {
  3022. qWarning("QPainter::drawPoints: Painter not active");
  3023. return;
  3024. }
  3025. if (pointCount <= 0)
  3026. return;
  3027. if (d->extended) {
  3028. d->extended->drawPoints(points, pointCount);
  3029. return;
  3030. }
  3031. d->updateState(d->state);
  3032. if (!d->state->emulationSpecifier) {
  3033. d->engine->drawPoints(points, pointCount);
  3034. return;
  3035. }
  3036. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  3037. && d->state->matrix.type() == QTransform::TxTranslate) {
  3038. // ### use drawPoints function
  3039. for (int i=0; i<pointCount; ++i) {
  3040. QPointF pt(points[i].x() + d->state->matrix.dx(),
  3041. points[i].y() + d->state->matrix.dy());
  3042. d->engine->drawPoints(&pt, 1);
  3043. }
  3044. } else {
  3045. QPen pen = d->state->pen;
  3046. bool flat_pen = pen.capStyle() == Qt::FlatCap;
  3047. if (flat_pen) {
  3048. save();
  3049. pen.setCapStyle(Qt::SquareCap);
  3050. setPen(pen);
  3051. }
  3052. QPainterPath path;
  3053. for (int i=0; i<pointCount; ++i) {
  3054. path.moveTo(points[i].x(), points[i].y());
  3055. path.lineTo(points[i].x() + 0.0001, points[i].y());
  3056. }
  3057. d->draw_helper(path, QPainterPrivate::StrokeDraw);
  3058. if (flat_pen)
  3059. restore();
  3060. }
  3061. }
  3062. /*!
  3063. \overload
  3064. Draws the first \a pointCount points in the array \a points using
  3065. the current pen's color.
  3066. */
  3067. void QPainter::drawPoints(const QPoint *points, int pointCount)
  3068. {
  3069. #ifdef QT_DEBUG_DRAW
  3070. if (qt_show_painter_debug_output)
  3071. printf("QPainter::drawPoints(), count=%d\n", pointCount);
  3072. #endif
  3073. Q_D(QPainter);
  3074. if (!d->engine) {
  3075. qWarning("QPainter::drawPoints: Painter not active");
  3076. return;
  3077. }
  3078. if (pointCount <= 0)
  3079. return;
  3080. if (d->extended) {
  3081. d->extended->drawPoints(points, pointCount);
  3082. return;
  3083. }
  3084. d->updateState(d->state);
  3085. if (!d->state->emulationSpecifier) {
  3086. d->engine->drawPoints(points, pointCount);
  3087. return;
  3088. }
  3089. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  3090. && d->state->matrix.type() == QTransform::TxTranslate) {
  3091. // ### use drawPoints function
  3092. for (int i=0; i<pointCount; ++i) {
  3093. QPointF pt(points[i].x() + d->state->matrix.dx(),
  3094. points[i].y() + d->state->matrix.dy());
  3095. d->engine->drawPoints(&pt, 1);
  3096. }
  3097. } else {
  3098. QPen pen = d->state->pen;
  3099. bool flat_pen = (pen.capStyle() == Qt::FlatCap);
  3100. if (flat_pen) {
  3101. save();
  3102. pen.setCapStyle(Qt::SquareCap);
  3103. setPen(pen);
  3104. }
  3105. QPainterPath path;
  3106. for (int i=0; i<pointCount; ++i) {
  3107. path.moveTo(points[i].x(), points[i].y());
  3108. path.lineTo(points[i].x() + 0.0001, points[i].y());
  3109. }
  3110. d->draw_helper(path, QPainterPrivate::StrokeDraw);
  3111. if (flat_pen)
  3112. restore();
  3113. }
  3114. }
  3115. /*!
  3116. \fn void QPainter::drawPoints(const QPolygonF &points)
  3117. \overload
  3118. Draws the points in the vector \a points.
  3119. */
  3120. /*!
  3121. \fn void QPainter::drawPoints(const QPolygon &points)
  3122. \overload
  3123. Draws the points in the vector \a points.
  3124. */
  3125. /*!
  3126. \fn void QPainter::drawPoints(const QPolygon &polygon, int index,
  3127. int count)
  3128. \overload
  3129. \compat
  3130. Draws \a count points in the vector \a polygon starting on \a index
  3131. using the current pen.
  3132. Use drawPoints() combined with QPolygon::constData() instead.
  3133. \oldcode
  3134. QPainter painter(this);
  3135. painter.drawPoints(polygon, index, count);
  3136. \newcode
  3137. int pointCount = (count == -1) ? polygon.size() - index : count;
  3138. QPainter painter(this);
  3139. painter.drawPoints(polygon.constData() + index, pointCount);
  3140. \endcode
  3141. */
  3142. /*!
  3143. Sets the background mode of the painter to the given \a mode
  3144. Qt::TransparentMode (the default) draws stippled lines and text
  3145. without setting the background pixels. Qt::OpaqueMode fills these
  3146. space with the current background color.
  3147. Note that in order to draw a bitmap or pixmap transparently, you
  3148. must use QPixmap::setMask().
  3149. \sa backgroundMode(), setBackground(),
  3150. {QPainter#Settings}{Settings}
  3151. */
  3152. void QPainter::setBackgroundMode(Qt::BGMode mode)
  3153. {
  3154. #ifdef QT_DEBUG_DRAW
  3155. if (qt_show_painter_debug_output)
  3156. printf("QPainter::setBackgroundMode(), mode=%d\n", mode);
  3157. #endif
  3158. Q_D(QPainter);
  3159. if (!d->engine) {
  3160. qWarning("QPainter::setBackgroundMode: Painter not active");
  3161. return;
  3162. }
  3163. if (d->state->bgMode == mode)
  3164. return;
  3165. d->state->bgMode = mode;
  3166. if (d->extended) {
  3167. d->checkEmulation();
  3168. } else {
  3169. d->state->dirtyFlags |= QPaintEngine::DirtyBackgroundMode;
  3170. }
  3171. }
  3172. /*!
  3173. Returns the current background mode.
  3174. \sa setBackgroundMode(), {QPainter#Settings}{Settings}
  3175. */
  3176. Qt::BGMode QPainter::backgroundMode() const
  3177. {
  3178. Q_D(const QPainter);
  3179. if (!d->engine) {
  3180. qWarning("QPainter::backgroundMode: Painter not active");
  3181. return Qt::TransparentMode;
  3182. }
  3183. return d->state->bgMode;
  3184. }
  3185. /*!
  3186. \overload
  3187. Sets the painter's pen to have style Qt::SolidLine, width 0 and the
  3188. specified \a color.
  3189. */
  3190. void QPainter::setPen(const QColor &color)
  3191. {
  3192. #ifdef QT_DEBUG_DRAW
  3193. if (qt_show_painter_debug_output)
  3194. printf("QPainter::setPen(), color=%04x\n", color.rgb());
  3195. #endif
  3196. Q_D(QPainter);
  3197. if (!d->engine) {
  3198. qWarning("QPainter::setPen: Painter not active");
  3199. return;
  3200. }
  3201. if (d->state->pen.style() == Qt::SolidLine
  3202. && d->state->pen.widthF() == 0
  3203. && d->state->pen.isSolid()
  3204. && d->state->pen.color() == color)
  3205. return;
  3206. QPen pen(color.isValid() ? color : QColor(Qt::black), 0, Qt::SolidLine);
  3207. d->state->pen = pen;
  3208. if (d->extended)
  3209. d->extended->penChanged();
  3210. else
  3211. d->state->dirtyFlags |= QPaintEngine::DirtyPen;
  3212. }
  3213. /*!
  3214. Sets the painter's pen to be the given \a pen.
  3215. The \a pen defines how to draw lines and outlines, and it also
  3216. defines the text color.
  3217. \sa pen(), {QPainter#Settings}{Settings}
  3218. */
  3219. void QPainter::setPen(const QPen &pen)
  3220. {
  3221. #ifdef QT_DEBUG_DRAW
  3222. if (qt_show_painter_debug_output)
  3223. printf("QPainter::setPen(), color=%04x, (brushStyle=%d) style=%d, cap=%d, join=%d\n",
  3224. pen.color().rgb(), pen.brush().style(), pen.style(), pen.capStyle(), pen.joinStyle());
  3225. #endif
  3226. Q_D(QPainter);
  3227. if (!d->engine) {
  3228. qWarning("QPainter::setPen: Painter not active");
  3229. return;
  3230. }
  3231. if (d->state->pen == pen)
  3232. return;
  3233. d->state->pen = pen;
  3234. if (d->extended) {
  3235. d->checkEmulation();
  3236. d->extended->penChanged();
  3237. return;
  3238. }
  3239. d->state->dirtyFlags |= QPaintEngine::DirtyPen;
  3240. }
  3241. /*!
  3242. \overload
  3243. Sets the painter's pen to have the given \a style, width 0 and
  3244. black color.
  3245. */
  3246. void QPainter::setPen(Qt::PenStyle style)
  3247. {
  3248. Q_D(QPainter);
  3249. if (!d->engine) {
  3250. qWarning("QPainter::setPen: Painter not active");
  3251. return;
  3252. }
  3253. if (d->state->pen.style() == style
  3254. && (style == Qt::NoPen || (d->state->pen.widthF() == 0
  3255. && d->state->pen.isSolid()
  3256. && d->state->pen.color() == QColor(Qt::black))))
  3257. return;
  3258. // QPen(Qt::NoPen) is to avoid creating QPenData, including its brush (from the color)
  3259. // Note that this works well as long as QPen(Qt::NoPen) returns a black, zero-width pen
  3260. d->state->pen = (style == Qt::NoPen) ? QPen(Qt::NoPen) : QPen(Qt::black, 0, style);
  3261. if (d->extended)
  3262. d->extended->penChanged();
  3263. else
  3264. d->state->dirtyFlags |= QPaintEngine::DirtyPen;
  3265. }
  3266. /*!
  3267. Returns the painter's current pen.
  3268. \sa setPen(), {QPainter#Settings}{Settings}
  3269. */
  3270. const QPen &QPainter::pen() const
  3271. {
  3272. Q_D(const QPainter);
  3273. if (!d->engine) {
  3274. qWarning("QPainter::pen: Painter not active");
  3275. return d->fakeState()->pen;
  3276. }
  3277. return d->state->pen;
  3278. }
  3279. /*!
  3280. Sets the painter's brush to the given \a brush.
  3281. The painter's brush defines how shapes are filled.
  3282. \sa brush(), {QPainter#Settings}{Settings}
  3283. */
  3284. void QPainter::setBrush(const QBrush &brush)
  3285. {
  3286. #ifdef QT_DEBUG_DRAW
  3287. if (qt_show_painter_debug_output)
  3288. printf("QPainter::setBrush(), color=%04x, style=%d\n", brush.color().rgb(), brush.style());
  3289. #endif
  3290. Q_D(QPainter);
  3291. if (!d->engine) {
  3292. qWarning("QPainter::setBrush: Painter not active");
  3293. return;
  3294. }
  3295. if (d->state->brush.d == brush.d)
  3296. return;
  3297. if (d->extended) {
  3298. d->state->brush = brush;
  3299. d->checkEmulation();
  3300. d->extended->brushChanged();
  3301. return;
  3302. }
  3303. d->state->brush = brush;
  3304. d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
  3305. }
  3306. /*!
  3307. \overload
  3308. Sets the painter's brush to black color and the specified \a
  3309. style.
  3310. */
  3311. void QPainter::setBrush(Qt::BrushStyle style)
  3312. {
  3313. Q_D(QPainter);
  3314. if (!d->engine) {
  3315. qWarning("QPainter::setBrush: Painter not active");
  3316. return;
  3317. }
  3318. if (d->state->brush.style() == style &&
  3319. (style == Qt::NoBrush
  3320. || (style == Qt::SolidPattern && d->state->brush.color() == QColor(0, 0, 0))))
  3321. return;
  3322. d->state->brush = QBrush(Qt::black, style);
  3323. if (d->extended)
  3324. d->extended->brushChanged();
  3325. else
  3326. d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
  3327. }
  3328. /*!
  3329. Returns the painter's current brush.
  3330. \sa QPainter::setBrush(), {QPainter#Settings}{Settings}
  3331. */
  3332. const QBrush &QPainter::brush() const
  3333. {
  3334. Q_D(const QPainter);
  3335. if (!d->engine) {
  3336. qWarning("QPainter::brush: Painter not active");
  3337. return d->fakeState()->brush;
  3338. }
  3339. return d->state->brush;
  3340. }
  3341. /*!
  3342. \fn void QPainter::setBackground(const QBrush &brush)
  3343. Sets the background brush of the painter to the given \a brush.
  3344. The background brush is the brush that is filled in when drawing
  3345. opaque text, stippled lines and bitmaps. The background brush has
  3346. no effect in transparent background mode (which is the default).
  3347. \sa background(), setBackgroundMode(),
  3348. {QPainter#Settings}{Settings}
  3349. */
  3350. void QPainter::setBackground(const QBrush &bg)
  3351. {
  3352. #ifdef QT_DEBUG_DRAW
  3353. if (qt_show_painter_debug_output)
  3354. printf("QPainter::setBackground(), color=%04x, style=%d\n", bg.color().rgb(), bg.style());
  3355. #endif
  3356. Q_D(QPainter);
  3357. if (!d->engine) {
  3358. qWarning("QPainter::setBackground: Painter not active");
  3359. return;
  3360. }
  3361. d->state->bgBrush = bg;
  3362. if (!d->extended)
  3363. d->state->dirtyFlags |= QPaintEngine::DirtyBackground;
  3364. }
  3365. /*!
  3366. Sets the painter's font to the given \a font.
  3367. This font is used by subsequent drawText() functions. The text
  3368. color is the same as the pen color.
  3369. If you set a font that isn't available, Qt finds a close match.
  3370. font() will return what you set using setFont() and fontInfo() returns the
  3371. font actually being used (which may be the same).
  3372. \sa font(), drawText(), {QPainter#Settings}{Settings}
  3373. */
  3374. void QPainter::setFont(const QFont &font)
  3375. {
  3376. Q_D(QPainter);
  3377. #ifdef QT_DEBUG_DRAW
  3378. if (qt_show_painter_debug_output)
  3379. printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.family().toLatin1().constData(), font.pointSize());
  3380. #endif
  3381. if (!d->engine) {
  3382. qWarning("QPainter::setFont: Painter not active");
  3383. return;
  3384. }
  3385. d->state->font = QFont(font.resolve(d->state->deviceFont), device());
  3386. if (!d->extended)
  3387. d->state->dirtyFlags |= QPaintEngine::DirtyFont;
  3388. }
  3389. /*!
  3390. Returns the currently set font used for drawing text.
  3391. \sa setFont(), drawText(), {QPainter#Settings}{Settings}
  3392. */
  3393. const QFont &QPainter::font() const
  3394. {
  3395. Q_D(const QPainter);
  3396. if (!d->engine) {
  3397. qWarning("QPainter::font: Painter not active");
  3398. return d->fakeState()->font;
  3399. }
  3400. return d->state->font;
  3401. }
  3402. /*!
  3403. \since 4.4
  3404. Draws the given rectangle \a rect with rounded corners.
  3405. The \a xRadius and \a yRadius arguments specify the radii
  3406. of the ellipses defining the corners of the rounded rectangle.
  3407. When \a mode is Qt::RelativeSize, \a xRadius and
  3408. \a yRadius are specified in percentage of half the rectangle's
  3409. width and height respectively, and should be in the range
  3410. 0.0 to 100.0.
  3411. A filled rectangle has a size of rect.size(). A stroked rectangle
  3412. has a size of rect.size() plus the pen width.
  3413. \table 100%
  3414. \row
  3415. \o \inlineimage qpainter-roundrect.png
  3416. \o
  3417. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 8
  3418. \endtable
  3419. \sa drawRect(), QPen
  3420. */
  3421. void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
  3422. {
  3423. #ifdef QT_DEBUG_DRAW
  3424. if (qt_show_painter_debug_output)
  3425. printf("QPainter::drawRoundedRect(), [%.2f,%.2f,%.2f,%.2f]\n", rect.x(), rect.y(), rect.width(), rect.height());
  3426. #endif
  3427. Q_D(QPainter);
  3428. if (!d->engine)
  3429. return;
  3430. if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
  3431. drawRect(rect);
  3432. return;
  3433. }
  3434. if (d->extended) {
  3435. d->extended->drawRoundedRect(rect, xRadius, yRadius, mode);
  3436. return;
  3437. }
  3438. QPainterPath path;
  3439. path.addRoundedRect(rect, xRadius, yRadius, mode);
  3440. drawPath(path);
  3441. }
  3442. /*!
  3443. \fn void QPainter::drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius,
  3444. Qt::SizeMode mode = Qt::AbsoluteSize);
  3445. \since 4.4
  3446. \overload
  3447. Draws the given rectangle \a rect with rounded corners.
  3448. */
  3449. /*!
  3450. \fn void QPainter::drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius,
  3451. Qt::SizeMode mode = Qt::AbsoluteSize);
  3452. \since 4.4
  3453. \overload
  3454. Draws the given rectangle \a x, \a y, \a w, \a h with rounded corners.
  3455. */
  3456. /*!
  3457. \obsolete
  3458. Draws a rectangle \a r with rounded corners.
  3459. The \a xRnd and \a yRnd arguments specify how rounded the corners
  3460. should be. 0 is angled corners, 99 is maximum roundedness.
  3461. A filled rectangle has a size of r.size(). A stroked rectangle
  3462. has a size of r.size() plus the pen width.
  3463. \sa drawRoundedRect()
  3464. */
  3465. void QPainter::drawRoundRect(const QRectF &r, int xRnd, int yRnd)
  3466. {
  3467. drawRoundedRect(r, xRnd, yRnd, Qt::RelativeSize);
  3468. }
  3469. /*!
  3470. \fn void QPainter::drawRoundRect(const QRect &r, int xRnd = 25, int yRnd = 25)
  3471. \overload
  3472. \obsolete
  3473. Draws the rectangle \a r with rounded corners.
  3474. */
  3475. /*!
  3476. \obsolete
  3477. \fn QPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd)
  3478. \overload
  3479. Draws the rectangle \a x, \a y, \a w, \a h with rounded corners.
  3480. */
  3481. /*!
  3482. \fn void QPainter::drawEllipse(const QRectF &rectangle)
  3483. Draws the ellipse defined by the given \a rectangle.
  3484. A filled ellipse has a size of \a{rectangle}.\l
  3485. {QRect::size()}{size()}. A stroked ellipse has a size of
  3486. \a{rectangle}.\l {QRect::size()}{size()} plus the pen width.
  3487. \table 100%
  3488. \row
  3489. \o \inlineimage qpainter-ellipse.png
  3490. \o
  3491. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 9
  3492. \endtable
  3493. \sa drawPie(), {Coordinate System}
  3494. */
  3495. void QPainter::drawEllipse(const QRectF &r)
  3496. {
  3497. #ifdef QT_DEBUG_DRAW
  3498. if (qt_show_painter_debug_output)
  3499. printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
  3500. #endif
  3501. Q_D(QPainter);
  3502. if (!d->engine)
  3503. return;
  3504. QRectF rect(r.normalized());
  3505. if (d->extended) {
  3506. d->extended->drawEllipse(rect);
  3507. return;
  3508. }
  3509. d->updateState(d->state);
  3510. if (d->state->emulationSpecifier) {
  3511. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  3512. && d->state->matrix.type() == QTransform::TxTranslate) {
  3513. rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
  3514. } else {
  3515. QPainterPath path;
  3516. path.addEllipse(rect);
  3517. d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
  3518. return;
  3519. }
  3520. }
  3521. d->engine->drawEllipse(rect);
  3522. }
  3523. /*!
  3524. \fn QPainter::drawEllipse(const QRect &rectangle)
  3525. \overload
  3526. Draws the ellipse defined by the given \a rectangle.
  3527. */
  3528. void QPainter::drawEllipse(const QRect &r)
  3529. {
  3530. #ifdef QT_DEBUG_DRAW
  3531. if (qt_show_painter_debug_output)
  3532. printf("QPainter::drawEllipse(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
  3533. #endif
  3534. Q_D(QPainter);
  3535. if (!d->engine)
  3536. return;
  3537. QRect rect(r.normalized());
  3538. if (d->extended) {
  3539. d->extended->drawEllipse(rect);
  3540. return;
  3541. }
  3542. d->updateState(d->state);
  3543. if (d->state->emulationSpecifier) {
  3544. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  3545. && d->state->matrix.type() == QTransform::TxTranslate) {
  3546. rect.translate(QPoint(qRound(d->state->matrix.dx()), qRound(d->state->matrix.dy())));
  3547. } else {
  3548. QPainterPath path;
  3549. path.addEllipse(rect);
  3550. d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
  3551. return;
  3552. }
  3553. }
  3554. d->engine->drawEllipse(rect);
  3555. }
  3556. /*!
  3557. \fn QPainter::drawEllipse(int x, int y, int width, int height)
  3558. \overload
  3559. Draws the ellipse defined by the rectangle beginning at (\a{x},
  3560. \a{y}) with the given \a width and \a height.
  3561. */
  3562. /*!
  3563. \since 4.4
  3564. \fn QPainter::drawEllipse(const QPointF &center, qreal rx, qreal ry)
  3565. \overload
  3566. Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
  3567. */
  3568. /*!
  3569. \since 4.4
  3570. \fn QPainter::drawEllipse(const QPoint &center, int rx, int ry)
  3571. \overload
  3572. Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
  3573. */
  3574. /*!
  3575. \fn void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
  3576. Draws the arc defined by the given \a rectangle, \a startAngle and
  3577. \a spanAngle.
  3578. The \a startAngle and \a spanAngle must be specified in 1/16th of
  3579. a degree, i.e. a full circle equals 5760 (16 * 360). Positive
  3580. values for the angles mean counter-clockwise while negative values
  3581. mean the clockwise direction. Zero degrees is at the 3 o'clock
  3582. position.
  3583. \table 100%
  3584. \row
  3585. \o \inlineimage qpainter-arc.png
  3586. \o
  3587. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 10
  3588. \endtable
  3589. \sa drawPie(), drawChord(), {Coordinate System}
  3590. */
  3591. void QPainter::drawArc(const QRectF &r, int a, int alen)
  3592. {
  3593. #ifdef QT_DEBUG_DRAW
  3594. if (qt_show_painter_debug_output)
  3595. printf("QPainter::drawArc(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
  3596. r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
  3597. #endif
  3598. Q_D(QPainter);
  3599. if (!d->engine)
  3600. return;
  3601. QRectF rect = r.normalized();
  3602. QPainterPath path;
  3603. path.arcMoveTo(rect, a/qreal(16.0));
  3604. path.arcTo(rect, a/qreal(16.0), alen/qreal(16.0));
  3605. strokePath(path, d->state->pen);
  3606. }
  3607. /*! \fn void QPainter::drawArc(const QRect &rectangle, int startAngle,
  3608. int spanAngle)
  3609. \overload
  3610. Draws the arc defined by the given \a rectangle, \a startAngle and
  3611. \a spanAngle.
  3612. */
  3613. /*!
  3614. \fn void QPainter::drawArc(int x, int y, int width, int height,
  3615. int startAngle, int spanAngle)
  3616. \overload
  3617. Draws the arc defined by the rectangle beginning at (\a x, \a y)
  3618. with the specified \a width and \a height, and the given \a
  3619. startAngle and \a spanAngle.
  3620. */
  3621. /*!
  3622. \fn void QPainter::drawPie(const QRectF &rectangle, int startAngle, int spanAngle)
  3623. Draws a pie defined by the given \a rectangle, \a startAngle and
  3624. and \a spanAngle.
  3625. The pie is filled with the current brush().
  3626. The startAngle and spanAngle must be specified in 1/16th of a
  3627. degree, i.e. a full circle equals 5760 (16 * 360). Positive values
  3628. for the angles mean counter-clockwise while negative values mean
  3629. the clockwise direction. Zero degrees is at the 3 o'clock
  3630. position.
  3631. \table 100%
  3632. \row
  3633. \o \inlineimage qpainter-pie.png
  3634. \o
  3635. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 11
  3636. \endtable
  3637. \sa drawEllipse(), drawChord(), {Coordinate System}
  3638. */
  3639. void QPainter::drawPie(const QRectF &r, int a, int alen)
  3640. {
  3641. #ifdef QT_DEBUG_DRAW
  3642. if (qt_show_painter_debug_output)
  3643. printf("QPainter::drawPie(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
  3644. r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
  3645. #endif
  3646. Q_D(QPainter);
  3647. if (!d->engine)
  3648. return;
  3649. if (a > (360*16)) {
  3650. a = a % (360*16);
  3651. } else if (a < 0) {
  3652. a = a % (360*16);
  3653. if (a < 0) a += (360*16);
  3654. }
  3655. QRectF rect = r.normalized();
  3656. QPainterPath path;
  3657. path.moveTo(rect.center());
  3658. path.arcTo(rect.x(), rect.y(), rect.width(), rect.height(), a/qreal(16.0), alen/qreal(16.0));
  3659. path.closeSubpath();
  3660. drawPath(path);
  3661. }
  3662. /*!
  3663. \fn void QPainter::drawPie(const QRect &rectangle, int startAngle, int spanAngle)
  3664. \overload
  3665. Draws a pie defined by the given \a rectangle, \a startAngle and
  3666. and \a spanAngle.
  3667. */
  3668. /*!
  3669. \fn void QPainter::drawPie(int x, int y, int width, int height, int
  3670. startAngle, int spanAngle)
  3671. \overload
  3672. Draws the pie defined by the rectangle beginning at (\a x, \a y) with
  3673. the specified \a width and \a height, and the given \a startAngle and
  3674. \a spanAngle.
  3675. */
  3676. /*!
  3677. \fn void QPainter::drawChord(const QRectF &rectangle, int startAngle, int spanAngle)
  3678. Draws the chord defined by the given \a rectangle, \a startAngle and
  3679. \a spanAngle. The chord is filled with the current brush().
  3680. The startAngle and spanAngle must be specified in 1/16th of a
  3681. degree, i.e. a full circle equals 5760 (16 * 360). Positive values
  3682. for the angles mean counter-clockwise while negative values mean
  3683. the clockwise direction. Zero degrees is at the 3 o'clock
  3684. position.
  3685. \table 100%
  3686. \row
  3687. \o \inlineimage qpainter-chord.png
  3688. \o
  3689. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 12
  3690. \endtable
  3691. \sa drawArc(), drawPie(), {Coordinate System}
  3692. */
  3693. void QPainter::drawChord(const QRectF &r, int a, int alen)
  3694. {
  3695. #ifdef QT_DEBUG_DRAW
  3696. if (qt_show_painter_debug_output)
  3697. printf("QPainter::drawChord(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
  3698. r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
  3699. #endif
  3700. Q_D(QPainter);
  3701. if (!d->engine)
  3702. return;
  3703. QRectF rect = r.normalized();
  3704. QPainterPath path;
  3705. path.arcMoveTo(rect, a/qreal(16.0));
  3706. path.arcTo(rect, a/qreal(16.0), alen/qreal(16.0));
  3707. path.closeSubpath();
  3708. drawPath(path);
  3709. }
  3710. /*!
  3711. \fn void QPainter::drawChord(const QRect &rectangle, int startAngle, int spanAngle)
  3712. \overload
  3713. Draws the chord defined by the given \a rectangle, \a startAngle and
  3714. \a spanAngle.
  3715. */
  3716. /*!
  3717. \fn void QPainter::drawChord(int x, int y, int width, int height, int
  3718. startAngle, int spanAngle)
  3719. \overload
  3720. Draws the chord defined by the rectangle beginning at (\a x, \a y)
  3721. with the specified \a width and \a height, and the given \a
  3722. startAngle and \a spanAngle.
  3723. */
  3724. #ifdef QT3_SUPPORT
  3725. /*!
  3726. \fn void QPainter::drawLineSegments(const QPolygon &polygon, int
  3727. index, int count)
  3728. Draws \a count separate lines from points defined by the \a
  3729. polygon, starting at \a{polygon}\e{[index]} (\a index defaults to
  3730. 0). If \a count is -1 (the default) all points until the end of
  3731. the array are used.
  3732. Use drawLines() combined with QPolygon::constData() instead.
  3733. \oldcode
  3734. QPainter painter(this);
  3735. painter.drawLineSegments(polygon, index, count);
  3736. \newcode
  3737. int lineCount = (count == -1) ? (polygon.size() - index) / 2 : count;
  3738. QPainter painter(this);
  3739. painter.drawLines(polygon.constData() + index * 2, lineCount);
  3740. \endcode
  3741. */
  3742. void QPainter::drawLineSegments(const QPolygon &a, int index, int nlines)
  3743. {
  3744. #ifdef QT_DEBUG_DRAW
  3745. if (qt_show_painter_debug_output)
  3746. printf("QPainter::drawLineSegments(), count=%d\n", a.size()/2);
  3747. #endif
  3748. Q_D(QPainter);
  3749. if (!d->engine)
  3750. return;
  3751. if (nlines < 0)
  3752. nlines = a.size()/2 - index/2;
  3753. if (index + nlines*2 > (int)a.size())
  3754. nlines = (a.size() - index)/2;
  3755. if (nlines < 1 || index < 0)
  3756. return;
  3757. if (d->extended) {
  3758. // FALCON: Use QVectorPath
  3759. QVector<QLineF> lines;
  3760. for (int i=index; i<index + nlines*2; i+=2)
  3761. lines << QLineF(a.at(i), a.at(i+1));
  3762. d->extended->drawLines(lines.data(), lines.size());
  3763. return;
  3764. }
  3765. d->updateState(d->state);
  3766. QVector<QLineF> lines;
  3767. if (d->state->emulationSpecifier) {
  3768. if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
  3769. && d->state->matrix.type() == QTransform::TxTranslate) {
  3770. QPointF offset(d->state->matrix.dx(), d->state->matrix.dy());
  3771. for (int i=index; i<index + nlines*2; i+=2)
  3772. lines << QLineF(a.at(i) + offset, a.at(i+1) + offset);
  3773. } else {
  3774. QPainterPath linesPath;
  3775. for (int i=index; i<index + nlines*2; i+=2) {
  3776. linesPath.moveTo(a.at(i));
  3777. linesPath.lineTo(a.at(i+1));
  3778. }
  3779. d->draw_helper(linesPath, QPainterPrivate::StrokeDraw);
  3780. return;
  3781. }
  3782. } else {
  3783. for (int i=index; i<index + nlines*2; i+=2)
  3784. lines << QLineF(a.at(i), a.at(i+1));
  3785. }
  3786. d->engine->drawLines(lines.data(), lines.size());
  3787. }
  3788. #endif // QT3_SUPPORT
  3789. /*!
  3790. Draws the first \a lineCount lines in the array \a lines
  3791. using the current pen.
  3792. \sa drawLine(), drawPolyline()
  3793. */
  3794. void QPainter::drawLines(const QLineF *lines, int lineCount)
  3795. {
  3796. #ifdef QT_DEBUG_DRAW
  3797. if (qt_show_painter_debug_output)
  3798. printf("QPainter::drawLines(), line count=%d\n", lineCount);
  3799. #endif
  3800. Q_D(QPainter);
  3801. if (!d->engine || lineCount < 1)
  3802. return;
  3803. if (d->extended) {
  3804. d->extended->drawLines(lines, lineCount);
  3805. return;
  3806. }
  3807. d->updateState(d->state);
  3808. uint lineEmulation = line_emulation(d->state->emulationSpecifier);
  3809. if (lineEmulation) {
  3810. if (lineEmulation == QPaintEngine::PrimitiveTransform
  3811. && d->state->matrix.type() == QTransform::TxTranslate) {
  3812. for (int i = 0; i < lineCount; ++i) {
  3813. QLineF line = lines[i];
  3814. line.translate(d->state->matrix.dx(), d->state->matrix.dy());
  3815. d->engine->drawLines(&line, 1);
  3816. }
  3817. } else {
  3818. QPainterPath linePath;
  3819. for (int i = 0; i < lineCount; ++i) {
  3820. linePath.moveTo(lines[i].p1());
  3821. linePath.lineTo(lines[i].p2());
  3822. }
  3823. d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
  3824. }
  3825. return;
  3826. }
  3827. d->engine->drawLines(lines, lineCount);
  3828. }
  3829. /*!
  3830. \fn void QPainter::drawLines(const QLine *lines, int lineCount)
  3831. \overload
  3832. Draws the first \a lineCount lines in the array \a lines
  3833. using the current pen.
  3834. */
  3835. void QPainter::drawLines(const QLine *lines, int lineCount)
  3836. {
  3837. #ifdef QT_DEBUG_DRAW
  3838. if (qt_show_painter_debug_output)
  3839. printf("QPainter::drawLine(), line count=%d\n", lineCount);
  3840. #endif
  3841. Q_D(QPainter);
  3842. if (!d->engine || lineCount < 1)
  3843. return;
  3844. if (d->extended) {
  3845. d->extended->drawLines(lines, lineCount);
  3846. return;
  3847. }
  3848. d->updateState(d->state);
  3849. uint lineEmulation = line_emulation(d->state->emulationSpecifier);
  3850. if (lineEmulation) {
  3851. if (lineEmulation == QPaintEngine::PrimitiveTransform
  3852. && d->state->matrix.type() == QTransform::TxTranslate) {
  3853. for (int i = 0; i < lineCount; ++i) {
  3854. QLineF line = lines[i];
  3855. line.translate(d->state->matrix.dx(), d->state->matrix.dy());
  3856. d->engine->drawLines(&line, 1);
  3857. }
  3858. } else {
  3859. QPainterPath linePath;
  3860. for (int i = 0; i < lineCount; ++i) {
  3861. linePath.moveTo(lines[i].p1());
  3862. linePath.lineTo(lines[i].p2());
  3863. }
  3864. d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
  3865. }
  3866. return;
  3867. }
  3868. d->engine->drawLines(lines, lineCount);
  3869. }
  3870. /*!
  3871. \overload
  3872. Draws the first \a lineCount lines in the array \a pointPairs
  3873. using the current pen. The lines are specified as pairs of points
  3874. so the number of entries in \a pointPairs must be at least \a
  3875. lineCount * 2.
  3876. */
  3877. void QPainter::drawLines(const QPointF *pointPairs, int lineCount)
  3878. {
  3879. Q_ASSERT(sizeof(QLineF) == 2*sizeof(QPointF));
  3880. drawLines((QLineF*)pointPairs, lineCount);
  3881. }
  3882. /*!
  3883. \overload
  3884. Draws the first \a lineCount lines in the array \a pointPairs
  3885. using the current pen.
  3886. */
  3887. void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
  3888. {
  3889. Q_ASSERT(sizeof(QLine) == 2*sizeof(QPoint));
  3890. drawLines((QLine*)pointPairs, lineCount);
  3891. }
  3892. /*!
  3893. \fn void QPainter::drawLines(const QVector<QPointF> &pointPairs)
  3894. \overload
  3895. Draws a line for each pair of points in the vector \a pointPairs
  3896. using the current pen. If there is an odd number of points in the
  3897. array, the last point will be ignored.
  3898. */
  3899. /*!
  3900. \fn void QPainter::drawLines(const QVector<QPoint> &pointPairs)
  3901. \overload
  3902. Draws a line for each pair of points in the vector \a pointPairs
  3903. using the current pen.
  3904. */
  3905. /*!
  3906. \fn void QPainter::drawLines(const QVector<QLineF> &lines)
  3907. \overload
  3908. Draws the set of lines defined by the list \a lines using the
  3909. current pen and brush.
  3910. */
  3911. /*!
  3912. \fn void QPainter::drawLines(const QVector<QLine> &lines)
  3913. \overload
  3914. Draws the set of lines defined by the list \a lines using the
  3915. current pen and brush.
  3916. */
  3917. /*!
  3918. Draws the polyline defined by the first \a pointCount points in \a
  3919. points using the current pen.
  3920. Note that unlike the drawPolygon() function the last point is \e
  3921. not connected to the first, neither is the polyline filled.
  3922. \table 100%
  3923. \row
  3924. \o
  3925. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 13
  3926. \endtable
  3927. \sa drawLines(), drawPolygon(), {Coordinate System}
  3928. */
  3929. void QPainter::drawPolyline(const QPointF *points, int pointCount)
  3930. {
  3931. #ifdef QT_DEBUG_DRAW
  3932. if (qt_show_painter_debug_output)
  3933. printf("QPainter::drawPolyline(), count=%d\n", pointCount);
  3934. #endif
  3935. Q_D(QPainter);
  3936. if (!d->engine || pointCount < 2)
  3937. return;
  3938. if (d->extended) {
  3939. d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
  3940. return;
  3941. }
  3942. d->updateState(d->state);
  3943. uint lineEmulation = line_emulation(d->state->emulationSpecifier);
  3944. if (lineEmulation) {
  3945. // ###
  3946. // if (lineEmulation == QPaintEngine::PrimitiveTransform
  3947. // && d->state->matrix.type() == QTransform::TxTranslate) {
  3948. // } else {
  3949. QPainterPath polylinePath(points[0]);
  3950. for (int i=1; i<pointCount; ++i)
  3951. polylinePath.lineTo(points[i]);
  3952. d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
  3953. // }
  3954. } else {
  3955. d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
  3956. }
  3957. }
  3958. /*!
  3959. \overload
  3960. Draws the polyline defined by the first \a pointCount points in \a
  3961. points using the current pen.
  3962. */
  3963. void QPainter::drawPolyline(const QPoint *points, int pointCount)
  3964. {
  3965. #ifdef QT_DEBUG_DRAW
  3966. if (qt_show_painter_debug_output)
  3967. printf("QPainter::drawPolyline(), count=%d\n", pointCount);
  3968. #endif
  3969. Q_D(QPainter);
  3970. if (!d->engine || pointCount < 2)
  3971. return;
  3972. if (d->extended) {
  3973. d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
  3974. return;
  3975. }
  3976. d->updateState(d->state);
  3977. uint lineEmulation = line_emulation(d->state->emulationSpecifier);
  3978. if (lineEmulation) {
  3979. // ###
  3980. // if (lineEmulation == QPaintEngine::PrimitiveTransform
  3981. // && d->state->matrix.type() == QTransform::TxTranslate) {
  3982. // } else {
  3983. QPainterPath polylinePath(points[0]);
  3984. for (int i=1; i<pointCount; ++i)
  3985. polylinePath.lineTo(points[i]);
  3986. d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
  3987. // }
  3988. } else {
  3989. d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
  3990. }
  3991. }
  3992. /*!
  3993. \fn void QPainter::drawPolyline(const QPolygon &polygon, int index, int
  3994. count)
  3995. \overload
  3996. \compat
  3997. Draws the polyline defined by the \a count lines of the given \a
  3998. polygon starting at \a index (\a index defaults to 0).
  3999. Use drawPolyline() combined with QPolygon::constData() instead.
  4000. \oldcode
  4001. QPainter painter(this);
  4002. painter.drawPolyline(polygon, index, count);
  4003. \newcode
  4004. int pointCount = (count == -1) ? polygon.size() - index : count;
  4005. QPainter painter(this);
  4006. painter.drawPolyline(polygon.constData() + index, pointCount);
  4007. \endcode
  4008. */
  4009. /*!
  4010. \fn void QPainter::drawPolyline(const QPolygonF &points)
  4011. \overload
  4012. Draws the polyline defined by the given \a points using the
  4013. current pen.
  4014. */
  4015. /*!
  4016. \fn void QPainter::drawPolyline(const QPolygon &points)
  4017. \overload
  4018. Draws the polyline defined by the given \a points using the
  4019. current pen.
  4020. */
  4021. /*!
  4022. Draws the polygon defined by the first \a pointCount points in the
  4023. array \a points using the current pen and brush.
  4024. \table 100%
  4025. \row
  4026. \o \inlineimage qpainter-polygon.png
  4027. \o
  4028. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 14
  4029. \endtable
  4030. The first point is implicitly connected to the last point, and the
  4031. polygon is filled with the current brush().
  4032. If \a fillRule is Qt::WindingFill, the polygon is filled using the
  4033. winding fill algorithm. If \a fillRule is Qt::OddEvenFill, the
  4034. polygon is filled using the odd-even fill algorithm. See
  4035. \l{Qt::FillRule} for a more detailed description of these fill
  4036. rules.
  4037. \sa drawConvexPolygon(), drawPolyline(), {Coordinate System}
  4038. */
  4039. void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
  4040. {
  4041. #ifdef QT_DEBUG_DRAW
  4042. if (qt_show_painter_debug_output)
  4043. printf("QPainter::drawPolygon(), count=%d\n", pointCount);
  4044. #endif
  4045. Q_D(QPainter);
  4046. if (!d->engine || pointCount < 2)
  4047. return;
  4048. if (d->extended) {
  4049. d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
  4050. return;
  4051. }
  4052. d->updateState(d->state);
  4053. uint emulationSpecifier = d->state->emulationSpecifier;
  4054. if (emulationSpecifier) {
  4055. QPainterPath polygonPath(points[0]);
  4056. for (int i=1; i<pointCount; ++i)
  4057. polygonPath.lineTo(points[i]);
  4058. polygonPath.closeSubpath();
  4059. polygonPath.setFillRule(fillRule);
  4060. d->draw_helper(polygonPath);
  4061. return;
  4062. }
  4063. d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
  4064. }
  4065. /*! \overload
  4066. Draws the polygon defined by the first \a pointCount points in the
  4067. array \a points.
  4068. */
  4069. void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
  4070. {
  4071. #ifdef QT_DEBUG_DRAW
  4072. if (qt_show_painter_debug_output)
  4073. printf("QPainter::drawPolygon(), count=%d\n", pointCount);
  4074. #endif
  4075. Q_D(QPainter);
  4076. if (!d->engine || pointCount < 2)
  4077. return;
  4078. if (d->extended) {
  4079. d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
  4080. return;
  4081. }
  4082. d->updateState(d->state);
  4083. uint emulationSpecifier = d->state->emulationSpecifier;
  4084. if (emulationSpecifier) {
  4085. QPainterPath polygonPath(points[0]);
  4086. for (int i=1; i<pointCount; ++i)
  4087. polygonPath.lineTo(points[i]);
  4088. polygonPath.closeSubpath();
  4089. polygonPath.setFillRule(fillRule);
  4090. d->draw_helper(polygonPath);
  4091. return;
  4092. }
  4093. d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
  4094. }
  4095. /*! \fn void QPainter::drawPolygon(const QPolygonF &polygon, bool winding, int index = 0,
  4096. int count = -1)
  4097. \compat
  4098. \overload
  4099. Use drawPolygon() combined with QPolygonF::constData() instead.
  4100. \oldcode
  4101. QPainter painter(this);
  4102. painter.drawPolygon(polygon, winding, index, count);
  4103. \newcode
  4104. int pointCount = (count == -1) ? polygon.size() - index : count;
  4105. int fillRule = winding ? Qt::WindingFill : Qt::OddEvenFill;
  4106. QPainter painter(this);
  4107. painter.drawPolygon( polygon.constData() + index, pointCount, fillRule);
  4108. \endcode
  4109. */
  4110. /*! \fn void QPainter::drawPolygon(const QPolygon &polygon, bool winding,
  4111. int index = 0, int count = -1)
  4112. \compat
  4113. \overload
  4114. Use drawPolygon() combined with QPolygon::constData() instead.
  4115. \oldcode
  4116. QPainter painter(this);
  4117. painter.drawPolygon(polygon, winding, index, count);
  4118. \newcode
  4119. int pointCount = (count == -1) ? polygon.size() - index : count;
  4120. int fillRule = winding ? Qt::WindingFill : Qt::OddEvenFill;
  4121. QPainter painter(this);
  4122. painter.drawPolygon( polygon.constData() + index, pointCount, fillRule);
  4123. \endcode
  4124. */
  4125. /*! \fn void QPainter::drawPolygon(const QPolygonF &points, Qt::FillRule fillRule)
  4126. \overload
  4127. Draws the polygon defined by the given \a points using the fill
  4128. rule \a fillRule.
  4129. */
  4130. /*! \fn void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule)
  4131. \overload
  4132. Draws the polygon defined by the given \a points using the fill
  4133. rule \a fillRule.
  4134. */
  4135. /*!
  4136. \fn void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
  4137. Draws the convex polygon defined by the first \a pointCount points
  4138. in the array \a points using the current pen.
  4139. \table 100%
  4140. \row
  4141. \o \inlineimage qpainter-polygon.png
  4142. \o
  4143. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 15
  4144. \endtable
  4145. The first point is implicitly connected to the last point, and the
  4146. polygon is filled with the current brush(). If the supplied
  4147. polygon is not convex, i.e. it contains at least one angle larger
  4148. than 180 degrees, the results are undefined.
  4149. On some platforms (e.g. X11), the drawConvexPolygon() function can
  4150. be faster than the drawPolygon() function.
  4151. \sa drawPolygon(), drawPolyline(), {Coordinate System}
  4152. */
  4153. /*!
  4154. \fn void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
  4155. \overload
  4156. Draws the convex polygon defined by the first \a pointCount points
  4157. in the array \a points using the current pen.
  4158. */
  4159. /*!
  4160. \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon)
  4161. \overload
  4162. Draws the convex polygon defined by \a polygon using the current
  4163. pen and brush.
  4164. */
  4165. /*!
  4166. \fn void QPainter::drawConvexPolygon(const QPolygon &polygon)
  4167. \overload
  4168. Draws the convex polygon defined by \a polygon using the current
  4169. pen and brush.
  4170. */
  4171. /*!
  4172. \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon, int
  4173. index, int count)
  4174. \compat
  4175. \overload
  4176. Use drawConvexPolygon() combined with QPolygonF::constData()
  4177. instead.
  4178. \oldcode
  4179. QPainter painter(this);
  4180. painter.drawConvexPolygon(polygon, index, count);
  4181. \newcode
  4182. int pointCount = (count == -1) ? polygon.size() - index : count;
  4183. QPainter painter(this);
  4184. painter.drawConvexPolygon(polygon.constData() + index, pointCount);
  4185. \endcode
  4186. */
  4187. /*!
  4188. \fn void QPainter::drawConvexPolygon(const QPolygon &polygon, int
  4189. index, int count)
  4190. \compat
  4191. \overload
  4192. Use drawConvexPolygon() combined with QPolygon::constData()
  4193. instead.
  4194. \oldcode
  4195. QPainter painter(this);
  4196. painter.drawConvexPolygon(polygon, index, count);
  4197. \newcode
  4198. int pointCount = (count == -1) ? polygon.size() - index : count;
  4199. QPainter painter(this);
  4200. painter.drawConvexPolygon(polygon.constData() + index, pointCount);
  4201. \endcode
  4202. */
  4203. void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
  4204. {
  4205. #ifdef QT_DEBUG_DRAW
  4206. if (qt_show_painter_debug_output)
  4207. printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
  4208. #endif
  4209. Q_D(QPainter);
  4210. if (!d->engine || pointCount < 2)
  4211. return;
  4212. if (d->extended) {
  4213. d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
  4214. return;
  4215. }
  4216. d->updateState(d->state);
  4217. uint emulationSpecifier = d->state->emulationSpecifier;
  4218. if (emulationSpecifier) {
  4219. QPainterPath polygonPath(points[0]);
  4220. for (int i=1; i<pointCount; ++i)
  4221. polygonPath.lineTo(points[i]);
  4222. polygonPath.closeSubpath();
  4223. polygonPath.setFillRule(Qt::WindingFill);
  4224. d->draw_helper(polygonPath);
  4225. return;
  4226. }
  4227. d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
  4228. }
  4229. void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
  4230. {
  4231. #ifdef QT_DEBUG_DRAW
  4232. if (qt_show_painter_debug_output)
  4233. printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
  4234. #endif
  4235. Q_D(QPainter);
  4236. if (!d->engine || pointCount < 2)
  4237. return;
  4238. if (d->extended) {
  4239. d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
  4240. return;
  4241. }
  4242. d->updateState(d->state);
  4243. uint emulationSpecifier = d->state->emulationSpecifier;
  4244. if (emulationSpecifier) {
  4245. QPainterPath polygonPath(points[0]);
  4246. for (int i=1; i<pointCount; ++i)
  4247. polygonPath.lineTo(points[i]);
  4248. polygonPath.closeSubpath();
  4249. polygonPath.setFillRule(Qt::WindingFill);
  4250. d->draw_helper(polygonPath);
  4251. return;
  4252. }
  4253. d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
  4254. }
  4255. static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransform &m)
  4256. {
  4257. return m.inverted().map(QPointF(m.map(p).toPoint()));
  4258. }
  4259. /*!
  4260. \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
  4261. Draws the rectangular portion \a source of the given \a pixmap
  4262. into the given \a target in the paint device.
  4263. \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
  4264. \table 100%
  4265. \row
  4266. \o
  4267. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 16
  4268. \endtable
  4269. If \a pixmap is a QBitmap it is drawn with the bits that are "set"
  4270. using the pens color. If backgroundMode is Qt::OpaqueMode, the
  4271. "unset" bits are drawn using the color of the background brush; if
  4272. backgroundMode is Qt::TransparentMode, the "unset" bits are
  4273. transparent. Drawing bitmaps with gradient or texture colors is
  4274. not supported.
  4275. \sa drawImage()
  4276. */
  4277. void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
  4278. {
  4279. #if defined QT_DEBUG_DRAW
  4280. if (qt_show_painter_debug_output)
  4281. printf("QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
  4282. p.x(), p.y(),
  4283. pm.width(), pm.height());
  4284. #endif
  4285. Q_D(QPainter);
  4286. if (!d->engine || pm.isNull())
  4287. return;
  4288. #ifndef QT_NO_DEBUG
  4289. qt_painter_thread_test(d->device->devType(), "drawPixmap()", true);
  4290. #endif
  4291. if (d->extended) {
  4292. d->extended->drawPixmap(p, pm);
  4293. return;
  4294. }
  4295. qreal x = p.x();
  4296. qreal y = p.y();
  4297. int w = pm.width();
  4298. int h = pm.height();
  4299. if (w <= 0)
  4300. return;
  4301. // Emulate opaque background for bitmaps
  4302. if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
  4303. fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
  4304. }
  4305. d->updateState(d->state);
  4306. if ((d->state->matrix.type() > QTransform::TxTranslate
  4307. && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
  4308. || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
  4309. || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
  4310. {
  4311. save();
  4312. // If there is no rotation involved we have to make sure we use the
  4313. // antialiased and not the aliased coordinate system by rounding the coordinates.
  4314. if (d->state->matrix.type() <= QTransform::TxScale) {
  4315. const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
  4316. x = p.x();
  4317. y = p.y();
  4318. }
  4319. translate(x, y);
  4320. setBackgroundMode(Qt::TransparentMode);
  4321. setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
  4322. QBrush brush(d->state->pen.color(), pm);
  4323. setBrush(brush);
  4324. setPen(Qt::NoPen);
  4325. setBrushOrigin(QPointF(0, 0));
  4326. drawRect(pm.rect());
  4327. restore();
  4328. } else {
  4329. if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
  4330. x += d->state->matrix.dx();
  4331. y += d->state->matrix.dy();
  4332. }
  4333. d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(0, 0, w, h));
  4334. }
  4335. }
  4336. void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
  4337. {
  4338. #if defined QT_DEBUG_DRAW
  4339. if (qt_show_painter_debug_output)
  4340. printf("QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
  4341. r.x(), r.y(), r.width(), r.height(),
  4342. pm.width(), pm.height(),
  4343. sr.x(), sr.y(), sr.width(), sr.height());
  4344. #endif
  4345. Q_D(QPainter);
  4346. if (!d->engine || pm.isNull())
  4347. return;
  4348. #ifndef QT_NO_DEBUG
  4349. qt_painter_thread_test(d->device->devType(), "drawPixmap()", true);
  4350. #endif
  4351. qreal x = r.x();
  4352. qreal y = r.y();
  4353. qreal w = r.width();
  4354. qreal h = r.height();
  4355. qreal sx = sr.x();
  4356. qreal sy = sr.y();
  4357. qreal sw = sr.width();
  4358. qreal sh = sr.height();
  4359. // Sanity-check clipping
  4360. if (sw <= 0)
  4361. sw = pm.width() - sx;
  4362. if (sh <= 0)
  4363. sh = pm.height() - sy;
  4364. if (w < 0)
  4365. w = sw;
  4366. if (h < 0)
  4367. h = sh;
  4368. if (sx < 0) {
  4369. qreal w_ratio = sx * w/sw;
  4370. x -= w_ratio;
  4371. w += w_ratio;
  4372. sw += sx;
  4373. sx = 0;
  4374. }
  4375. if (sy < 0) {
  4376. qreal h_ratio = sy * h/sh;
  4377. y -= h_ratio;
  4378. h += h_ratio;
  4379. sh += sy;
  4380. sy = 0;
  4381. }
  4382. if (sw + sx > pm.width()) {
  4383. qreal delta = sw - (pm.width() - sx);
  4384. qreal w_ratio = delta * w/sw;
  4385. sw -= delta;
  4386. w -= w_ratio;
  4387. }
  4388. if (sh + sy > pm.height()) {
  4389. qreal delta = sh - (pm.height() - sy);
  4390. qreal h_ratio = delta * h/sh;
  4391. sh -= delta;
  4392. h -= h_ratio;
  4393. }
  4394. if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
  4395. return;
  4396. if (d->extended) {
  4397. d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
  4398. return;
  4399. }
  4400. // Emulate opaque background for bitmaps
  4401. if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
  4402. fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
  4403. d->updateState(d->state);
  4404. if ((d->state->matrix.type() > QTransform::TxTranslate
  4405. && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
  4406. || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
  4407. || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
  4408. || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
  4409. {
  4410. save();
  4411. // If there is no rotation involved we have to make sure we use the
  4412. // antialiased and not the aliased coordinate system by rounding the coordinates.
  4413. if (d->state->matrix.type() <= QTransform::TxScale) {
  4414. const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
  4415. x = p.x();
  4416. y = p.y();
  4417. }
  4418. if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
  4419. sx = qRound(sx);
  4420. sy = qRound(sy);
  4421. sw = qRound(sw);
  4422. sh = qRound(sh);
  4423. }
  4424. translate(x, y);
  4425. scale(w / sw, h / sh);
  4426. setBackgroundMode(Qt::TransparentMode);
  4427. setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
  4428. QBrush brush;
  4429. if (sw == pm.width() && sh == pm.height())
  4430. brush = QBrush(d->state->pen.color(), pm);
  4431. else
  4432. brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
  4433. setBrush(brush);
  4434. setPen(Qt::NoPen);
  4435. drawRect(QRectF(0, 0, sw, sh));
  4436. restore();
  4437. } else {
  4438. if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
  4439. x += d->state->matrix.dx();
  4440. y += d->state->matrix.dy();
  4441. }
  4442. d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
  4443. }
  4444. }
  4445. /*!
  4446. \fn void QPainter::drawPixmap(const QRect &target, const QPixmap &pixmap,
  4447. const QRect &source)
  4448. \overload
  4449. Draws the rectangular portion \a source of the given \a pixmap
  4450. into the given \a target in the paint device.
  4451. \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
  4452. */
  4453. /*!
  4454. \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap,
  4455. const QRectF &source)
  4456. \overload
  4457. Draws the rectangular portion \a source of the given \a pixmap
  4458. with its origin at the given \a point.
  4459. */
  4460. /*!
  4461. \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap,
  4462. const QRect &source)
  4463. \overload
  4464. Draws the rectangular portion \a source of the given \a pixmap
  4465. with its origin at the given \a point.
  4466. */
  4467. /*!
  4468. \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap)
  4469. \overload
  4470. Draws the given \a pixmap with its origin at the given \a point.
  4471. */
  4472. /*!
  4473. \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap)
  4474. \overload
  4475. Draws the given \a pixmap with its origin at the given \a point.
  4476. */
  4477. /*!
  4478. \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap)
  4479. \overload
  4480. Draws the given \a pixmap at position (\a{x}, \a{y}).
  4481. */
  4482. /*!
  4483. \fn void QPainter::drawPixmap(const QRect &rectangle, const QPixmap &pixmap)
  4484. \overload
  4485. Draws the given \a pixmap into the given \a rectangle.
  4486. \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
  4487. */
  4488. /*!
  4489. \fn void QPainter::drawPixmap(int x, int y, int width, int height,
  4490. const QPixmap &pixmap)
  4491. \overload
  4492. Draws the \a pixmap into the rectangle at position (\a{x}, \a{y})
  4493. with the given \a width and \a height.
  4494. */
  4495. /*!
  4496. \fn void QPainter::drawPixmap(int x, int y, int w, int h, const QPixmap &pixmap,
  4497. int sx, int sy, int sw, int sh)
  4498. \overload
  4499. Draws the rectangular portion with the origin (\a{sx}, \a{sy}),
  4500. width \a sw and height \a sh, of the given \a pixmap , at the
  4501. point (\a{x}, \a{y}), with a width of \a w and a height of \a h.
  4502. If sw or sh are equal to zero the width/height of the pixmap
  4503. is used and adjusted by the offset sx/sy;
  4504. */
  4505. /*!
  4506. \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap,
  4507. int sx, int sy, int sw, int sh)
  4508. \overload
  4509. Draws a pixmap at (\a{x}, \a{y}) by copying a part of the given \a
  4510. pixmap into the paint device.
  4511. (\a{x}, \a{y}) specifies the top-left point in the paint device that is
  4512. to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
  4513. pixmap that is to be drawn. The default is (0, 0).
  4514. (\a{sw}, \a{sh}) specifies the size of the pixmap that is to be drawn.
  4515. The default, (0, 0) (and negative) means all the way to the
  4516. bottom-right of the pixmap.
  4517. */
  4518. void QPainter::drawImage(const QPointF &p, const QImage &image)
  4519. {
  4520. Q_D(QPainter);
  4521. if (!d->engine || image.isNull())
  4522. return;
  4523. if (d->extended) {
  4524. d->extended->drawImage(p, image);
  4525. return;
  4526. }
  4527. qreal x = p.x();
  4528. qreal y = p.y();
  4529. int w = image.width();
  4530. int h = image.height();
  4531. d->updateState(d->state);
  4532. if (((d->state->matrix.type() > QTransform::TxTranslate)
  4533. && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
  4534. || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
  4535. || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
  4536. {
  4537. save();
  4538. // If there is no rotation involved we have to make sure we use the
  4539. // antialiased and not the aliased coordinate system by rounding the coordinates.
  4540. if (d->state->matrix.type() <= QTransform::TxScale) {
  4541. const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
  4542. x = p.x();
  4543. y = p.y();
  4544. }
  4545. translate(x, y);
  4546. setBackgroundMode(Qt::TransparentMode);
  4547. setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
  4548. QBrush brush(image);
  4549. setBrush(brush);
  4550. setPen(Qt::NoPen);
  4551. setBrushOrigin(QPointF(0, 0));
  4552. drawRect(image.rect());
  4553. restore();
  4554. return;
  4555. }
  4556. if (d->state->matrix.type() == QTransform::TxTranslate
  4557. && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
  4558. x += d->state->matrix.dx();
  4559. y += d->state->matrix.dy();
  4560. }
  4561. d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(0, 0, w, h), Qt::AutoColor);
  4562. }
  4563. void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
  4564. Qt::ImageConversionFlags flags)
  4565. {
  4566. Q_D(QPainter);
  4567. if (!d->engine || image.isNull())
  4568. return;
  4569. qreal x = targetRect.x();
  4570. qreal y = targetRect.y();
  4571. qreal w = targetRect.width();
  4572. qreal h = targetRect.height();
  4573. qreal sx = sourceRect.x();
  4574. qreal sy = sourceRect.y();
  4575. qreal sw = sourceRect.width();
  4576. qreal sh = sourceRect.height();
  4577. // Sanity-check clipping
  4578. if (sw <= 0)
  4579. sw = image.width() - sx;
  4580. if (sh <= 0)
  4581. sh = image.height() - sy;
  4582. if (w < 0)
  4583. w = sw;
  4584. if (h < 0)
  4585. h = sh;
  4586. if (sx < 0) {
  4587. qreal w_ratio = sx * w/sw;
  4588. x -= w_ratio;
  4589. w += w_ratio;
  4590. sw += sx;
  4591. sx = 0;
  4592. }
  4593. if (sy < 0) {
  4594. qreal h_ratio = sy * h/sh;
  4595. y -= h_ratio;
  4596. h += h_ratio;
  4597. sh += sy;
  4598. sy = 0;
  4599. }
  4600. if (sw + sx > image.width()) {
  4601. qreal delta = sw - (image.width() - sx);
  4602. qreal w_ratio = delta * w/sw;
  4603. sw -= delta;
  4604. w -= w_ratio;
  4605. }
  4606. if (sh + sy > image.height()) {
  4607. qreal delta = sh - (image.height() - sy);
  4608. qreal h_ratio = delta * h/sh;
  4609. sh -= delta;
  4610. h -= h_ratio;
  4611. }
  4612. if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
  4613. return;
  4614. if (d->extended) {
  4615. d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
  4616. return;
  4617. }
  4618. d->updateState(d->state);
  4619. if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
  4620. && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
  4621. || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
  4622. || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
  4623. {
  4624. save();
  4625. // If there is no rotation involved we have to make sure we use the
  4626. // antialiased and not the aliased coordinate system by rounding the coordinates.
  4627. if (d->state->matrix.type() <= QTransform::TxScale) {
  4628. const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
  4629. x = p.x();
  4630. y = p.y();
  4631. }
  4632. if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
  4633. sx = qRound(sx);
  4634. sy = qRound(sy);
  4635. sw = qRound(sw);
  4636. sh = qRound(sh);
  4637. }
  4638. translate(x, y);
  4639. scale(w / sw, h / sh);
  4640. setBackgroundMode(Qt::TransparentMode);
  4641. setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
  4642. QBrush brush(image);
  4643. setBrush(brush);
  4644. setPen(Qt::NoPen);
  4645. setBrushOrigin(QPointF(-sx, -sy));
  4646. drawRect(QRectF(0, 0, sw, sh));
  4647. restore();
  4648. return;
  4649. }
  4650. if (d->state->matrix.type() == QTransform::TxTranslate
  4651. && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
  4652. x += d->state->matrix.dx();
  4653. y += d->state->matrix.dy();
  4654. }
  4655. d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
  4656. }
  4657. #if !defined(QT_NO_RAWFONT)
  4658. /*!
  4659. \fn void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphs)
  4660. Draws the specified \a glyphs at the given \a position.
  4661. The \a position gives the edge of the baseline for the string of glyphs.
  4662. The glyphs will be retrieved from the font selected by \a glyphs and at
  4663. offsets given by the positions in \a glyphs.
  4664. \since 4.8
  4665. \sa QGlyphRun::setRawFont(), QGlyphRun::setPositions(), QGlyphRun::setGlyphIndexes()
  4666. */
  4667. void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
  4668. {
  4669. Q_D(QPainter);
  4670. QRawFont font = glyphRun.rawFont();
  4671. if (!font.isValid())
  4672. return;
  4673. QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
  4674. const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
  4675. const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
  4676. int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
  4677. QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
  4678. QRawFontPrivate *fontD = QRawFontPrivate::get(font);
  4679. bool supportsTransformations;
  4680. if (d->extended != 0) {
  4681. supportsTransformations = d->extended->supportsTransformations(fontD->fontEngine->fontDef.pixelSize,
  4682. d->state->matrix);
  4683. } else {
  4684. supportsTransformations = d->engine->type() == QPaintEngine::CoreGraphics
  4685. || d->state->matrix.isAffine();
  4686. }
  4687. for (int i=0; i<count; ++i) {
  4688. QPointF processedPosition = position + glyphPositions[i];
  4689. if (!supportsTransformations)
  4690. processedPosition = d->state->transform().map(processedPosition);
  4691. fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
  4692. }
  4693. d->drawGlyphs(glyphIndexes, fixedPointPositions.data(), count, font, glyphRun.overline(),
  4694. glyphRun.underline(), glyphRun.strikeOut());
  4695. }
  4696. void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positions,
  4697. int glyphCount,
  4698. const QRawFont &font, bool overline, bool underline,
  4699. bool strikeOut)
  4700. {
  4701. Q_Q(QPainter);
  4702. updateState(state);
  4703. QRawFontPrivate *fontD = QRawFontPrivate::get(font);
  4704. QFontEngine *fontEngine = fontD->fontEngine;
  4705. QFixed leftMost;
  4706. QFixed rightMost;
  4707. QFixed baseLine;
  4708. for (int i=0; i<glyphCount; ++i) {
  4709. glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
  4710. if (i == 0 || leftMost > positions[i].x)
  4711. leftMost = positions[i].x;
  4712. // We don't support glyphs that do not share a common baseline. If this turns out to
  4713. // be a relevant use case, then we need to find clusters of glyphs that share a baseline
  4714. // and do a drawTextItemDecorations call per cluster.
  4715. if (i == 0 || baseLine < positions[i].y)
  4716. baseLine = positions[i].y;
  4717. // We use the advance rather than the actual bounds to match the algorithm in drawText()
  4718. if (i == 0 || rightMost < positions[i].x + gm.xoff)
  4719. rightMost = positions[i].x + gm.xoff;
  4720. }
  4721. QFixed width = rightMost - leftMost;
  4722. if (extended != 0 && state->matrix.isAffine()) {
  4723. QStaticTextItem staticTextItem;
  4724. staticTextItem.color = state->pen.color();
  4725. staticTextItem.font = state->font;
  4726. staticTextItem.setFontEngine(fontEngine);
  4727. staticTextItem.numGlyphs = glyphCount;
  4728. staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray));
  4729. staticTextItem.glyphPositions = positions;
  4730. extended->drawStaticTextItem(&staticTextItem);
  4731. } else {
  4732. QTextItemInt textItem;
  4733. textItem.fontEngine = fontEngine;
  4734. QVarLengthArray<QFixed, 128> advances(glyphCount);
  4735. QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
  4736. QVarLengthArray<HB_GlyphAttributes, 128> glyphAttributes(glyphCount);
  4737. qMemSet(glyphAttributes.data(), 0, glyphAttributes.size() * sizeof(HB_GlyphAttributes));
  4738. qMemSet(advances.data(), 0, advances.size() * sizeof(QFixed));
  4739. qMemSet(glyphJustifications.data(), 0, glyphJustifications.size() * sizeof(QGlyphJustification));
  4740. textItem.glyphs.numGlyphs = glyphCount;
  4741. textItem.glyphs.glyphs = reinterpret_cast<HB_Glyph *>(const_cast<quint32 *>(glyphArray));
  4742. textItem.glyphs.offsets = positions;
  4743. textItem.glyphs.advances_x = advances.data();
  4744. textItem.glyphs.advances_y = advances.data();
  4745. textItem.glyphs.justifications = glyphJustifications.data();
  4746. textItem.glyphs.attributes = glyphAttributes.data();
  4747. engine->drawTextItem(QPointF(0, 0), textItem);
  4748. }
  4749. QTextItemInt::RenderFlags flags;
  4750. if (underline)
  4751. flags |= QTextItemInt::Underline;
  4752. if (overline)
  4753. flags |= QTextItemInt::Overline;
  4754. if (strikeOut)
  4755. flags |= QTextItemInt::StrikeOut;
  4756. drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()),
  4757. fontEngine,
  4758. (underline
  4759. ? QTextCharFormat::SingleUnderline
  4760. : QTextCharFormat::NoUnderline),
  4761. flags, width.toReal(), QTextCharFormat());
  4762. }
  4763. #endif // QT_NO_RAWFONT
  4764. /*!
  4765. \fn void QPainter::drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText)
  4766. \since 4.7
  4767. \overload
  4768. Draws the \a staticText at the \a topLeftPosition.
  4769. \note The y-position is used as the top of the font.
  4770. */
  4771. /*!
  4772. \fn void QPainter::drawStaticText(int left, int top, const QStaticText &staticText)
  4773. \since 4.7
  4774. \overload
  4775. Draws the \a staticText at coordinates \a left and \a top.
  4776. \note The y-position is used as the top of the font.
  4777. */
  4778. /*!
  4779. \fn void QPainter::drawText(const QPointF &position, const QString &text)
  4780. Draws the given \a text with the currently defined text direction,
  4781. beginning at the given \a position.
  4782. This function does not handle the newline character (\n), as it cannot
  4783. break text into multiple lines, and it cannot display the newline character.
  4784. Use the QPainter::drawText() overload that takes a rectangle instead
  4785. if you want to draw multiple lines of text with the newline character, or
  4786. if you want the text to be wrapped.
  4787. By default, QPainter draws text anti-aliased.
  4788. \note The y-position is used as the baseline of the font.
  4789. */
  4790. void QPainter::drawText(const QPointF &p, const QString &str)
  4791. {
  4792. drawText(p, str, 0, 0);
  4793. }
  4794. /*!
  4795. \since 4.7
  4796. Draws the given \a staticText at the given \a topLeftPosition.
  4797. The text will be drawn using the font and the transformation set on the painter. If the
  4798. font and/or transformation set on the painter are different from the ones used to initialize
  4799. the layout of the QStaticText, then the layout will have to be recalculated. Use
  4800. QStaticText::prepare() to initialize \a staticText with the font and transformation with which
  4801. it will later be drawn.
  4802. If \a topLeftPosition is not the same as when \a staticText was initialized, or when it was
  4803. last drawn, then there will be a slight overhead when translating the text to its new position.
  4804. \note If the painter's transformation is not affine, then \a staticText will be drawn using
  4805. regular calls to drawText(), losing any potential for performance improvement.
  4806. \note The y-position is used as the top of the font.
  4807. \sa QStaticText
  4808. */
  4809. void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText)
  4810. {
  4811. Q_D(QPainter);
  4812. if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
  4813. return;
  4814. QStaticTextPrivate *staticText_d =
  4815. const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
  4816. if (font() != staticText_d->font) {
  4817. staticText_d->font = font();
  4818. staticText_d->needsRelayout = true;
  4819. }
  4820. // If we don't have an extended paint engine, or if the painter is projected,
  4821. // we go through standard code path
  4822. if (d->extended == 0 || !d->state->matrix.isAffine()) {
  4823. staticText_d->paintText(topLeftPosition, this);
  4824. return;
  4825. }
  4826. bool supportsTransformations = d->extended->supportsTransformations(staticText_d->font.pixelSize(),
  4827. d->state->matrix);
  4828. if (supportsTransformations && !staticText_d->untransformedCoordinates) {
  4829. staticText_d->untransformedCoordinates = true;
  4830. staticText_d->needsRelayout = true;
  4831. } else if (!supportsTransformations && staticText_d->untransformedCoordinates) {
  4832. staticText_d->untransformedCoordinates = false;
  4833. staticText_d->needsRelayout = true;
  4834. }
  4835. // Don't recalculate entire layout because of translation, rather add the dx and dy
  4836. // into the position to move each text item the correct distance.
  4837. QPointF transformedPosition = topLeftPosition;
  4838. if (!staticText_d->untransformedCoordinates)
  4839. transformedPosition = transformedPosition * d->state->matrix;
  4840. QTransform oldMatrix;
  4841. // The translation has been applied to transformedPosition. Remove translation
  4842. // component from matrix.
  4843. if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
  4844. qreal m11 = d->state->matrix.m11();
  4845. qreal m12 = d->state->matrix.m12();
  4846. qreal m13 = d->state->matrix.m13();
  4847. qreal m21 = d->state->matrix.m21();
  4848. qreal m22 = d->state->matrix.m22();
  4849. qreal m23 = d->state->matrix.m23();
  4850. qreal m33 = d->state->matrix.m33();
  4851. oldMatrix = d->state->matrix;
  4852. d->state->matrix.setMatrix(m11, m12, m13,
  4853. m21, m22, m23,
  4854. 0.0, 0.0, m33);
  4855. }
  4856. // If the transform is not identical to the text transform,
  4857. // we have to relayout the text (for other transformations than plain translation)
  4858. bool staticTextNeedsReinit = staticText_d->needsRelayout;
  4859. if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
  4860. staticText_d->matrix = d->state->matrix;
  4861. staticTextNeedsReinit = true;
  4862. }
  4863. // Recreate the layout of the static text because the matrix or font has changed
  4864. if (staticTextNeedsReinit)
  4865. staticText_d->init();
  4866. if (transformedPosition != staticText_d->position) { // Translate to actual position
  4867. QFixed fx = QFixed::fromReal(transformedPosition.x());
  4868. QFixed fy = QFixed::fromReal(transformedPosition.y());
  4869. QFixed oldX = QFixed::fromReal(staticText_d->position.x());
  4870. QFixed oldY = QFixed::fromReal(staticText_d->position.y());
  4871. for (int item=0; item<staticText_d->itemCount;++item) {
  4872. QStaticTextItem *textItem = staticText_d->items + item;
  4873. for (int i=0; i<textItem->numGlyphs; ++i) {
  4874. textItem->glyphPositions[i].x += fx - oldX;
  4875. textItem->glyphPositions[i].y += fy - oldY;
  4876. }
  4877. textItem->userDataNeedsUpdate = true;
  4878. }
  4879. staticText_d->position = transformedPosition;
  4880. }
  4881. QPen oldPen = d->state->pen;
  4882. QColor currentColor = oldPen.color();
  4883. for (int i=0; i<staticText_d->itemCount; ++i) {
  4884. QStaticTextItem *item = staticText_d->items + i;
  4885. if (item->color.isValid() && currentColor != item->color) {
  4886. setPen(item->color);
  4887. currentColor = item->color;
  4888. }
  4889. d->extended->drawStaticTextItem(item);
  4890. qt_draw_decoration_for_glyphs(this, item->glyphs, item->glyphPositions,
  4891. item->numGlyphs, item->fontEngine(), staticText_d->font,
  4892. QTextCharFormat());
  4893. }
  4894. if (currentColor != oldPen.color())
  4895. setPen(oldPen);
  4896. if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
  4897. d->state->matrix = oldMatrix;
  4898. }
  4899. /*!
  4900. \internal
  4901. */
  4902. void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
  4903. {
  4904. #ifdef QT_DEBUG_DRAW
  4905. if (qt_show_painter_debug_output)
  4906. printf("QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
  4907. #endif
  4908. Q_D(QPainter);
  4909. if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
  4910. return;
  4911. if (tf & Qt::TextBypassShaping) {
  4912. // Skip harfbuzz complex shaping, shape using glyph advances only
  4913. int len = str.length();
  4914. int numGlyphs = len;
  4915. QVarLengthGlyphLayoutArray glyphs(len);
  4916. QFontEngine *fontEngine = d->state->font.d->engineForScript(QUnicodeTables::Common);
  4917. if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) {
  4918. glyphs.resize(numGlyphs);
  4919. if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0))
  4920. Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
  4921. }
  4922. QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine);
  4923. drawTextItem(p, gf);
  4924. return;
  4925. }
  4926. QStackTextEngine engine(str, d->state->font);
  4927. engine.option.setTextDirection(d->state->layoutDirection);
  4928. if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
  4929. engine.ignoreBidi = true;
  4930. engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
  4931. }
  4932. engine.itemize();
  4933. QScriptLine line;
  4934. line.length = str.length();
  4935. engine.shapeLine(line);
  4936. int nItems = engine.layoutData->items.size();
  4937. QVarLengthArray<int> visualOrder(nItems);
  4938. QVarLengthArray<uchar> levels(nItems);
  4939. for (int i = 0; i < nItems; ++i)
  4940. levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
  4941. QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
  4942. if (justificationPadding > 0) {
  4943. engine.option.setAlignment(Qt::AlignJustify);
  4944. engine.forceJustification = true;
  4945. // this works because justify() is only interested in the difference between width and textWidth
  4946. line.width = justificationPadding;
  4947. engine.justify(line);
  4948. }
  4949. QFixed x = QFixed::fromReal(p.x());
  4950. for (int i = 0; i < nItems; ++i) {
  4951. int item = visualOrder[i];
  4952. const QScriptItem &si = engine.layoutData->items.at(item);
  4953. if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
  4954. x += si.width;
  4955. continue;
  4956. }
  4957. QFont f = engine.font(si);
  4958. QTextItemInt gf(si, &f);
  4959. gf.glyphs = engine.shapedGlyphs(&si);
  4960. gf.chars = engine.layoutData->string.unicode() + si.position;
  4961. gf.num_chars = engine.length(item);
  4962. if (engine.forceJustification) {
  4963. for (int j=0; j<gf.glyphs.numGlyphs; ++j)
  4964. gf.width += gf.glyphs.effectiveAdvance(j);
  4965. } else {
  4966. gf.width = si.width;
  4967. }
  4968. gf.logClusters = engine.logClusters(&si);
  4969. drawTextItem(QPointF(x.toReal(), p.y()), gf);
  4970. x += gf.width;
  4971. }
  4972. }
  4973. void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br)
  4974. {
  4975. #ifdef QT_DEBUG_DRAW
  4976. if (qt_show_painter_debug_output)
  4977. printf("QPainter::drawText(), r=[%d,%d,%d,%d], flags=%d, str='%s'\n",
  4978. r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
  4979. #endif
  4980. Q_D(QPainter);
  4981. if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
  4982. return;
  4983. if (!d->extended)
  4984. d->updateState(d->state);
  4985. QRectF bounds;
  4986. qt_format_text(d->state->font, r, flags, 0, str, br ? &bounds : 0, 0, 0, 0, this);
  4987. if (br)
  4988. *br = bounds.toAlignedRect();
  4989. }
  4990. /*!
  4991. \fn void QPainter::drawText(const QPoint &position, const QString &text)
  4992. \overload
  4993. Draws the given \a text with the currently defined text direction,
  4994. beginning at the given \a position.
  4995. By default, QPainter draws text anti-aliased.
  4996. \note The y-position is used as the baseline of the font.
  4997. */
  4998. /*!
  4999. \fn void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect)
  5000. \overload
  5001. Draws the given \a text within the provided \a rectangle.
  5002. \table 100%
  5003. \row
  5004. \o \inlineimage qpainter-text.png
  5005. \o
  5006. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 17
  5007. \endtable
  5008. The \a boundingRect (if not null) is set to the what the bounding rectangle
  5009. should be in order to enclose the whole text. The \a flags argument is a bitwise
  5010. OR of the following flags:
  5011. \list
  5012. \o Qt::AlignLeft
  5013. \o Qt::AlignRight
  5014. \o Qt::AlignHCenter
  5015. \o Qt::AlignJustify
  5016. \o Qt::AlignTop
  5017. \o Qt::AlignBottom
  5018. \o Qt::AlignVCenter
  5019. \o Qt::AlignCenter
  5020. \o Qt::TextDontClip
  5021. \o Qt::TextSingleLine
  5022. \o Qt::TextExpandTabs
  5023. \o Qt::TextShowMnemonic
  5024. \o Qt::TextWordWrap
  5025. \o Qt::TextIncludeTrailingSpaces
  5026. \endlist
  5027. \sa Qt::AlignmentFlag, Qt::TextFlag, boundingRect(), layoutDirection()
  5028. By default, QPainter draws text anti-aliased.
  5029. \note The y-coordinate of \a rectangle is used as the top of the font.
  5030. */
  5031. void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *br)
  5032. {
  5033. #ifdef QT_DEBUG_DRAW
  5034. if (qt_show_painter_debug_output)
  5035. printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], flags=%d, str='%s'\n",
  5036. r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
  5037. #endif
  5038. Q_D(QPainter);
  5039. if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
  5040. return;
  5041. if (!d->extended)
  5042. d->updateState(d->state);
  5043. qt_format_text(d->state->font, r, flags, 0, str, br, 0, 0, 0, this);
  5044. }
  5045. /*!
  5046. \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect)
  5047. \overload
  5048. Draws the given \a text within the provided \a rectangle according
  5049. to the specified \a flags. The \a boundingRect (if not null) is set to
  5050. the what the bounding rectangle should be in order to enclose the whole text.
  5051. By default, QPainter draws text anti-aliased.
  5052. \note The y-coordinate of \a rectangle is used as the top of the font.
  5053. */
  5054. /*!
  5055. \fn void QPainter::drawText(int x, int y, const QString &text)
  5056. \overload
  5057. Draws the given \a text at position (\a{x}, \a{y}), using the painter's
  5058. currently defined text direction.
  5059. By default, QPainter draws text anti-aliased.
  5060. \note The y-position is used as the baseline of the font.
  5061. */
  5062. /*!
  5063. \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
  5064. const QString &text, QRect *boundingRect)
  5065. \overload
  5066. Draws the given \a text within the rectangle with origin (\a{x},
  5067. \a{y}), \a width and \a height.
  5068. The \a boundingRect (if not null) is set to the actual bounding
  5069. rectangle of the output. The \a flags argument is a bitwise OR of
  5070. the following flags:
  5071. \list
  5072. \o Qt::AlignLeft
  5073. \o Qt::AlignRight
  5074. \o Qt::AlignHCenter
  5075. \o Qt::AlignJustify
  5076. \o Qt::AlignTop
  5077. \o Qt::AlignBottom
  5078. \o Qt::AlignVCenter
  5079. \o Qt::AlignCenter
  5080. \o Qt::TextSingleLine
  5081. \o Qt::TextExpandTabs
  5082. \o Qt::TextShowMnemonic
  5083. \o Qt::TextWordWrap
  5084. \endlist
  5085. By default, QPainter draws text anti-aliased.
  5086. \note The y-position is used as the top of the font.
  5087. \sa Qt::AlignmentFlag, Qt::TextFlag
  5088. */
  5089. /*!
  5090. \fn void QPainter::drawText(const QRectF &rectangle, const QString &text,
  5091. const QTextOption &option)
  5092. \overload
  5093. Draws the given \a text in the \a rectangle specified using the \a option
  5094. to control its positioning and orientation.
  5095. By default, QPainter draws text anti-aliased.
  5096. \note The y-coordinate of \a rectangle is used as the top of the font.
  5097. */
  5098. void QPainter::drawText(const QRectF &r, const QString &text, const QTextOption &o)
  5099. {
  5100. #ifdef QT_DEBUG_DRAW
  5101. if (qt_show_painter_debug_output)
  5102. printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], str='%s'\n",
  5103. r.x(), r.y(), r.width(), r.height(), text.toLatin1().constData());
  5104. #endif
  5105. Q_D(QPainter);
  5106. if (!d->engine || text.length() == 0 || pen().style() == Qt::NoPen)
  5107. return;
  5108. if (!d->extended)
  5109. d->updateState(d->state);
  5110. qt_format_text(d->state->font, r, 0, &o, text, 0, 0, 0, 0, this);
  5111. }
  5112. /*!
  5113. \fn void QPainter::drawTextItem(int x, int y, const QTextItem &ti)
  5114. \internal
  5115. \overload
  5116. */
  5117. /*!
  5118. \fn void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti)
  5119. \internal
  5120. \overload
  5121. Draws the text item \a ti at position \a p.
  5122. */
  5123. /*!
  5124. \fn void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti)
  5125. \internal
  5126. \since 4.1
  5127. Draws the text item \a ti at position \a p.
  5128. This method ignores the painters background mode and
  5129. color. drawText and qt_format_text have to do it themselves, as
  5130. only they know the extents of the complete string.
  5131. It ignores the font set on the painter as the text item has one of its own.
  5132. The underline and strikeout parameters of the text items font are
  5133. ignored aswell. You'll need to pass in the correct flags to get
  5134. underlining and strikeout.
  5135. */
  5136. static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
  5137. {
  5138. const qreal radiusBase = qMax(qreal(1), maxRadius);
  5139. QString key = QLatin1Literal("WaveUnderline-")
  5140. % pen.color().name()
  5141. % HexString<qreal>(radiusBase);
  5142. QPixmap pixmap;
  5143. if (QPixmapCache::find(key, pixmap))
  5144. return pixmap;
  5145. const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio
  5146. const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
  5147. const int radius = qFloor(radiusBase);
  5148. QPainterPath path;
  5149. qreal xs = 0;
  5150. qreal ys = radius;
  5151. while (xs < width) {
  5152. xs += halfPeriod;
  5153. ys = -ys;
  5154. path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
  5155. }
  5156. pixmap = QPixmap(width, radius * 2);
  5157. pixmap.fill(Qt::transparent);
  5158. {
  5159. QPen wavePen = pen;
  5160. wavePen.setCapStyle(Qt::SquareCap);
  5161. // This is to protect against making the line too fat, as happens on Mac OS X
  5162. // due to it having a rather thick width for the regular underline.
  5163. const qreal maxPenWidth = .8 * radius;
  5164. if (wavePen.widthF() > maxPenWidth)
  5165. wavePen.setWidth(maxPenWidth);
  5166. QPainter imgPainter(&pixmap);
  5167. imgPainter.setPen(wavePen);
  5168. imgPainter.setRenderHint(QPainter::Antialiasing);
  5169. imgPainter.translate(0, radius);
  5170. imgPainter.drawPath(path);
  5171. }
  5172. QPixmapCache::insert(key, pixmap);
  5173. return pixmap;
  5174. }
  5175. static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe,
  5176. QTextCharFormat::UnderlineStyle underlineStyle,
  5177. QTextItem::RenderFlags flags, qreal width,
  5178. const QTextCharFormat &charFormat)
  5179. {
  5180. if (underlineStyle == QTextCharFormat::NoUnderline
  5181. && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
  5182. return;
  5183. const QPen oldPen = painter->pen();
  5184. const QBrush oldBrush = painter->brush();
  5185. painter->setBrush(Qt::NoBrush);
  5186. QPen pen = oldPen;
  5187. pen.setStyle(Qt::SolidLine);
  5188. pen.setWidthF(fe->lineThickness().toReal());
  5189. pen.setCapStyle(Qt::FlatCap);
  5190. QLineF line(pos.x(), pos.y(), pos.x() + qFloor(width), pos.y());
  5191. qreal underlineOffset = fe->underlinePosition().toReal();
  5192. qreal y = pos.y();
  5193. // compensate for different rounding rule in Core Graphics paint engine,
  5194. // ideally code like this should be moved to respective engines.
  5195. if (painter->paintEngine()->type() == QPaintEngine::CoreGraphics) {
  5196. y = qCeil(y);
  5197. }
  5198. // deliberately ceil the offset to avoid the underline coming too close to
  5199. // the text above it.
  5200. const qreal underlinePos = y + qCeil(underlineOffset);
  5201. if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
  5202. underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle));
  5203. }
  5204. if (underlineStyle == QTextCharFormat::WaveUnderline) {
  5205. painter->save();
  5206. painter->translate(0, pos.y() + 1);
  5207. QColor uc = charFormat.underlineColor();
  5208. if (uc.isValid())
  5209. pen.setColor(uc);
  5210. // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
  5211. const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen);
  5212. const int descent = (int) fe->descent().toReal();
  5213. painter->setBrushOrigin(painter->brushOrigin().x(), 0);
  5214. painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
  5215. painter->restore();
  5216. } else if (underlineStyle != QTextCharFormat::NoUnderline) {
  5217. QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos);
  5218. QColor uc = charFormat.underlineColor();
  5219. if (uc.isValid())
  5220. pen.setColor(uc);
  5221. pen.setStyle((Qt::PenStyle)(underlineStyle));
  5222. painter->setPen(pen);
  5223. painter->drawLine(underLine);
  5224. }
  5225. pen.setStyle(Qt::SolidLine);
  5226. pen.setColor(oldPen.color());
  5227. if (flags & QTextItem::StrikeOut) {
  5228. QLineF strikeOutLine = line;
  5229. strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
  5230. painter->setPen(pen);
  5231. painter->drawLine(strikeOutLine);
  5232. }
  5233. if (flags & QTextItem::Overline) {
  5234. QLineF overLine = line;
  5235. overLine.translate(0., - fe->ascent().toReal());
  5236. painter->setPen(pen);
  5237. painter->drawLine(overLine);
  5238. }
  5239. painter->setPen(oldPen);
  5240. painter->setBrush(oldBrush);
  5241. }
  5242. Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
  5243. const QFixedPoint *positions, int glyphCount,
  5244. QFontEngine *fontEngine, const QFont &font,
  5245. const QTextCharFormat &charFormat)
  5246. {
  5247. if (!(font.underline() || font.strikeOut() || font.overline()))
  5248. return;
  5249. QFixed leftMost;
  5250. QFixed rightMost;
  5251. QFixed baseLine;
  5252. for (int i=0; i<glyphCount; ++i) {
  5253. glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
  5254. if (i == 0 || leftMost > positions[i].x)
  5255. leftMost = positions[i].x;
  5256. // We don't support glyphs that do not share a common baseline. If this turns out to
  5257. // be a relevant use case, then we need to find clusters of glyphs that share a baseline
  5258. // and do a drawTextItemDecorations call per cluster.
  5259. if (i == 0 || baseLine < positions[i].y)
  5260. baseLine = positions[i].y;
  5261. // We use the advance rather than the actual bounds to match the algorithm in drawText()
  5262. if (i == 0 || rightMost < positions[i].x + gm.xoff)
  5263. rightMost = positions[i].x + gm.xoff;
  5264. }
  5265. QFixed width = rightMost - leftMost;
  5266. QTextItem::RenderFlags flags = 0;
  5267. if (font.underline())
  5268. flags |= QTextItem::Underline;
  5269. if (font.overline())
  5270. flags |= QTextItem::Overline;
  5271. if (font.strikeOut())
  5272. flags |= QTextItem::StrikeOut;
  5273. drawTextItemDecoration(painter, QPointF(leftMost.toReal(), baseLine.toReal()),
  5274. fontEngine,
  5275. font.underline() ? QTextCharFormat::SingleUnderline
  5276. : QTextCharFormat::NoUnderline, flags,
  5277. width.toReal(), charFormat);
  5278. }
  5279. void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti)
  5280. {
  5281. #ifdef QT_DEBUG_DRAW
  5282. if (qt_show_painter_debug_output)
  5283. printf("QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
  5284. p.x(), p.y(), qPrintable(_ti.text()));
  5285. #endif
  5286. Q_D(QPainter);
  5287. if (!d->engine)
  5288. return;
  5289. #ifndef QT_NO_DEBUG
  5290. qt_painter_thread_test(d->device->devType(),
  5291. "text and fonts",
  5292. QFontDatabase::supportsThreadedFontRendering());
  5293. #endif
  5294. QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti));
  5295. if (!d->extended && d->state->bgMode == Qt::OpaqueMode) {
  5296. QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal());
  5297. fillRect(rect, d->state->bgBrush);
  5298. }
  5299. if (pen().style() == Qt::NoPen)
  5300. return;
  5301. const RenderHints oldRenderHints = d->state->renderHints;
  5302. if (!d->state->renderHints & QPainter::Antialiasing && d->state->matrix.type() >= QTransform::TxScale) {
  5303. // draw antialias decoration (underline/overline/strikeout) with
  5304. // transformed text
  5305. bool aa = true;
  5306. const QTransform &m = d->state->matrix;
  5307. if (d->state->matrix.type() < QTransform::TxShear) {
  5308. bool isPlain90DegreeRotation =
  5309. (qFuzzyIsNull(m.m11())
  5310. && qFuzzyIsNull(m.m12() - qreal(1))
  5311. && qFuzzyIsNull(m.m21() + qreal(1))
  5312. && qFuzzyIsNull(m.m22())
  5313. )
  5314. ||
  5315. (qFuzzyIsNull(m.m11() + qreal(1))
  5316. && qFuzzyIsNull(m.m12())
  5317. && qFuzzyIsNull(m.m21())
  5318. && qFuzzyIsNull(m.m22() + qreal(1))
  5319. )
  5320. ||
  5321. (qFuzzyIsNull(m.m11())
  5322. && qFuzzyIsNull(m.m12() + qreal(1))
  5323. && qFuzzyIsNull(m.m21() - qreal(1))
  5324. && qFuzzyIsNull(m.m22())
  5325. )
  5326. ;
  5327. aa = !isPlain90DegreeRotation;
  5328. }
  5329. if (aa)
  5330. setRenderHint(QPainter::Antialiasing, true);
  5331. }
  5332. if (!d->extended)
  5333. d->updateState(d->state);
  5334. if (!ti.glyphs.numGlyphs) {
  5335. // nothing to do
  5336. } else if (ti.fontEngine->type() == QFontEngine::Multi) {
  5337. QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
  5338. const QGlyphLayout &glyphs = ti.glyphs;
  5339. int which = glyphs.glyphs[0] >> 24;
  5340. qreal x = p.x();
  5341. qreal y = p.y();
  5342. bool rtl = ti.flags & QTextItem::RightToLeft;
  5343. if (rtl)
  5344. x += ti.width.toReal();
  5345. int start = 0;
  5346. int end, i;
  5347. for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
  5348. const int e = glyphs.glyphs[end] >> 24;
  5349. if (e == which)
  5350. continue;
  5351. QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
  5352. ti2.width = 0;
  5353. // set the high byte to zero and calc the width
  5354. for (i = start; i < end; ++i) {
  5355. glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
  5356. ti2.width += ti.glyphs.effectiveAdvance(i);
  5357. }
  5358. if (rtl)
  5359. x -= ti2.width.toReal();
  5360. d->engine->drawTextItem(QPointF(x, y), ti2);
  5361. if (!rtl)
  5362. x += ti2.width.toReal();
  5363. // reset the high byte for all glyphs and advance to the next sub-string
  5364. const int hi = which << 24;
  5365. for (i = start; i < end; ++i) {
  5366. glyphs.glyphs[i] = hi | glyphs.glyphs[i];
  5367. }
  5368. // change engine
  5369. start = end;
  5370. which = e;
  5371. }
  5372. QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
  5373. ti2.width = 0;
  5374. // set the high byte to zero and calc the width
  5375. for (i = start; i < end; ++i) {
  5376. glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
  5377. ti2.width += ti.glyphs.effectiveAdvance(i);
  5378. }
  5379. if (rtl)
  5380. x -= ti2.width.toReal();
  5381. if (d->extended)
  5382. d->extended->drawTextItem(QPointF(x, y), ti2);
  5383. else
  5384. d->engine->drawTextItem(QPointF(x,y), ti2);
  5385. // reset the high byte for all glyphs
  5386. const int hi = which << 24;
  5387. for (i = start; i < end; ++i)
  5388. glyphs.glyphs[i] = hi | glyphs.glyphs[i];
  5389. } else {
  5390. if (d->extended)
  5391. d->extended->drawTextItem(p, ti);
  5392. else
  5393. d->engine->drawTextItem(p, ti);
  5394. }
  5395. drawTextItemDecoration(this, p, ti.fontEngine, ti.underlineStyle, ti.flags, ti.width.toReal(),
  5396. ti.charFormat);
  5397. if (d->state->renderHints != oldRenderHints) {
  5398. d->state->renderHints = oldRenderHints;
  5399. if (d->extended)
  5400. d->extended->renderHintsChanged();
  5401. else
  5402. d->state->dirtyFlags |= QPaintEngine::DirtyHints;
  5403. }
  5404. }
  5405. /*!
  5406. \fn QRectF QPainter::boundingRect(const QRectF &rectangle, int flags, const QString &text)
  5407. Returns the bounding rectangle of the \a text as it will appear
  5408. when drawn inside the given \a rectangle with the specified \a
  5409. flags using the currently set font(); i.e the function tells you
  5410. where the drawText() function will draw when given the same
  5411. arguments.
  5412. If the \a text does not fit within the given \a rectangle using
  5413. the specified \a flags, the function returns the required
  5414. rectangle.
  5415. The \a flags argument is a bitwise OR of the following flags:
  5416. \list
  5417. \o Qt::AlignLeft
  5418. \o Qt::AlignRight
  5419. \o Qt::AlignHCenter
  5420. \o Qt::AlignTop
  5421. \o Qt::AlignBottom
  5422. \o Qt::AlignVCenter
  5423. \o Qt::AlignCenter
  5424. \o Qt::TextSingleLine
  5425. \o Qt::TextExpandTabs
  5426. \o Qt::TextShowMnemonic
  5427. \o Qt::TextWordWrap
  5428. \o Qt::TextIncludeTrailingSpaces
  5429. \endlist
  5430. If several of the horizontal or several of the vertical alignment
  5431. flags are set, the resulting alignment is undefined.
  5432. \sa drawText(), Qt::Alignment, Qt::TextFlag
  5433. */
  5434. /*!
  5435. \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
  5436. const QString &text)
  5437. \overload
  5438. Returns the bounding rectangle of the \a text as it will appear
  5439. when drawn inside the given \a rectangle with the specified \a
  5440. flags using the currently set font().
  5441. */
  5442. /*!
  5443. \fn QRect QPainter::boundingRect(int x, int y, int w, int h, int flags,
  5444. const QString &text);
  5445. \overload
  5446. Returns the bounding rectangle of the given \a text as it will
  5447. appear when drawn inside the rectangle beginning at the point
  5448. (\a{x}, \a{y}) with width \a w and height \a h.
  5449. */
  5450. QRect QPainter::boundingRect(const QRect &rect, int flags, const QString &str)
  5451. {
  5452. if (str.isEmpty())
  5453. return QRect(rect.x(),rect.y(), 0,0);
  5454. QRect brect;
  5455. drawText(rect, flags | Qt::TextDontPrint, str, &brect);
  5456. return brect;
  5457. }
  5458. QRectF QPainter::boundingRect(const QRectF &rect, int flags, const QString &str)
  5459. {
  5460. if (str.isEmpty())
  5461. return QRectF(rect.x(),rect.y(), 0,0);
  5462. QRectF brect;
  5463. drawText(rect, flags | Qt::TextDontPrint, str, &brect);
  5464. return brect;
  5465. }
  5466. /*!
  5467. \fn QRectF QPainter::boundingRect(const QRectF &rectangle,
  5468. const QString &text, const QTextOption &option)
  5469. \overload
  5470. Instead of specifying flags as a bitwise OR of the
  5471. Qt::AlignmentFlag and Qt::TextFlag, this overloaded function takes
  5472. an \a option argument. The QTextOption class provides a
  5473. description of general rich text properties.
  5474. \sa QTextOption
  5475. */
  5476. QRectF QPainter::boundingRect(const QRectF &r, const QString &text, const QTextOption &o)
  5477. {
  5478. Q_D(QPainter);
  5479. if (!d->engine || text.length() == 0)
  5480. return QRectF(r.x(),r.y(), 0,0);
  5481. QRectF br;
  5482. qt_format_text(d->state->font, r, Qt::TextDontPrint, &o, text, &br, 0, 0, 0, this);
  5483. return br;
  5484. }
  5485. /*!
  5486. \fn void QPainter::drawTiledPixmap(const QRectF &rectangle, const QPixmap &pixmap, const QPointF &position)
  5487. Draws a tiled \a pixmap, inside the given \a rectangle with its
  5488. origin at the given \a position.
  5489. Calling drawTiledPixmap() is similar to calling drawPixmap()
  5490. several times to fill (tile) an area with a pixmap, but is
  5491. potentially much more efficient depending on the underlying window
  5492. system.
  5493. \sa drawPixmap()
  5494. */
  5495. void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sp)
  5496. {
  5497. #ifdef QT_DEBUG_DRAW
  5498. if (qt_show_painter_debug_output)
  5499. printf("QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
  5500. r.x(), r.y(), r.width(), r.height(),
  5501. pixmap.width(), pixmap.height(),
  5502. sp.x(), sp.y());
  5503. #endif
  5504. Q_D(QPainter);
  5505. if (!d->engine || pixmap.isNull() || r.isEmpty())
  5506. return;
  5507. #ifndef QT_NO_DEBUG
  5508. qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()", true);
  5509. #endif
  5510. qreal sw = pixmap.width();
  5511. qreal sh = pixmap.height();
  5512. qreal sx = sp.x();
  5513. qreal sy = sp.y();
  5514. if (sx < 0)
  5515. sx = qRound(sw) - qRound(-sx) % qRound(sw);
  5516. else
  5517. sx = qRound(sx) % qRound(sw);
  5518. if (sy < 0)
  5519. sy = qRound(sh) - -qRound(sy) % qRound(sh);
  5520. else
  5521. sy = qRound(sy) % qRound(sh);
  5522. if (d->extended) {
  5523. d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
  5524. return;
  5525. }
  5526. if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
  5527. fillRect(r, d->state->bgBrush);
  5528. d->updateState(d->state);
  5529. if ((d->state->matrix.type() > QTransform::TxTranslate
  5530. && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
  5531. || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
  5532. {
  5533. save();
  5534. setBackgroundMode(Qt::TransparentMode);
  5535. setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
  5536. setBrush(QBrush(d->state->pen.color(), pixmap));
  5537. setPen(Qt::NoPen);
  5538. // If there is no rotation involved we have to make sure we use the
  5539. // antialiased and not the aliased coordinate system by rounding the coordinates.
  5540. if (d->state->matrix.type() <= QTransform::TxScale) {
  5541. const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
  5542. if (d->state->matrix.type() <= QTransform::TxTranslate) {
  5543. sx = qRound(sx);
  5544. sy = qRound(sy);
  5545. }
  5546. setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
  5547. drawRect(QRectF(p, r.size()));
  5548. } else {
  5549. setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
  5550. drawRect(r);
  5551. }
  5552. restore();
  5553. return;
  5554. }
  5555. qreal x = r.x();
  5556. qreal y = r.y();
  5557. if (d->state->matrix.type() == QTransform::TxTranslate
  5558. && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
  5559. x += d->state->matrix.dx();
  5560. y += d->state->matrix.dy();
  5561. }
  5562. d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
  5563. }
  5564. /*!
  5565. \fn QPainter::drawTiledPixmap(const QRect &rectangle, const QPixmap &pixmap,
  5566. const QPoint &position = QPoint())
  5567. \overload
  5568. Draws a tiled \a pixmap, inside the given \a rectangle with its
  5569. origin at the given \a position.
  5570. */
  5571. /*!
  5572. \fn void QPainter::drawTiledPixmap(int x, int y, int width, int height, const
  5573. QPixmap &pixmap, int sx, int sy);
  5574. \overload
  5575. Draws a tiled \a pixmap in the specified rectangle.
  5576. (\a{x}, \a{y}) specifies the top-left point in the paint device
  5577. that is to be drawn onto; with the given \a width and \a
  5578. height. (\a{sx}, \a{sy}) specifies the top-left point in the \a
  5579. pixmap that is to be drawn; this defaults to (0, 0).
  5580. */
  5581. #ifndef QT_NO_PICTURE
  5582. /*!
  5583. \fn void QPainter::drawPicture(const QPointF &point, const QPicture &picture)
  5584. Replays the given \a picture at the given \a point.
  5585. The QPicture class is a paint device that records and replays
  5586. QPainter commands. A picture serializes the painter commands to an
  5587. IO device in a platform-independent format. Everything that can be
  5588. painted on a widget or pixmap can also be stored in a picture.
  5589. This function does exactly the same as QPicture::play() when
  5590. called with \a point = QPoint(0, 0).
  5591. \table 100%
  5592. \row
  5593. \o
  5594. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 18
  5595. \endtable
  5596. \sa QPicture::play()
  5597. */
  5598. void QPainter::drawPicture(const QPointF &p, const QPicture &picture)
  5599. {
  5600. Q_D(QPainter);
  5601. if (!d->engine)
  5602. return;
  5603. if (!d->extended)
  5604. d->updateState(d->state);
  5605. save();
  5606. translate(p);
  5607. const_cast<QPicture *>(&picture)->play(this);
  5608. restore();
  5609. }
  5610. /*!
  5611. \fn void QPainter::drawPicture(const QPoint &point, const QPicture &picture)
  5612. \overload
  5613. Replays the given \a picture at the given \a point.
  5614. */
  5615. /*!
  5616. \fn void QPainter::drawPicture(int x, int y, const QPicture &picture)
  5617. \overload
  5618. Draws the given \a picture at point (\a x, \a y).
  5619. */
  5620. #endif // QT_NO_PICTURE
  5621. /*!
  5622. \fn void QPainter::eraseRect(const QRectF &rectangle)
  5623. Erases the area inside the given \a rectangle. Equivalent to
  5624. calling
  5625. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 19
  5626. \sa fillRect()
  5627. */
  5628. void QPainter::eraseRect(const QRectF &r)
  5629. {
  5630. Q_D(QPainter);
  5631. fillRect(r, d->state->bgBrush);
  5632. }
  5633. static inline bool needsResolving(const QBrush &brush)
  5634. {
  5635. Qt::BrushStyle s = brush.style();
  5636. return ((s == Qt::LinearGradientPattern || s == Qt::RadialGradientPattern ||
  5637. s == Qt::ConicalGradientPattern) &&
  5638. brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode);
  5639. }
  5640. /*!
  5641. \fn void QPainter::eraseRect(const QRect &rectangle)
  5642. \overload
  5643. Erases the area inside the given \a rectangle.
  5644. */
  5645. /*!
  5646. \fn void QPainter::eraseRect(int x, int y, int width, int height)
  5647. \overload
  5648. Erases the area inside the rectangle beginning at (\a x, \a y)
  5649. with the given \a width and \a height.
  5650. */
  5651. /*!
  5652. \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::BrushStyle style)
  5653. \overload
  5654. Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
  5655. width and \a height, using the brush \a style specified.
  5656. \since 4.5
  5657. */
  5658. /*!
  5659. \fn void QPainter::fillRect(const QRect &rectangle, Qt::BrushStyle style)
  5660. \overload
  5661. Fills the given \a rectangle with the brush \a style specified.
  5662. \since 4.5
  5663. */
  5664. /*!
  5665. \fn void QPainter::fillRect(const QRectF &rectangle, Qt::BrushStyle style)
  5666. \overload
  5667. Fills the given \a rectangle with the brush \a style specified.
  5668. \since 4.5
  5669. */
  5670. /*!
  5671. \fn void QPainter::fillRect(const QRectF &rectangle, const QBrush &brush)
  5672. Fills the given \a rectangle with the \a brush specified.
  5673. Alternatively, you can specify a QColor instead of a QBrush; the
  5674. QBrush constructor (taking a QColor argument) will automatically
  5675. create a solid pattern brush.
  5676. \sa drawRect()
  5677. */
  5678. void QPainter::fillRect(const QRectF &r, const QBrush &brush)
  5679. {
  5680. Q_D(QPainter);
  5681. if (!d->engine)
  5682. return;
  5683. if (d->extended) {
  5684. const QGradient *g = brush.gradient();
  5685. if (!g || g->coordinateMode() == QGradient::LogicalMode) {
  5686. d->extended->fillRect(r, brush);
  5687. return;
  5688. }
  5689. }
  5690. QPen oldPen = pen();
  5691. QBrush oldBrush = this->brush();
  5692. setPen(Qt::NoPen);
  5693. if (brush.style() == Qt::SolidPattern) {
  5694. d->colorBrush.setStyle(Qt::SolidPattern);
  5695. d->colorBrush.setColor(brush.color());
  5696. setBrush(d->colorBrush);
  5697. } else {
  5698. setBrush(brush);
  5699. }
  5700. drawRect(r);
  5701. setBrush(oldBrush);
  5702. setPen(oldPen);
  5703. }
  5704. /*!
  5705. \fn void QPainter::fillRect(const QRect &rectangle, const QBrush &brush)
  5706. \overload
  5707. Fills the given \a rectangle with the specified \a brush.
  5708. */
  5709. void QPainter::fillRect(const QRect &r, const QBrush &brush)
  5710. {
  5711. Q_D(QPainter);
  5712. if (!d->engine)
  5713. return;
  5714. if (d->extended) {
  5715. const QGradient *g = brush.gradient();
  5716. if (!g || g->coordinateMode() == QGradient::LogicalMode) {
  5717. d->extended->fillRect(r, brush);
  5718. return;
  5719. }
  5720. }
  5721. QPen oldPen = pen();
  5722. QBrush oldBrush = this->brush();
  5723. setPen(Qt::NoPen);
  5724. if (brush.style() == Qt::SolidPattern) {
  5725. d->colorBrush.setStyle(Qt::SolidPattern);
  5726. d->colorBrush.setColor(brush.color());
  5727. setBrush(d->colorBrush);
  5728. } else {
  5729. setBrush(brush);
  5730. }
  5731. drawRect(r);
  5732. setBrush(oldBrush);
  5733. setPen(oldPen);
  5734. }
  5735. /*!
  5736. \fn void QPainter::fillRect(const QRect &rectangle, const QColor &color)
  5737. \overload
  5738. Fills the given \a rectangle with the \a color specified.
  5739. \since 4.5
  5740. */
  5741. void QPainter::fillRect(const QRect &r, const QColor &color)
  5742. {
  5743. Q_D(QPainter);
  5744. if (!d->engine)
  5745. return;
  5746. if (d->extended) {
  5747. d->extended->fillRect(r, color);
  5748. return;
  5749. }
  5750. fillRect(r, QBrush(color));
  5751. }
  5752. /*!
  5753. \fn void QPainter::fillRect(const QRectF &rectangle, const QColor &color)
  5754. \overload
  5755. Fills the given \a rectangle with the \a color specified.
  5756. \since 4.5
  5757. */
  5758. void QPainter::fillRect(const QRectF &r, const QColor &color)
  5759. {
  5760. Q_D(QPainter);
  5761. if (!d->engine)
  5762. return;
  5763. if (d->extended) {
  5764. d->extended->fillRect(r, color);
  5765. return;
  5766. }
  5767. fillRect(r, QBrush(color));
  5768. }
  5769. /*!
  5770. \fn void QPainter::fillRect(int x, int y, int width, int height, const QBrush &brush)
  5771. \overload
  5772. Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
  5773. width and \a height, using the given \a brush.
  5774. */
  5775. /*!
  5776. \fn void QPainter::fillRect(int x, int y, int width, int height, const QColor &color)
  5777. \overload
  5778. Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
  5779. width and \a height, using the given \a color.
  5780. \since 4.5
  5781. */
  5782. /*!
  5783. \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::GlobalColor color)
  5784. \overload
  5785. Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
  5786. width and \a height, using the given \a color.
  5787. \since 4.5
  5788. */
  5789. /*!
  5790. \fn void QPainter::fillRect(const QRect &rectangle, Qt::GlobalColor color);
  5791. \overload
  5792. Fills the given \a rectangle with the specified \a color.
  5793. \since 4.5
  5794. */
  5795. /*!
  5796. \fn void QPainter::fillRect(const QRectF &rectangle, Qt::GlobalColor color);
  5797. \overload
  5798. Fills the given \a rectangle with the specified \a color.
  5799. \since 4.5
  5800. */
  5801. /*!
  5802. Sets the given render \a hint on the painter if \a on is true;
  5803. otherwise clears the render hint.
  5804. \sa setRenderHints(), renderHints(), {QPainter#Rendering
  5805. Quality}{Rendering Quality}
  5806. */
  5807. void QPainter::setRenderHint(RenderHint hint, bool on)
  5808. {
  5809. #ifdef QT_DEBUG_DRAW
  5810. if (qt_show_painter_debug_output)
  5811. printf("QPainter::setRenderHint: hint=%x, %s\n", hint, on ? "on" : "off");
  5812. #endif
  5813. #ifndef QT_NO_DEBUG
  5814. static const bool antialiasingDisabled = qgetenv("QT_NO_ANTIALIASING").toInt();
  5815. if (hint == QPainter::Antialiasing && antialiasingDisabled)
  5816. return;
  5817. #endif
  5818. setRenderHints(hint, on);
  5819. }
  5820. /*!
  5821. \since 4.2
  5822. Sets the given render \a hints on the painter if \a on is true;
  5823. otherwise clears the render hints.
  5824. \sa setRenderHint(), renderHints(), {QPainter#Rendering
  5825. Quality}{Rendering Quality}
  5826. */
  5827. void QPainter::setRenderHints(RenderHints hints, bool on)
  5828. {
  5829. Q_D(QPainter);
  5830. if (!d->engine) {
  5831. qWarning("QPainter::setRenderHint: Painter must be active to set rendering hints");
  5832. return;
  5833. }
  5834. if (on)
  5835. d->state->renderHints |= hints;
  5836. else
  5837. d->state->renderHints &= ~hints;
  5838. if (d->extended)
  5839. d->extended->renderHintsChanged();
  5840. else
  5841. d->state->dirtyFlags |= QPaintEngine::DirtyHints;
  5842. }
  5843. /*!
  5844. Returns a flag that specifies the rendering hints that are set for
  5845. this painter.
  5846. \sa testRenderHint(), {QPainter#Rendering Quality}{Rendering Quality}
  5847. */
  5848. QPainter::RenderHints QPainter::renderHints() const
  5849. {
  5850. Q_D(const QPainter);
  5851. if (!d->engine)
  5852. return 0;
  5853. return d->state->renderHints;
  5854. }
  5855. /*!
  5856. \fn bool QPainter::testRenderHint(RenderHint hint) const
  5857. \since 4.3
  5858. Returns true if \a hint is set; otherwise returns false.
  5859. \sa renderHints(), setRenderHint()
  5860. */
  5861. /*!
  5862. Returns true if view transformation is enabled; otherwise returns
  5863. false.
  5864. \sa setViewTransformEnabled(), worldTransform()
  5865. */
  5866. bool QPainter::viewTransformEnabled() const
  5867. {
  5868. Q_D(const QPainter);
  5869. if (!d->engine) {
  5870. qWarning("QPainter::viewTransformEnabled: Painter not active");
  5871. return false;
  5872. }
  5873. return d->state->VxF;
  5874. }
  5875. /*!
  5876. \fn void QPainter::setWindow(const QRect &rectangle)
  5877. Sets the painter's window to the given \a rectangle, and enables
  5878. view transformations.
  5879. The window rectangle is part of the view transformation. The
  5880. window specifies the logical coordinate system. Its sister, the
  5881. viewport(), specifies the device coordinate system.
  5882. The default window rectangle is the same as the device's
  5883. rectangle.
  5884. \sa window(), viewTransformEnabled(), {Coordinate
  5885. System#Window-Viewport Conversion}{Window-Viewport Conversion}
  5886. */
  5887. /*!
  5888. \fn void QPainter::setWindow(int x, int y, int width, int height)
  5889. \overload
  5890. Sets the painter's window to the rectangle beginning at (\a x, \a
  5891. y) and the given \a width and \a height.
  5892. */
  5893. void QPainter::setWindow(const QRect &r)
  5894. {
  5895. #ifdef QT_DEBUG_DRAW
  5896. if (qt_show_painter_debug_output)
  5897. printf("QPainter::setWindow(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
  5898. #endif
  5899. Q_D(QPainter);
  5900. if (!d->engine) {
  5901. qWarning("QPainter::setWindow: Painter not active");
  5902. return;
  5903. }
  5904. d->state->wx = r.x();
  5905. d->state->wy = r.y();
  5906. d->state->ww = r.width();
  5907. d->state->wh = r.height();
  5908. d->state->VxF = true;
  5909. d->updateMatrix();
  5910. }
  5911. /*!
  5912. Returns the window rectangle.
  5913. \sa setWindow(), setViewTransformEnabled()
  5914. */
  5915. QRect QPainter::window() const
  5916. {
  5917. Q_D(const QPainter);
  5918. if (!d->engine) {
  5919. qWarning("QPainter::window: Painter not active");
  5920. return QRect();
  5921. }
  5922. return QRect(d->state->wx, d->state->wy, d->state->ww, d->state->wh);
  5923. }
  5924. /*!
  5925. \fn void QPainter::setViewport(const QRect &rectangle)
  5926. Sets the painter's viewport rectangle to the given \a rectangle,
  5927. and enables view transformations.
  5928. The viewport rectangle is part of the view transformation. The
  5929. viewport specifies the device coordinate system. Its sister, the
  5930. window(), specifies the logical coordinate system.
  5931. The default viewport rectangle is the same as the device's
  5932. rectangle.
  5933. \sa viewport(), viewTransformEnabled() {Coordinate
  5934. System#Window-Viewport Conversion}{Window-Viewport Conversion}
  5935. */
  5936. /*!
  5937. \fn void QPainter::setViewport(int x, int y, int width, int height)
  5938. \overload
  5939. Sets the painter's viewport rectangle to be the rectangle
  5940. beginning at (\a x, \a y) with the given \a width and \a height.
  5941. */
  5942. void QPainter::setViewport(const QRect &r)
  5943. {
  5944. #ifdef QT_DEBUG_DRAW
  5945. if (qt_show_painter_debug_output)
  5946. printf("QPainter::setViewport(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
  5947. #endif
  5948. Q_D(QPainter);
  5949. if (!d->engine) {
  5950. qWarning("QPainter::setViewport: Painter not active");
  5951. return;
  5952. }
  5953. d->state->vx = r.x();
  5954. d->state->vy = r.y();
  5955. d->state->vw = r.width();
  5956. d->state->vh = r.height();
  5957. d->state->VxF = true;
  5958. d->updateMatrix();
  5959. }
  5960. /*!
  5961. Returns the viewport rectangle.
  5962. \sa setViewport(), setViewTransformEnabled()
  5963. */
  5964. QRect QPainter::viewport() const
  5965. {
  5966. Q_D(const QPainter);
  5967. if (!d->engine) {
  5968. qWarning("QPainter::viewport: Painter not active");
  5969. return QRect();
  5970. }
  5971. return QRect(d->state->vx, d->state->vy, d->state->vw, d->state->vh);
  5972. }
  5973. /*! \fn bool QPainter::hasViewXForm() const
  5974. \compat
  5975. Use viewTransformEnabled() instead.
  5976. */
  5977. /*! \fn bool QPainter::hasWorldXForm() const
  5978. \compat
  5979. Use worldMatrixEnabled() instead.
  5980. */
  5981. /*! \fn void QPainter::resetXForm()
  5982. \compat
  5983. Use resetTransform() instead.
  5984. */
  5985. /*! \fn void QPainter::setViewXForm(bool enabled)
  5986. \compat
  5987. Use setViewTransformEnabled() instead.
  5988. */
  5989. /*! \fn void QPainter::setWorldXForm(bool enabled)
  5990. \compat
  5991. Use setWorldMatrixEnabled() instead.
  5992. */
  5993. /*!
  5994. Enables view transformations if \a enable is true, or disables
  5995. view transformations if \a enable is false.
  5996. \sa viewTransformEnabled(), {Coordinate System#Window-Viewport
  5997. Conversion}{Window-Viewport Conversion}
  5998. */
  5999. void QPainter::setViewTransformEnabled(bool enable)
  6000. {
  6001. #ifdef QT_DEBUG_DRAW
  6002. if (qt_show_painter_debug_output)
  6003. printf("QPainter::setViewTransformEnabled(), enable=%d\n", enable);
  6004. #endif
  6005. Q_D(QPainter);
  6006. if (!d->engine) {
  6007. qWarning("QPainter::setViewTransformEnabled: Painter not active");
  6008. return;
  6009. }
  6010. if (enable == d->state->VxF)
  6011. return;
  6012. d->state->VxF = enable;
  6013. d->updateMatrix();
  6014. }
  6015. #ifdef QT3_SUPPORT
  6016. /*!
  6017. \obsolete
  6018. Use the worldTransform() combined with QTransform::dx() instead.
  6019. \oldcode
  6020. QPainter painter(this);
  6021. qreal x = painter.translationX();
  6022. \newcode
  6023. QPainter painter(this);
  6024. qreal x = painter.worldTransform().dx();
  6025. \endcode
  6026. */
  6027. qreal QPainter::translationX() const
  6028. {
  6029. Q_D(const QPainter);
  6030. if (!d->engine) {
  6031. qWarning("QPainter::translationX: Painter not active");
  6032. return 0.0;
  6033. }
  6034. return d->state->worldMatrix.dx();
  6035. }
  6036. /*!
  6037. \obsolete
  6038. Use the worldTransform() combined with QTransform::dy() instead.
  6039. \oldcode
  6040. QPainter painter(this);
  6041. qreal y = painter.translationY();
  6042. \newcode
  6043. QPainter painter(this);
  6044. qreal y = painter.worldTransform().dy();
  6045. \endcode
  6046. */
  6047. qreal QPainter::translationY() const
  6048. {
  6049. Q_D(const QPainter);
  6050. if (!d->engine) {
  6051. qWarning("QPainter::translationY: Painter not active");
  6052. return 0.0;
  6053. }
  6054. return d->state->worldMatrix.dy();
  6055. }
  6056. /*!
  6057. \fn void QPainter::map(int x, int y, int *rx, int *ry) const
  6058. \internal
  6059. Sets (\a{rx}, \a{ry}) to the point that results from applying the
  6060. painter's current transformation on the point (\a{x}, \a{y}).
  6061. */
  6062. void QPainter::map(int x, int y, int *rx, int *ry) const
  6063. {
  6064. QPoint p(x, y);
  6065. p = p * combinedMatrix();
  6066. *rx = p.x();
  6067. *ry = p.y();
  6068. }
  6069. /*!
  6070. \fn QPoint QPainter::xForm(const QPoint &point) const
  6071. Use combinedTransform() instead.
  6072. */
  6073. QPoint QPainter::xForm(const QPoint &p) const
  6074. {
  6075. Q_D(const QPainter);
  6076. if (!d->engine) {
  6077. qWarning("QPainter::xForm: Painter not active");
  6078. return QPoint();
  6079. }
  6080. if (d->state->matrix.type() == QTransform::TxNone)
  6081. return p;
  6082. return p * combinedMatrix();
  6083. }
  6084. /*!
  6085. \fn QRect QPainter::xForm(const QRect &rectangle) const
  6086. \overload
  6087. Use combinedTransform() instead of this function and call
  6088. mapRect() on the result to obtain a QRect.
  6089. */
  6090. QRect QPainter::xForm(const QRect &r) const
  6091. {
  6092. Q_D(const QPainter);
  6093. if (!d->engine) {
  6094. qWarning("QPainter::xForm: Painter not active");
  6095. return QRect();
  6096. }
  6097. if (d->state->matrix.type() == QTransform::TxNone)
  6098. return r;
  6099. return combinedMatrix().mapRect(r);
  6100. }
  6101. /*!
  6102. \fn QPolygon QPainter::xForm(const QPolygon &polygon) const
  6103. \overload
  6104. Use combinedTransform() instead.
  6105. */
  6106. QPolygon QPainter::xForm(const QPolygon &a) const
  6107. {
  6108. Q_D(const QPainter);
  6109. if (!d->engine) {
  6110. qWarning("QPainter::xForm: Painter not active");
  6111. return QPolygon();
  6112. }
  6113. if (d->state->matrix.type() == QTransform::TxNone)
  6114. return a;
  6115. return a * combinedMatrix();
  6116. }
  6117. /*!
  6118. \fn QPolygon QPainter::xForm(const QPolygon &polygon, int index, int count) const
  6119. \overload
  6120. Use combinedTransform() combined with QPolygon::mid() instead.
  6121. \oldcode
  6122. QPainter painter(this);
  6123. QPolygon transformed = painter.xForm(polygon, index, count)
  6124. \newcode
  6125. QPainter painter(this);
  6126. QPolygon transformed = polygon.mid(index, count) * painter.combinedTransform();
  6127. \endcode
  6128. */
  6129. QPolygon QPainter::xForm(const QPolygon &av, int index, int npoints) const
  6130. {
  6131. int lastPoint = npoints < 0 ? av.size() : index+npoints;
  6132. QPolygon a(lastPoint-index);
  6133. memcpy(a.data(), av.data()+index, (lastPoint-index)*sizeof(QPoint));
  6134. return a * combinedMatrix();
  6135. }
  6136. /*!
  6137. \fn QPoint QPainter::xFormDev(const QPoint &point) const
  6138. \overload
  6139. \obsolete
  6140. Use combinedTransform() combined with QTransform::inverted() instead.
  6141. \oldcode
  6142. QPainter painter(this);
  6143. QPoint transformed = painter.xFormDev(point);
  6144. \newcode
  6145. QPainter painter(this);
  6146. QPoint transformed = point * painter.combinedTransform().inverted();
  6147. \endcode
  6148. */
  6149. QPoint QPainter::xFormDev(const QPoint &p) const
  6150. {
  6151. Q_D(const QPainter);
  6152. if (!d->engine) {
  6153. qWarning("QPainter::xFormDev: Painter not active");
  6154. return QPoint();
  6155. }
  6156. if(d->state->matrix.type() == QTransform::TxNone)
  6157. return p;
  6158. return p * combinedMatrix().inverted();
  6159. }
  6160. /*!
  6161. \fn QRect QPainter::xFormDev(const QRect &rectangle) const
  6162. \overload
  6163. \obsolete
  6164. Use combinedTransform() combined with QTransform::inverted() instead.
  6165. \oldcode
  6166. QPainter painter(this);
  6167. QRect transformed = painter.xFormDev(rectangle);
  6168. \newcode
  6169. QPainter painter(this);
  6170. QRegion region = QRegion(rectangle) * painter.combinedTransform().inverted();
  6171. QRect transformed = region.boundingRect();
  6172. \endcode
  6173. */
  6174. QRect QPainter::xFormDev(const QRect &r) const
  6175. {
  6176. Q_D(const QPainter);
  6177. if (!d->engine) {
  6178. qWarning("QPainter::xFormDev: Painter not active");
  6179. return QRect();
  6180. }
  6181. if (d->state->matrix.type() == QTransform::TxNone)
  6182. return r;
  6183. return combinedMatrix().inverted().mapRect(r);
  6184. }
  6185. /*!
  6186. \overload
  6187. \fn QPoint QPainter::xFormDev(const QPolygon &polygon) const
  6188. \obsolete
  6189. Use combinedTransform() combined with QTransform::inverted() instead.
  6190. \oldcode
  6191. QPainter painter(this);
  6192. QPolygon transformed = painter.xFormDev(rectangle);
  6193. \newcode
  6194. QPainter painter(this);
  6195. QPolygon transformed = polygon * painter.combinedTransform().inverted();
  6196. \endcode
  6197. */
  6198. QPolygon QPainter::xFormDev(const QPolygon &a) const
  6199. {
  6200. Q_D(const QPainter);
  6201. if (!d->engine) {
  6202. qWarning("QPainter::xFormDev: Painter not active");
  6203. return QPolygon();
  6204. }
  6205. if (d->state->matrix.type() == QTransform::TxNone)
  6206. return a;
  6207. return a * combinedMatrix().inverted();
  6208. }
  6209. /*!
  6210. \fn QPolygon QPainter::xFormDev(const QPolygon &polygon, int index, int count) const
  6211. \overload
  6212. \obsolete
  6213. Use combinedTransform() combined with QPolygon::mid() and QTransform::inverted() instead.
  6214. \oldcode
  6215. QPainter painter(this);
  6216. QPolygon transformed = painter.xFormDev(polygon, index, count);
  6217. \newcode
  6218. QPainter painter(this);
  6219. QPolygon transformed = polygon.mid(index, count) * painter.combinedTransform().inverted();
  6220. \endcode
  6221. */
  6222. QPolygon QPainter::xFormDev(const QPolygon &ad, int index, int npoints) const
  6223. {
  6224. Q_D(const QPainter);
  6225. int lastPoint = npoints < 0 ? ad.size() : index+npoints;
  6226. QPolygon a(lastPoint-index);
  6227. memcpy(a.data(), ad.data()+index, (lastPoint-index)*sizeof(QPoint));
  6228. if (d->state->matrix.type() == QTransform::TxNone)
  6229. return a;
  6230. return a * combinedMatrix().inverted();
  6231. }
  6232. /*!
  6233. \fn void QPainter::drawCubicBezier(const QPolygon &controlPoints, int index)
  6234. Draws a cubic Bezier curve defined by the \a controlPoints,
  6235. starting at \a{controlPoints}\e{[index]} (\a index defaults to 0).
  6236. Points after \a{controlPoints}\e{[index + 3]} are ignored. Nothing
  6237. happens if there aren't enough control points.
  6238. Use strokePath() instead.
  6239. \oldcode
  6240. QPainter painter(this);
  6241. painter.drawCubicBezier(controlPoints, index)
  6242. \newcode
  6243. QPainterPath path;
  6244. path.moveTo(controlPoints.at(index));
  6245. path.cubicTo(controlPoints.at(index+1),
  6246. controlPoints.at(index+2),
  6247. controlPoints.at(index+3));
  6248. QPainter painter(this);
  6249. painter.strokePath(path, painter.pen());
  6250. \endcode
  6251. */
  6252. void QPainter::drawCubicBezier(const QPolygon &a, int index)
  6253. {
  6254. Q_D(QPainter);
  6255. if (!d->engine)
  6256. return;
  6257. if ((int)a.size() - index < 4) {
  6258. qWarning("QPainter::drawCubicBezier: Cubic Bezier needs 4 control "
  6259. "points");
  6260. return;
  6261. }
  6262. QPainterPath path;
  6263. path.moveTo(a.at(index));
  6264. path.cubicTo(a.at(index+1), a.at(index+2), a.at(index+3));
  6265. strokePath(path, d->state->pen);
  6266. }
  6267. #endif
  6268. struct QPaintDeviceRedirection
  6269. {
  6270. QPaintDeviceRedirection() : device(0), replacement(0), internalWidgetRedirectionIndex(-1) {}
  6271. QPaintDeviceRedirection(const QPaintDevice *device, QPaintDevice *replacement,
  6272. const QPoint& offset, int internalWidgetRedirectionIndex)
  6273. : device(device), replacement(replacement), offset(offset),
  6274. internalWidgetRedirectionIndex(internalWidgetRedirectionIndex) { }
  6275. const QPaintDevice *device;
  6276. QPaintDevice *replacement;
  6277. QPoint offset;
  6278. int internalWidgetRedirectionIndex;
  6279. bool operator==(const QPaintDevice *pdev) const { return device == pdev; }
  6280. Q_DUMMY_COMPARISON_OPERATOR(QPaintDeviceRedirection)
  6281. };
  6282. typedef QList<QPaintDeviceRedirection> QPaintDeviceRedirectionList;
  6283. Q_GLOBAL_STATIC(QPaintDeviceRedirectionList, globalRedirections)
  6284. Q_GLOBAL_STATIC(QMutex, globalRedirectionsMutex)
  6285. Q_GLOBAL_STATIC(QAtomicInt, globalRedirectionAtomic)
  6286. /*!
  6287. \threadsafe
  6288. \obsolete
  6289. Please use QWidget::render() instead.
  6290. Redirects all paint commands for the given paint \a device, to the
  6291. \a replacement device. The optional point \a offset defines an
  6292. offset within the source device.
  6293. The redirection will not be effective until the begin() function
  6294. has been called; make sure to call end() for the given \a
  6295. device's painter (if any) before redirecting. Call
  6296. restoreRedirected() to restore the previous redirection.
  6297. \warning Making use of redirections in the QPainter API implies
  6298. that QPainter::begin() and QPaintDevice destructors need to hold
  6299. a mutex for a short period. This can impact performance. Use of
  6300. QWidget::render is strongly encouraged.
  6301. \sa redirected(), restoreRedirected()
  6302. */
  6303. void QPainter::setRedirected(const QPaintDevice *device,
  6304. QPaintDevice *replacement,
  6305. const QPoint &offset)
  6306. {
  6307. Q_ASSERT(device != 0);
  6308. bool hadInternalWidgetRedirection = false;
  6309. if (device->devType() == QInternal::Widget) {
  6310. const QWidgetPrivate *widgetPrivate = static_cast<const QWidget *>(device)->d_func();
  6311. // This is the case when the widget is in a paint event.
  6312. if (widgetPrivate->redirectDev) {
  6313. // Remove internal redirection and put it back into the global redirection list.
  6314. QPoint oldOffset;
  6315. QPaintDevice *oldReplacement = widgetPrivate->redirected(&oldOffset);
  6316. const_cast<QWidgetPrivate *>(widgetPrivate)->restoreRedirected();
  6317. setRedirected(device, oldReplacement, oldOffset);
  6318. hadInternalWidgetRedirection = true;
  6319. }
  6320. }
  6321. QPoint roffset;
  6322. QPaintDevice *rdev = redirected(replacement, &roffset);
  6323. QMutexLocker locker(globalRedirectionsMutex());
  6324. QPaintDeviceRedirectionList *redirections = globalRedirections();
  6325. Q_ASSERT(redirections != 0);
  6326. *redirections += QPaintDeviceRedirection(device, rdev ? rdev : replacement, offset + roffset,
  6327. hadInternalWidgetRedirection ? redirections->size() - 1 : -1);
  6328. globalRedirectionAtomic()->ref();
  6329. }
  6330. /*!
  6331. \threadsafe
  6332. \obsolete
  6333. Using QWidget::render() obsoletes the use of this function.
  6334. Restores the previous redirection for the given \a device after a
  6335. call to setRedirected().
  6336. \warning Making use of redirections in the QPainter API implies
  6337. that QPainter::begin() and QPaintDevice destructors need to hold
  6338. a mutex for a short period. This can impact performance. Use of
  6339. QWidget::render is strongly encouraged.
  6340. \sa redirected()
  6341. */
  6342. void QPainter::restoreRedirected(const QPaintDevice *device)
  6343. {
  6344. Q_ASSERT(device != 0);
  6345. QMutexLocker locker(globalRedirectionsMutex());
  6346. QPaintDeviceRedirectionList *redirections = globalRedirections();
  6347. Q_ASSERT(redirections != 0);
  6348. for (int i = redirections->size()-1; i >= 0; --i) {
  6349. if (redirections->at(i) == device) {
  6350. globalRedirectionAtomic()->deref();
  6351. const int internalWidgetRedirectionIndex = redirections->at(i).internalWidgetRedirectionIndex;
  6352. redirections->removeAt(i);
  6353. // Restore the internal widget redirection, i.e. remove it from the global
  6354. // redirection list and put it back into QWidgetPrivate. The index is only set when
  6355. // someone call QPainter::setRedirected in a widget's paint event and we internally
  6356. // have a redirection set (typically set in QWidgetPrivate::drawWidget).
  6357. if (internalWidgetRedirectionIndex >= 0) {
  6358. Q_ASSERT(internalWidgetRedirectionIndex < redirections->size());
  6359. const QPaintDeviceRedirection &redirectionDevice = redirections->at(internalWidgetRedirectionIndex);
  6360. QWidget *widget = static_cast<QWidget *>(const_cast<QPaintDevice *>(device));
  6361. widget->d_func()->setRedirected(redirectionDevice.replacement, redirectionDevice.offset);
  6362. redirections->removeAt(internalWidgetRedirectionIndex);
  6363. }
  6364. return;
  6365. }
  6366. }
  6367. }
  6368. /*!
  6369. \threadsafe
  6370. \obsolete
  6371. Using QWidget::render() obsoletes the use of this function.
  6372. Returns the replacement for given \a device. The optional out
  6373. parameter \a offset returns the offset within the replaced device.
  6374. \warning Making use of redirections in the QPainter API implies
  6375. that QPainter::begin() and QPaintDevice destructors need to hold
  6376. a mutex for a short period. This can impact performance. Use of
  6377. QWidget::render is strongly encouraged.
  6378. \sa setRedirected(), restoreRedirected()
  6379. */
  6380. QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset)
  6381. {
  6382. Q_ASSERT(device != 0);
  6383. if (device->devType() == QInternal::Widget) {
  6384. const QWidgetPrivate *widgetPrivate = static_cast<const QWidget *>(device)->d_func();
  6385. if (widgetPrivate->redirectDev)
  6386. return widgetPrivate->redirected(offset);
  6387. }
  6388. if (!globalRedirectionAtomic() || *globalRedirectionAtomic() == 0)
  6389. return 0;
  6390. QMutexLocker locker(globalRedirectionsMutex());
  6391. QPaintDeviceRedirectionList *redirections = globalRedirections();
  6392. Q_ASSERT(redirections != 0);
  6393. for (int i = redirections->size()-1; i >= 0; --i)
  6394. if (redirections->at(i) == device) {
  6395. if (offset)
  6396. *offset = redirections->at(i).offset;
  6397. return redirections->at(i).replacement;
  6398. }
  6399. if (offset)
  6400. *offset = QPoint(0, 0);
  6401. return 0;
  6402. }
  6403. void qt_painter_removePaintDevice(QPaintDevice *dev)
  6404. {
  6405. if (!globalRedirectionAtomic() || *globalRedirectionAtomic() == 0)
  6406. return;
  6407. QMutex *mutex = 0;
  6408. QT_TRY {
  6409. mutex = globalRedirectionsMutex();
  6410. } QT_CATCH(...) {
  6411. // ignore the missing mutex, since we could be called from
  6412. // a destructor, and destructors shall not throw
  6413. }
  6414. QMutexLocker locker(mutex);
  6415. QPaintDeviceRedirectionList *redirections = 0;
  6416. QT_TRY {
  6417. redirections = globalRedirections();
  6418. } QT_CATCH(...) {
  6419. // do nothing - code below is safe with redirections being 0.
  6420. }
  6421. if (redirections) {
  6422. for (int i = 0; i < redirections->size(); ) {
  6423. if(redirections->at(i) == dev || redirections->at(i).replacement == dev)
  6424. redirections->removeAt(i);
  6425. else
  6426. ++i;
  6427. }
  6428. }
  6429. }
  6430. void qt_format_text(const QFont &fnt, const QRectF &_r,
  6431. int tf, const QString& str, QRectF *brect,
  6432. int tabstops, int *ta, int tabarraylen,
  6433. QPainter *painter)
  6434. {
  6435. qt_format_text(fnt, _r,
  6436. tf, 0, str, brect,
  6437. tabstops, ta, tabarraylen,
  6438. painter);
  6439. }
  6440. void qt_format_text(const QFont &fnt, const QRectF &_r,
  6441. int tf, const QTextOption *option, const QString& str, QRectF *brect,
  6442. int tabstops, int *ta, int tabarraylen,
  6443. QPainter *painter)
  6444. {
  6445. Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=0) ); // we either have an option or flags
  6446. if (option) {
  6447. tf |= option->alignment();
  6448. if (option->wrapMode() != QTextOption::NoWrap)
  6449. tf |= Qt::TextWordWrap;
  6450. if (option->flags() & QTextOption::IncludeTrailingSpaces)
  6451. tf |= Qt::TextIncludeTrailingSpaces;
  6452. if (option->tabStop() >= 0 || !option->tabArray().isEmpty())
  6453. tf |= Qt::TextExpandTabs;
  6454. }
  6455. // we need to copy r here to protect against the case (&r == brect).
  6456. QRectF r(_r);
  6457. bool dontclip = (tf & Qt::TextDontClip);
  6458. bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
  6459. bool singleline = (tf & Qt::TextSingleLine);
  6460. bool showmnemonic = (tf & Qt::TextShowMnemonic);
  6461. bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
  6462. Qt::LayoutDirection layout_direction;
  6463. if (tf & Qt::TextForceLeftToRight)
  6464. layout_direction = Qt::LeftToRight;
  6465. else if (tf & Qt::TextForceRightToLeft)
  6466. layout_direction = Qt::RightToLeft;
  6467. else if (option)
  6468. layout_direction = option->textDirection();
  6469. else if (painter)
  6470. layout_direction = painter->layoutDirection();
  6471. else
  6472. layout_direction = Qt::LeftToRight;
  6473. tf = QStyle::visualAlignment(layout_direction, QFlag(tf));
  6474. bool isRightToLeft = layout_direction == Qt::RightToLeft;
  6475. bool expandtabs = ((tf & Qt::TextExpandTabs) &&
  6476. (((tf & Qt::AlignLeft) && !isRightToLeft) ||
  6477. ((tf & Qt::AlignRight) && isRightToLeft)));
  6478. if (!painter)
  6479. tf |= Qt::TextDontPrint;
  6480. uint maxUnderlines = 0;
  6481. int numUnderlines = 0;
  6482. QVarLengthArray<int, 32> underlinePositions(1);
  6483. QFontMetricsF fm(fnt);
  6484. QString text = str;
  6485. int offset = 0;
  6486. start_lengthVariant:
  6487. bool hasMoreLengthVariants = false;
  6488. // compatible behaviour to the old implementation. Replace
  6489. // tabs by spaces
  6490. int old_offset = offset;
  6491. for (; offset < text.length(); offset++) {
  6492. QChar chr = text.at(offset);
  6493. if (chr == QLatin1Char('\r') || (singleline && chr == QLatin1Char('\n'))) {
  6494. text[offset] = QLatin1Char(' ');
  6495. } else if (chr == QLatin1Char('\n')) {
  6496. text[offset] = QChar::LineSeparator;
  6497. } else if (chr == QLatin1Char('&')) {
  6498. ++maxUnderlines;
  6499. } else if (chr == QLatin1Char('\t')) {
  6500. if (!expandtabs) {
  6501. text[offset] = QLatin1Char(' ');
  6502. } else if (!tabarraylen && !tabstops) {
  6503. tabstops = qRound(fm.width(QLatin1Char('x'))*8);
  6504. }
  6505. } else if (chr == QChar(ushort(0x9c))) {
  6506. // string with multiple length variants
  6507. hasMoreLengthVariants = true;
  6508. break;
  6509. }
  6510. }
  6511. int length = offset - old_offset;
  6512. if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
  6513. underlinePositions.resize(maxUnderlines + 1);
  6514. QChar *cout = text.data() + old_offset;
  6515. QChar *cin = cout;
  6516. int l = length;
  6517. while (l) {
  6518. if (*cin == QLatin1Char('&')) {
  6519. ++cin;
  6520. --length;
  6521. --l;
  6522. if (!l)
  6523. break;
  6524. if (*cin != QLatin1Char('&') && !hidemnmemonic)
  6525. underlinePositions[numUnderlines++] = cout - text.data() - old_offset;
  6526. }
  6527. *cout = *cin;
  6528. ++cout;
  6529. ++cin;
  6530. --l;
  6531. }
  6532. }
  6533. // no need to do extra work for underlines if we don't paint
  6534. if (tf & Qt::TextDontPrint)
  6535. numUnderlines = 0;
  6536. underlinePositions[numUnderlines] = -1;
  6537. qreal height = 0;
  6538. qreal width = 0;
  6539. QString finalText = text.mid(old_offset, length);
  6540. QStackTextEngine engine(finalText, fnt);
  6541. if (option) {
  6542. engine.option = *option;
  6543. }
  6544. if (engine.option.tabStop() < 0 && tabstops > 0)
  6545. engine.option.setTabStop(tabstops);
  6546. if (engine.option.tabs().isEmpty() && ta) {
  6547. QList<qreal> tabs;
  6548. for (int i = 0; i < tabarraylen; i++)
  6549. tabs.append(qreal(ta[i]));
  6550. engine.option.setTabArray(tabs);
  6551. }
  6552. engine.option.setTextDirection(layout_direction);
  6553. if (tf & Qt::AlignJustify)
  6554. engine.option.setAlignment(Qt::AlignJustify);
  6555. else
  6556. engine.option.setAlignment(Qt::AlignLeft); // do not do alignment twice
  6557. if (!option && (tf & Qt::TextWrapAnywhere))
  6558. engine.option.setWrapMode(QTextOption::WrapAnywhere);
  6559. if (tf & Qt::TextJustificationForced)
  6560. engine.forceJustification = true;
  6561. QTextLayout textLayout(&engine);
  6562. textLayout.setCacheEnabled(true);
  6563. textLayout.engine()->underlinePositions = underlinePositions.data();
  6564. if (finalText.isEmpty()) {
  6565. height = fm.height();
  6566. width = 0;
  6567. tf |= Qt::TextDontPrint;
  6568. } else {
  6569. qreal lineWidth = 0x01000000;
  6570. if (wordwrap || (tf & Qt::TextJustificationForced))
  6571. lineWidth = qMax<qreal>(0, r.width());
  6572. if(!wordwrap)
  6573. tf |= Qt::TextIncludeTrailingSpaces;
  6574. textLayout.engine()->ignoreBidi = bool(tf & Qt::TextDontPrint);
  6575. textLayout.beginLayout();
  6576. qreal leading = fm.leading();
  6577. height = -leading;
  6578. while (1) {
  6579. QTextLine l = textLayout.createLine();
  6580. if (!l.isValid())
  6581. break;
  6582. l.setLineWidth(lineWidth);
  6583. height += leading;
  6584. l.setPosition(QPointF(0., height));
  6585. height += l.height();
  6586. width = qMax(width, l.naturalTextWidth());
  6587. if (!dontclip && !brect && height >= r.height())
  6588. break;
  6589. }
  6590. textLayout.endLayout();
  6591. }
  6592. qreal yoff = 0;
  6593. qreal xoff = 0;
  6594. if (tf & Qt::AlignBottom) {
  6595. yoff = r.height() - height;
  6596. } else if (tf & Qt::AlignVCenter) {
  6597. yoff = (r.height() - height)/2;
  6598. if (painter) {
  6599. QTransform::TransformationType type = painter->transform().type();
  6600. if (type <= QTransform::TxScale) {
  6601. // do the rounding manually to work around inconsistencies
  6602. // in the paint engines when drawing on floating point offsets
  6603. const qreal scale = painter->transform().m22();
  6604. if (scale != 0)
  6605. yoff = -qRound(-yoff * scale) / scale;
  6606. }
  6607. }
  6608. }
  6609. if (tf & Qt::AlignRight) {
  6610. xoff = r.width() - width;
  6611. } else if (tf & Qt::AlignHCenter) {
  6612. xoff = (r.width() - width)/2;
  6613. if (painter) {
  6614. QTransform::TransformationType type = painter->transform().type();
  6615. if (type <= QTransform::TxScale) {
  6616. // do the rounding manually to work around inconsistencies
  6617. // in the paint engines when drawing on floating point offsets
  6618. const qreal scale = painter->transform().m11();
  6619. if (scale != 0)
  6620. xoff = qRound(xoff * scale) / scale;
  6621. }
  6622. }
  6623. }
  6624. QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
  6625. if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
  6626. offset++;
  6627. goto start_lengthVariant;
  6628. }
  6629. if (brect)
  6630. *brect = bounds;
  6631. if (!(tf & Qt::TextDontPrint)) {
  6632. bool restore = false;
  6633. if (!dontclip && !r.contains(bounds)) {
  6634. restore = true;
  6635. painter->save();
  6636. painter->setClipRect(r, Qt::IntersectClip);
  6637. }
  6638. for (int i = 0; i < textLayout.lineCount(); i++) {
  6639. QTextLine line = textLayout.lineAt(i);
  6640. qreal advance = line.horizontalAdvance();
  6641. xoff = 0;
  6642. if (tf & Qt::AlignRight) {
  6643. QTextEngine *eng = textLayout.engine();
  6644. xoff = r.width() - advance -
  6645. eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
  6646. }
  6647. else if (tf & Qt::AlignHCenter)
  6648. xoff = (r.width() - advance) / 2;
  6649. line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff));
  6650. }
  6651. if (restore) {
  6652. painter->restore();
  6653. }
  6654. }
  6655. }
  6656. /*!
  6657. Sets the layout direction used by the painter when drawing text,
  6658. to the specified \a direction.
  6659. The default is Qt::LayoutDirectionAuto, which will implicitly determine the
  6660. direction from the text drawn.
  6661. \sa QTextOption::setTextDirection(), layoutDirection(), drawText(), {QPainter#Settings}{Settings}
  6662. */
  6663. void QPainter::setLayoutDirection(Qt::LayoutDirection direction)
  6664. {
  6665. Q_D(QPainter);
  6666. if (d->state)
  6667. d->state->layoutDirection = direction;
  6668. }
  6669. /*!
  6670. Returns the layout direction used by the painter when drawing text.
  6671. \sa QTextOption::textDirection(), setLayoutDirection(), drawText(), {QPainter#Settings}{Settings}
  6672. */
  6673. Qt::LayoutDirection QPainter::layoutDirection() const
  6674. {
  6675. Q_D(const QPainter);
  6676. return d->state ? d->state->layoutDirection : Qt::LayoutDirectionAuto;
  6677. }
  6678. QPainterState::QPainterState(const QPainterState *s)
  6679. : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
  6680. pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
  6681. clipRegion(s->clipRegion), clipPath(s->clipPath),
  6682. clipOperation(s->clipOperation),
  6683. renderHints(s->renderHints), clipInfo(s->clipInfo),
  6684. worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
  6685. wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
  6686. vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
  6687. opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
  6688. clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
  6689. layoutDirection(s->layoutDirection),
  6690. composition_mode(s->composition_mode),
  6691. emulationSpecifier(s->emulationSpecifier), changeFlags(0)
  6692. {
  6693. dirtyFlags = s->dirtyFlags;
  6694. }
  6695. QPainterState::QPainterState()
  6696. : brushOrigin(0, 0), bgBrush(Qt::white), clipOperation(Qt::NoClip),
  6697. renderHints(0),
  6698. wx(0), wy(0), ww(0), wh(0), vx(0), vy(0), vw(0), vh(0),
  6699. opacity(1), WxF(false), VxF(false), clipEnabled(true),
  6700. bgMode(Qt::TransparentMode), painter(0),
  6701. layoutDirection(QApplication::layoutDirection()),
  6702. composition_mode(QPainter::CompositionMode_SourceOver),
  6703. emulationSpecifier(0), changeFlags(0)
  6704. {
  6705. dirtyFlags = 0;
  6706. }
  6707. QPainterState::~QPainterState()
  6708. {
  6709. }
  6710. void QPainterState::init(QPainter *p) {
  6711. bgBrush = Qt::white;
  6712. bgMode = Qt::TransparentMode;
  6713. WxF = false;
  6714. VxF = false;
  6715. clipEnabled = true;
  6716. wx = wy = ww = wh = 0;
  6717. vx = vy = vw = vh = 0;
  6718. painter = p;
  6719. pen = QPen();
  6720. brushOrigin = QPointF(0, 0);
  6721. brush = QBrush();
  6722. font = deviceFont = QFont();
  6723. clipRegion = QRegion();
  6724. clipPath = QPainterPath();
  6725. clipOperation = Qt::NoClip;
  6726. clipInfo.clear();
  6727. worldMatrix.reset();
  6728. matrix.reset();
  6729. layoutDirection = QApplication::layoutDirection();
  6730. composition_mode = QPainter::CompositionMode_SourceOver;
  6731. emulationSpecifier = 0;
  6732. dirtyFlags = 0;
  6733. changeFlags = 0;
  6734. renderHints = 0;
  6735. opacity = 1;
  6736. }
  6737. #ifdef QT3_SUPPORT
  6738. static void bitBlt_helper(QPaintDevice *dst, const QPoint &dp,
  6739. const QPaintDevice *src, const QRect &sr, bool)
  6740. {
  6741. Q_ASSERT(dst);
  6742. Q_ASSERT(src);
  6743. if (src->devType() == QInternal::Pixmap) {
  6744. const QPixmap *pixmap = static_cast<const QPixmap *>(src);
  6745. QPainter pt(dst);
  6746. pt.drawPixmap(dp, *pixmap, sr);
  6747. } else {
  6748. qWarning("QPainter: bitBlt only works when source is of type pixmap");
  6749. }
  6750. }
  6751. void bitBlt(QPaintDevice *dst, int dx, int dy,
  6752. const QPaintDevice *src, int sx, int sy, int sw, int sh,
  6753. bool ignoreMask )
  6754. {
  6755. bitBlt_helper(dst, QPoint(dx, dy), src, QRect(sx, sy, sw, sh), ignoreMask);
  6756. }
  6757. void bitBlt(QPaintDevice *dst, const QPoint &dp, const QPaintDevice *src, const QRect &sr, bool ignoreMask)
  6758. {
  6759. bitBlt_helper(dst, dp, src, sr, ignoreMask);
  6760. }
  6761. void bitBlt(QPaintDevice *dst, int dx, int dy,
  6762. const QImage *src, int sx, int sy, int sw, int sh, int fl)
  6763. {
  6764. Qt::ImageConversionFlags flags(fl);
  6765. QPixmap srcPixmap = QPixmap::fromImage(*src, flags);
  6766. bitBlt_helper(dst, QPoint(dx, dy), &srcPixmap, QRect(sx, sy, sw, sh), false);
  6767. }
  6768. #endif // QT3_SUPPORT
  6769. /*!
  6770. \fn void QPainter::setBackgroundColor(const QColor &color)
  6771. Use setBackground() instead.
  6772. */
  6773. /*!
  6774. \fn const QColor &QPainter::backgroundColor() const
  6775. Use background() and QBrush::color() instead.
  6776. \oldcode
  6777. QColor myColor = backgroundColor();
  6778. \newcode
  6779. QColor myColor = background().color();
  6780. \endcode
  6781. Note that the background can be a complex brush such as a texture
  6782. or a gradient.
  6783. */
  6784. /*!
  6785. \fn void QPainter::drawText(int x, int y, const QString &text, int pos, int length)
  6786. \compat
  6787. Use drawText() combined with QString::mid() instead.
  6788. \oldcode
  6789. QPainter painter(this);
  6790. painter.drawText(x, y, text, pos, length);
  6791. \newcode
  6792. QPainter painter(this);
  6793. painter.drawText(x, y, text.mid(pos, length));
  6794. \endcode
  6795. */
  6796. /*!
  6797. \fn void QPainter::drawText(const QPoint &point, const QString &text, int pos, int length)
  6798. \compat
  6799. Use drawText() combined with QString::mid() instead.
  6800. \oldcode
  6801. QPainter painter(this);
  6802. painter.drawText(point, text, pos, length);
  6803. \newcode
  6804. QPainter painter(this);
  6805. painter.drawText(point, text.mid(pos, length));
  6806. \endcode
  6807. */
  6808. /*!
  6809. \fn void QPainter::drawText(int x, int y, const QString &text, int length)
  6810. \compat
  6811. Use drawText() combined with QString::left() instead.
  6812. \oldcode
  6813. QPainter painter(this);
  6814. painter.drawText(x, y, text, length);
  6815. \newcode
  6816. QPainter painter(this);
  6817. painter.drawText(x, y, text.left(length));
  6818. \endcode
  6819. */
  6820. /*!
  6821. \fn void QPainter::drawText(const QPoint &point, const QString &text, int length)
  6822. \compat
  6823. Use drawText() combined with QString::left() instead.
  6824. \oldcode
  6825. QPainter painter(this);
  6826. painter.drawText(point, text, length);
  6827. \newcode
  6828. QPainter painter(this);
  6829. painter.drawText(point, text.left(length));
  6830. \endcode
  6831. */
  6832. /*!
  6833. \fn bool QPainter::begin(QPaintDevice *device, const QWidget *init)
  6834. \compat
  6835. Use begin() instead.
  6836. If the paint \a device is a QWidget, QPainter is initialized after
  6837. the widget's settings automatically. Otherwise, you must call the
  6838. initFrom() function to initialize the painters pen, background and
  6839. font to the same as any given widget.
  6840. \oldcode
  6841. QPainter painter(this);
  6842. painter.begin(device, init);
  6843. \newcode
  6844. QPainter painter(this);
  6845. painter.begin(device);
  6846. painter.initFrom(init);
  6847. \endcode
  6848. */
  6849. /*!
  6850. \fn void QPainter::drawImage(const QRectF &target, const QImage &image, const QRectF &source,
  6851. Qt::ImageConversionFlags flags)
  6852. Draws the rectangular portion \a source of the given \a image
  6853. into the \a target rectangle in the paint device.
  6854. \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
  6855. If the image needs to be modified to fit in a lower-resolution
  6856. result (e.g. converting from 32-bit to 8-bit), use the \a flags to
  6857. specify how you would prefer this to happen.
  6858. \table 100%
  6859. \row
  6860. \o
  6861. \snippet doc/src/snippets/code/src_gui_painting_qpainter.cpp 20
  6862. \endtable
  6863. \sa drawPixmap()
  6864. */
  6865. /*!
  6866. \fn void QPainter::drawImage(const QRect &target, const QImage &image, const QRect &source,
  6867. Qt::ImageConversionFlags flags)
  6868. \overload
  6869. Draws the rectangular portion \a source of the given \a image
  6870. into the \a target rectangle in the paint device.
  6871. \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
  6872. */
  6873. /*!
  6874. \fn void QPainter::drawImage(const QPointF &point, const QImage &image)
  6875. \overload
  6876. Draws the given \a image at the given \a point.
  6877. */
  6878. /*!
  6879. \fn void QPainter::drawImage(const QPoint &point, const QImage &image)
  6880. \overload
  6881. Draws the given \a image at the given \a point.
  6882. */
  6883. /*!
  6884. \fn void QPainter::drawImage(const QPointF &point, const QImage &image, const QRectF &source,
  6885. Qt::ImageConversionFlags flags = 0)
  6886. \overload
  6887. Draws the rectangular portion \a source of the given \a image with
  6888. its origin at the given \a point.
  6889. */
  6890. /*!
  6891. \fn void QPainter::drawImage(const QPoint &point, const QImage &image, const QRect &source,
  6892. Qt::ImageConversionFlags flags = 0)
  6893. \overload
  6894. Draws the rectangular portion \a source of the given \a image with
  6895. its origin at the given \a point.
  6896. */
  6897. /*!
  6898. \fn void QPainter::drawImage(const QRectF &rectangle, const QImage &image)
  6899. \overload
  6900. Draws the given \a image into the given \a rectangle.
  6901. \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
  6902. */
  6903. /*!
  6904. \fn void QPainter::drawImage(const QRect &rectangle, const QImage &image)
  6905. \overload
  6906. Draws the given \a image into the given \a rectangle.
  6907. \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
  6908. */
  6909. /*!
  6910. \fn void QPainter::drawImage(int x, int y, const QImage &image,
  6911. int sx, int sy, int sw, int sh,
  6912. Qt::ImageConversionFlags flags)
  6913. \overload
  6914. Draws an image at (\a{x}, \a{y}) by copying a part of \a image into
  6915. the paint device.
  6916. (\a{x}, \a{y}) specifies the top-left point in the paint device that is
  6917. to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
  6918. image that is to be drawn. The default is (0, 0).
  6919. (\a{sw}, \a{sh}) specifies the size of the image that is to be drawn.
  6920. The default, (0, 0) (and negative) means all the way to the
  6921. bottom-right of the image.
  6922. */
  6923. /*!
  6924. \fn void QPainter::redirect(QPaintDevice *pdev, QPaintDevice *replacement)
  6925. Use setRedirected() instead.
  6926. */
  6927. /*!
  6928. \fn QPaintDevice *QPainter::redirect(QPaintDevice *pdev)
  6929. Use redirected() instead.
  6930. */
  6931. /*!
  6932. \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
  6933. const QString &text, int length)
  6934. \compat
  6935. Returns the bounding rectangle for the given \a length of the \a
  6936. text constrained by the provided \a rectangle.
  6937. Use boundingRect() combined with QString::left() instead.
  6938. \oldcode
  6939. QRect rectangle = boundingRect(rect, flags, text, length);
  6940. \newcode
  6941. QRect rectangle = boundingRect(rect, flags, text.left(length));
  6942. \endcode
  6943. */
  6944. /*!
  6945. \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text,
  6946. int length, QRect *br)
  6947. \compat
  6948. Use drawText() combined with QString::left() instead.
  6949. \oldcode
  6950. QPainter painter(this);
  6951. painter.drawText(rectangle, flags, text, length, br );
  6952. \newcode
  6953. QPainter painter(this);
  6954. painter.drawText(rectangle, flags, text.left(length), br );
  6955. \endcode
  6956. */
  6957. /*!
  6958. \fn QRect QPainter::boundingRect(int x, int y, int width, int height, int flags,
  6959. const QString &text, int length);
  6960. \compat
  6961. Returns the bounding rectangle for the given \a length of the \a
  6962. text constrained by the rectangle that begins at point (\a{x},
  6963. \a{y}) with the given \a width and \a height.
  6964. Use boundingRect() combined with QString::left() instead.
  6965. \oldcode
  6966. QRect rectangle = boundingRect(x, y, width, height, flags, text, length);
  6967. \newcode
  6968. QRect rectangle = boundingRect(x, y, width, height, flags, text.left(length));
  6969. \endcode
  6970. */
  6971. /*!
  6972. \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
  6973. const QString &text, int length, QRect *br)
  6974. \compat
  6975. Use drawText() combined with QString::left() instead.
  6976. \oldcode
  6977. QPainter painter(this);
  6978. painter.drawText(x, y, width, height, flags, text, length, br );
  6979. \newcode
  6980. QPainter painter(this);
  6981. painter.drawText(x, y, width, height, flags, text.left(length), br );
  6982. \endcode
  6983. */
  6984. /*!
  6985. \class QPaintEngineState
  6986. \since 4.1
  6987. \brief The QPaintEngineState class provides information about the
  6988. active paint engine's current state.
  6989. \reentrant
  6990. QPaintEngineState records which properties that have changed since
  6991. the last time the paint engine was updated, as well as their
  6992. current value.
  6993. Which properties that have changed can at any time be retrieved
  6994. using the state() function. This function returns an instance of
  6995. the QPaintEngine::DirtyFlags type which stores an OR combination
  6996. of QPaintEngine::DirtyFlag values. The QPaintEngine::DirtyFlag
  6997. enum defines whether a property has changed since the last update
  6998. or not.
  6999. If a property is marked with a dirty flag, its current value can
  7000. be retrieved using the corresponding get function:
  7001. \target GetFunction
  7002. \table
  7003. \header \o Property Flag \o Current Property Value
  7004. \row \o QPaintEngine::DirtyBackground \o backgroundBrush()
  7005. \row \o QPaintEngine::DirtyBackgroundMode \o backgroundMode()
  7006. \row \o QPaintEngine::DirtyBrush \o brush()
  7007. \row \o QPaintEngine::DirtyBrushOrigin \o brushOrigin()
  7008. \row \o QPaintEngine::DirtyClipRegion \e or QPaintEngine::DirtyClipPath
  7009. \o clipOperation()
  7010. \row \o QPaintEngine::DirtyClipPath \o clipPath()
  7011. \row \o QPaintEngine::DirtyClipRegion \o clipRegion()
  7012. \row \o QPaintEngine::DirtyCompositionMode \o compositionMode()
  7013. \row \o QPaintEngine::DirtyFont \o font()
  7014. \row \o QPaintEngine::DirtyTransform \o transform()
  7015. \row \o QPaintEngine::DirtyClipEnabled \o isClipEnabled()
  7016. \row \o QPaintEngine::DirtyPen \o pen()
  7017. \row \o QPaintEngine::DirtyHints \o renderHints()
  7018. \endtable
  7019. The QPaintEngineState class also provide the painter() function
  7020. which returns a pointer to the painter that is currently updating
  7021. the paint engine.
  7022. An instance of this class, representing the current state of the
  7023. active paint engine, is passed as argument to the
  7024. QPaintEngine::updateState() function. The only situation in which
  7025. you will have to use this class directly is when implementing your
  7026. own paint engine.
  7027. \sa QPaintEngine
  7028. */
  7029. /*!
  7030. \fn QPaintEngine::DirtyFlags QPaintEngineState::state() const
  7031. Returns a combination of flags identifying the set of properties
  7032. that need to be updated when updating the paint engine's state
  7033. (i.e. during a call to the QPaintEngine::updateState() function).
  7034. \sa QPaintEngine::updateState()
  7035. */
  7036. /*!
  7037. Returns the pen in the current paint engine state.
  7038. This variable should only be used when the state() returns a
  7039. combination which includes the QPaintEngine::DirtyPen flag.
  7040. \sa state(), QPaintEngine::updateState()
  7041. */
  7042. QPen QPaintEngineState::pen() const
  7043. {
  7044. return static_cast<const QPainterState *>(this)->pen;
  7045. }
  7046. /*!
  7047. Returns the brush in the current paint engine state.
  7048. This variable should only be used when the state() returns a
  7049. combination which includes the QPaintEngine::DirtyBrush flag.
  7050. \sa state(), QPaintEngine::updateState()
  7051. */
  7052. QBrush QPaintEngineState::brush() const
  7053. {
  7054. return static_cast<const QPainterState *>(this)->brush;
  7055. }
  7056. /*!
  7057. Returns the brush origin in the current paint engine state.
  7058. This variable should only be used when the state() returns a
  7059. combination which includes the QPaintEngine::DirtyBrushOrigin flag.
  7060. \sa state(), QPaintEngine::updateState()
  7061. */
  7062. QPointF QPaintEngineState::brushOrigin() const
  7063. {
  7064. return static_cast<const QPainterState *>(this)->brushOrigin;
  7065. }
  7066. /*!
  7067. Returns the background brush in the current paint engine state.
  7068. This variable should only be used when the state() returns a
  7069. combination which includes the QPaintEngine::DirtyBackground flag.
  7070. \sa state(), QPaintEngine::updateState()
  7071. */
  7072. QBrush QPaintEngineState::backgroundBrush() const
  7073. {
  7074. return static_cast<const QPainterState *>(this)->bgBrush;
  7075. }
  7076. /*!
  7077. Returns the background mode in the current paint engine
  7078. state.
  7079. This variable should only be used when the state() returns a
  7080. combination which includes the QPaintEngine::DirtyBackgroundMode flag.
  7081. \sa state(), QPaintEngine::updateState()
  7082. */
  7083. Qt::BGMode QPaintEngineState::backgroundMode() const
  7084. {
  7085. return static_cast<const QPainterState *>(this)->bgMode;
  7086. }
  7087. /*!
  7088. Returns the font in the current paint engine
  7089. state.
  7090. This variable should only be used when the state() returns a
  7091. combination which includes the QPaintEngine::DirtyFont flag.
  7092. \sa state(), QPaintEngine::updateState()
  7093. */
  7094. QFont QPaintEngineState::font() const
  7095. {
  7096. return static_cast<const QPainterState *>(this)->font;
  7097. }
  7098. /*!
  7099. \since 4.2
  7100. \obsolete
  7101. Returns the matrix in the current paint engine
  7102. state.
  7103. \note It is advisable to use transform() instead of this function to
  7104. preserve the properties of perspective transformations.
  7105. This variable should only be used when the state() returns a
  7106. combination which includes the QPaintEngine::DirtyTransform flag.
  7107. \sa state(), QPaintEngine::updateState()
  7108. */
  7109. QMatrix QPaintEngineState::matrix() const
  7110. {
  7111. const QPainterState *st = static_cast<const QPainterState *>(this);
  7112. return st->matrix.toAffine();
  7113. }
  7114. /*!
  7115. \since 4.3
  7116. Returns the matrix in the current paint engine state.
  7117. This variable should only be used when the state() returns a
  7118. combination which includes the QPaintEngine::DirtyTransform flag.
  7119. \sa state(), QPaintEngine::updateState()
  7120. */
  7121. QTransform QPaintEngineState::transform() const
  7122. {
  7123. const QPainterState *st = static_cast<const QPainterState *>(this);
  7124. return st->matrix;
  7125. }
  7126. /*!
  7127. Returns the clip operation in the current paint engine
  7128. state.
  7129. This variable should only be used when the state() returns a
  7130. combination which includes either the QPaintEngine::DirtyClipPath
  7131. or the QPaintEngine::DirtyClipRegion flag.
  7132. \sa state(), QPaintEngine::updateState()
  7133. */
  7134. Qt::ClipOperation QPaintEngineState::clipOperation() const
  7135. {
  7136. return static_cast<const QPainterState *>(this)->clipOperation;
  7137. }
  7138. /*!
  7139. \since 4.3
  7140. Returns whether the coordinate of the fill have been specified
  7141. as bounded by the current rendering operation and have to be
  7142. resolved (about the currently rendered primitive).
  7143. */
  7144. bool QPaintEngineState::brushNeedsResolving() const
  7145. {
  7146. const QBrush &brush = static_cast<const QPainterState *>(this)->brush;
  7147. return needsResolving(brush);
  7148. }
  7149. /*!
  7150. \since 4.3
  7151. Returns whether the coordinate of the stroke have been specified
  7152. as bounded by the current rendering operation and have to be
  7153. resolved (about the currently rendered primitive).
  7154. */
  7155. bool QPaintEngineState::penNeedsResolving() const
  7156. {
  7157. const QPen &pen = static_cast<const QPainterState *>(this)->pen;
  7158. return needsResolving(pen.brush());
  7159. }
  7160. /*!
  7161. Returns the clip region in the current paint engine state.
  7162. This variable should only be used when the state() returns a
  7163. combination which includes the QPaintEngine::DirtyClipRegion flag.
  7164. \sa state(), QPaintEngine::updateState()
  7165. */
  7166. QRegion QPaintEngineState::clipRegion() const
  7167. {
  7168. return static_cast<const QPainterState *>(this)->clipRegion;
  7169. }
  7170. /*!
  7171. Returns the clip path in the current paint engine state.
  7172. This variable should only be used when the state() returns a
  7173. combination which includes the QPaintEngine::DirtyClipPath flag.
  7174. \sa state(), QPaintEngine::updateState()
  7175. */
  7176. QPainterPath QPaintEngineState::clipPath() const
  7177. {
  7178. return static_cast<const QPainterState *>(this)->clipPath;
  7179. }
  7180. /*!
  7181. Returns whether clipping is enabled or not in the current paint
  7182. engine state.
  7183. This variable should only be used when the state() returns a
  7184. combination which includes the QPaintEngine::DirtyClipEnabled
  7185. flag.
  7186. \sa state(), QPaintEngine::updateState()
  7187. */
  7188. bool QPaintEngineState::isClipEnabled() const
  7189. {
  7190. return static_cast<const QPainterState *>(this)->clipEnabled;
  7191. }
  7192. /*!
  7193. Returns the render hints in the current paint engine state.
  7194. This variable should only be used when the state() returns a
  7195. combination which includes the QPaintEngine::DirtyHints
  7196. flag.
  7197. \sa state(), QPaintEngine::updateState()
  7198. */
  7199. QPainter::RenderHints QPaintEngineState::renderHints() const
  7200. {
  7201. return static_cast<const QPainterState *>(this)->renderHints;
  7202. }
  7203. /*!
  7204. Returns the composition mode in the current paint engine state.
  7205. This variable should only be used when the state() returns a
  7206. combination which includes the QPaintEngine::DirtyCompositionMode
  7207. flag.
  7208. \sa state(), QPaintEngine::updateState()
  7209. */
  7210. QPainter::CompositionMode QPaintEngineState::compositionMode() const
  7211. {
  7212. return static_cast<const QPainterState *>(this)->composition_mode;
  7213. }
  7214. /*!
  7215. Returns a pointer to the painter currently updating the paint
  7216. engine.
  7217. */
  7218. QPainter *QPaintEngineState::painter() const
  7219. {
  7220. return static_cast<const QPainterState *>(this)->painter;
  7221. }
  7222. /*!
  7223. \since 4.2
  7224. Returns the opacity in the current paint engine state.
  7225. */
  7226. qreal QPaintEngineState::opacity() const
  7227. {
  7228. return static_cast<const QPainterState *>(this)->opacity;
  7229. }
  7230. /*!
  7231. \since 4.3
  7232. Sets the world transformation matrix.
  7233. If \a combine is true, the specified \a transform is combined with
  7234. the current matrix; otherwise it replaces the current matrix.
  7235. \sa transform() setWorldTransform()
  7236. */
  7237. void QPainter::setTransform(const QTransform &transform, bool combine )
  7238. {
  7239. setWorldTransform(transform, combine);
  7240. }
  7241. /*!
  7242. Returns the world transformation matrix.
  7243. \sa worldTransform()
  7244. */
  7245. const QTransform & QPainter::transform() const
  7246. {
  7247. return worldTransform();
  7248. }
  7249. /*!
  7250. Returns the matrix that transforms from logical coordinates to
  7251. device coordinates of the platform dependent paint device.
  7252. This function is \e only needed when using platform painting
  7253. commands on the platform dependent handle (Qt::HANDLE), and the
  7254. platform does not do transformations nativly.
  7255. The QPaintEngine::PaintEngineFeature enum can be queried to
  7256. determine whether the platform performs the transformations or
  7257. not.
  7258. \sa worldTransform(), QPaintEngine::hasFeature(),
  7259. */
  7260. const QTransform & QPainter::deviceTransform() const
  7261. {
  7262. Q_D(const QPainter);
  7263. if (!d->engine) {
  7264. qWarning("QPainter::deviceTransform: Painter not active");
  7265. return d->fakeState()->transform;
  7266. }
  7267. return d->state->matrix;
  7268. }
  7269. /*!
  7270. Resets any transformations that were made using translate(),
  7271. scale(), shear(), rotate(), setWorldTransform(), setViewport()
  7272. and setWindow().
  7273. \sa {Coordinate Transformations}
  7274. */
  7275. void QPainter::resetTransform()
  7276. {
  7277. Q_D(QPainter);
  7278. #ifdef QT_DEBUG_DRAW
  7279. if (qt_show_painter_debug_output)
  7280. printf("QPainter::resetMatrix()\n");
  7281. #endif
  7282. if (!d->engine) {
  7283. qWarning("QPainter::resetMatrix: Painter not active");
  7284. return;
  7285. }
  7286. d->state->wx = d->state->wy = d->state->vx = d->state->vy = 0; // default view origins
  7287. d->state->ww = d->state->vw = d->device->metric(QPaintDevice::PdmWidth);
  7288. d->state->wh = d->state->vh = d->device->metric(QPaintDevice::PdmHeight);
  7289. d->state->worldMatrix = QTransform();
  7290. setMatrixEnabled(false);
  7291. setViewTransformEnabled(false);
  7292. if (d->extended)
  7293. d->extended->transformChanged();
  7294. else
  7295. d->state->dirtyFlags |= QPaintEngine::DirtyTransform;
  7296. }
  7297. /*!
  7298. Sets the world transformation matrix.
  7299. If \a combine is true, the specified \a matrix is combined with the current matrix;
  7300. otherwise it replaces the current matrix.
  7301. \sa transform(), setTransform()
  7302. */
  7303. void QPainter::setWorldTransform(const QTransform &matrix, bool combine )
  7304. {
  7305. Q_D(QPainter);
  7306. if (!d->engine) {
  7307. qWarning("QPainter::setWorldTransform: Painter not active");
  7308. return;
  7309. }
  7310. if (combine)
  7311. d->state->worldMatrix = matrix * d->state->worldMatrix; // combines
  7312. else
  7313. d->state->worldMatrix = matrix; // set new matrix
  7314. d->state->WxF = true;
  7315. d->updateMatrix();
  7316. }
  7317. /*!
  7318. Returns the world transformation matrix.
  7319. */
  7320. const QTransform & QPainter::worldTransform() const
  7321. {
  7322. Q_D(const QPainter);
  7323. if (!d->engine) {
  7324. qWarning("QPainter::worldTransform: Painter not active");
  7325. return d->fakeState()->transform;
  7326. }
  7327. return d->state->worldMatrix;
  7328. }
  7329. /*!
  7330. Returns the transformation matrix combining the current
  7331. window/viewport and world transformation.
  7332. \sa setWorldTransform(), setWindow(), setViewport()
  7333. */
  7334. QTransform QPainter::combinedTransform() const
  7335. {
  7336. Q_D(const QPainter);
  7337. if (!d->engine) {
  7338. qWarning("QPainter::combinedTransform: Painter not active");
  7339. return QTransform();
  7340. }
  7341. return d->state->worldMatrix * d->viewTransform();
  7342. }
  7343. /*!
  7344. \since 4.7
  7345. This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap,
  7346. at multiple positions with different scale, rotation and opacity. \a
  7347. fragments is an array of \a fragmentCount elements specifying the
  7348. parameters used to draw each pixmap fragment. The \a hints
  7349. parameter can be used to pass in drawing hints.
  7350. This function is potentially faster than multiple calls to drawPixmap(),
  7351. since the backend can optimize state changes.
  7352. \sa QPainter::PixmapFragment, QPainter::PixmapFragmentHint
  7353. */
  7354. void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
  7355. const QPixmap &pixmap, PixmapFragmentHints hints)
  7356. {
  7357. Q_D(QPainter);
  7358. if (!d->engine || pixmap.isNull())
  7359. return;
  7360. #ifndef QT_NO_DEBUG
  7361. for (int i = 0; i < fragmentCount; ++i) {
  7362. QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
  7363. fragments[i].width, fragments[i].height);
  7364. if (!(QRectF(pixmap.rect()).contains(sourceRect)))
  7365. qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
  7366. }
  7367. #endif
  7368. if (d->engine->isExtended()) {
  7369. d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
  7370. } else {
  7371. qreal oldOpacity = opacity();
  7372. QTransform oldTransform = transform();
  7373. for (int i = 0; i < fragmentCount; ++i) {
  7374. QTransform transform = oldTransform;
  7375. qreal xOffset = 0;
  7376. qreal yOffset = 0;
  7377. if (fragments[i].rotation == 0) {
  7378. xOffset = fragments[i].x;
  7379. yOffset = fragments[i].y;
  7380. } else {
  7381. transform.translate(fragments[i].x, fragments[i].y);
  7382. transform.rotate(fragments[i].rotation);
  7383. }
  7384. setOpacity(oldOpacity * fragments[i].opacity);
  7385. setTransform(transform);
  7386. qreal w = fragments[i].scaleX * fragments[i].width;
  7387. qreal h = fragments[i].scaleY * fragments[i].height;
  7388. QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
  7389. fragments[i].width, fragments[i].height);
  7390. drawPixmap(QRectF(qreal(-0.5) * w + xOffset, qreal(-0.5) * h + yOffset, w, h), pixmap, sourceRect);
  7391. }
  7392. setOpacity(oldOpacity);
  7393. setTransform(oldTransform);
  7394. }
  7395. }
  7396. /*!
  7397. \since 4.8
  7398. This function is used to draw the same \a pixmap with multiple target
  7399. and source rectangles specified by \a targetRects. If \a sourceRects is 0,
  7400. the whole pixmap will be rendered at each of the target rectangles.
  7401. The \a hints parameter can be used to pass in drawing hints.
  7402. This function is potentially faster than multiple calls to drawPixmap(),
  7403. since the backend can optimize state changes.
  7404. \sa QPainter::PixmapFragmentHint
  7405. */
  7406. void QPainter::drawPixmapFragments(const QRectF *targetRects, const QRectF *sourceRects, int fragmentCount,
  7407. const QPixmap &pixmap, PixmapFragmentHints hints)
  7408. {
  7409. Q_D(QPainter);
  7410. if (!d->engine || pixmap.isNull())
  7411. return;
  7412. #ifndef QT_NO_DEBUG
  7413. if (sourceRects) {
  7414. for (int i = 0; i < fragmentCount; ++i) {
  7415. QRectF sourceRect = sourceRects[i];
  7416. if (!(QRectF(pixmap.rect()).contains(sourceRect)))
  7417. qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
  7418. }
  7419. }
  7420. #endif
  7421. if (d->engine->isExtended()) {
  7422. d->extended->drawPixmapFragments(targetRects, sourceRects, fragmentCount, pixmap, hints);
  7423. } else {
  7424. if (sourceRects) {
  7425. for (int i = 0; i < fragmentCount; ++i)
  7426. drawPixmap(targetRects[i], pixmap, sourceRects[i]);
  7427. } else {
  7428. QRectF sourceRect = pixmap.rect();
  7429. for (int i = 0; i < fragmentCount; ++i)
  7430. drawPixmap(targetRects[i], pixmap, sourceRect);
  7431. }
  7432. }
  7433. }
  7434. /*!
  7435. \since 4.7
  7436. \class QPainter::PixmapFragment
  7437. \brief This class is used in conjunction with the
  7438. QPainter::drawPixmapFragments() function to specify how a pixmap, or
  7439. sub-rect of a pixmap, is drawn.
  7440. The \a sourceLeft, \a sourceTop, \a width and \a height variables are used
  7441. as a source rectangle within the pixmap passed into the
  7442. QPainter::drawPixmapFragments() function. The variables \a x, \a y, \a
  7443. width and \a height are used to calculate the target rectangle that is
  7444. drawn. \a x and \a y denotes the center of the target rectangle. The \a
  7445. width and \a height in the target rectangle is scaled by the \a scaleX and
  7446. \a scaleY values. The resulting target rectangle is then rotated \a
  7447. rotation degrees around the \a x, \a y center point.
  7448. \sa QPainter::drawPixmapFragments()
  7449. */
  7450. /*!
  7451. \since 4.7
  7452. This is a convenience function that returns a QPainter::PixmapFragment that is
  7453. initialized with the \a pos, \a sourceRect, \a scaleX, \a scaleY, \a
  7454. rotation, \a opacity parameters.
  7455. */
  7456. QPainter::PixmapFragment QPainter::PixmapFragment::create(const QPointF &pos, const QRectF &sourceRect,
  7457. qreal scaleX, qreal scaleY, qreal rotation,
  7458. qreal opacity)
  7459. {
  7460. PixmapFragment fragment = {pos.x(), pos.y(), sourceRect.x(), sourceRect.y(), sourceRect.width(),
  7461. sourceRect.height(), scaleX, scaleY, rotation, opacity};
  7462. return fragment;
  7463. }
  7464. /*!
  7465. \variable QPainter::PixmapFragment::x
  7466. \brief the x coordinate of center point in the target rectangle.
  7467. */
  7468. /*!
  7469. \variable QPainter::PixmapFragment::y
  7470. \brief the y coordinate of the center point in the target rectangle.
  7471. */
  7472. /*!
  7473. \variable QPainter::PixmapFragment::sourceLeft
  7474. \brief the left coordinate of the source rectangle.
  7475. */
  7476. /*!
  7477. \variable QPainter::PixmapFragment::sourceTop
  7478. \brief the top coordinate of the source rectangle.
  7479. */
  7480. /*!
  7481. \variable QPainter::PixmapFragment::width
  7482. \brief the width of the source rectangle and is used to calculate the width
  7483. of the target rectangle.
  7484. */
  7485. /*!
  7486. \variable QPainter::PixmapFragment::height
  7487. \brief the height of the source rectangle and is used to calculate the
  7488. height of the target rectangle.
  7489. */
  7490. /*!
  7491. \variable QPainter::PixmapFragment::scaleX
  7492. \brief the horizontal scale of the target rectangle.
  7493. */
  7494. /*!
  7495. \variable QPainter::PixmapFragment::scaleY
  7496. \brief the vertical scale of the target rectangle.
  7497. */
  7498. /*!
  7499. \variable QPainter::PixmapFragment::rotation
  7500. \brief the rotation of the target rectangle in degrees. The target
  7501. rectangle is rotated after it has been scaled.
  7502. */
  7503. /*!
  7504. \variable QPainter::PixmapFragment::opacity
  7505. \brief the opacity of the target rectangle, where 0.0 is fully transparent
  7506. and 1.0 is fully opaque.
  7507. */
  7508. /*!
  7509. \since 4.7
  7510. \enum QPainter::PixmapFragmentHint
  7511. \value OpaqueHint Indicates that the pixmap fragments to be drawn are
  7512. opaque. Opaque fragments are potentially faster to draw.
  7513. \sa QPainter::drawPixmapFragments(), QPainter::PixmapFragment
  7514. */
  7515. void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
  7516. {
  7517. p->draw_helper(path, operation);
  7518. }
  7519. /*! \fn Display *QPaintDevice::x11Display() const
  7520. Use QX11Info::display() instead.
  7521. \oldcode
  7522. Display *display = widget->x11Display();
  7523. \newcode
  7524. Display *display = QX11Info::display();
  7525. \endcode
  7526. \sa QWidget::x11Info(), QX11Info::display()
  7527. */
  7528. /*! \fn int QPaintDevice::x11Screen() const
  7529. Use QX11Info::screen() instead.
  7530. \oldcode
  7531. int screen = widget->x11Screen();
  7532. \newcode
  7533. int screen = widget->x11Info().screen();
  7534. \endcode
  7535. \sa QWidget::x11Info(), QPixmap::x11Info()
  7536. */
  7537. /*! \fn void *QPaintDevice::x11Visual() const
  7538. Use QX11Info::visual() instead.
  7539. \oldcode
  7540. void *visual = widget->x11Visual();
  7541. \newcode
  7542. void *visual = widget->x11Info().visual();
  7543. \endcode
  7544. \sa QWidget::x11Info(), QPixmap::x11Info()
  7545. */
  7546. /*! \fn int QPaintDevice::x11Depth() const
  7547. Use QX11Info::depth() instead.
  7548. \oldcode
  7549. int depth = widget->x11Depth();
  7550. \newcode
  7551. int depth = widget->x11Info().depth();
  7552. \endcode
  7553. \sa QWidget::x11Info(), QPixmap::x11Info()
  7554. */
  7555. /*! \fn int QPaintDevice::x11Cells() const
  7556. Use QX11Info::cells() instead.
  7557. \oldcode
  7558. int cells = widget->x11Cells();
  7559. \newcode
  7560. int cells = widget->x11Info().cells();
  7561. \endcode
  7562. \sa QWidget::x11Info(), QPixmap::x11Info()
  7563. */
  7564. /*! \fn Qt::HANDLE QPaintDevice::x11Colormap() const
  7565. Use QX11Info::colormap() instead.
  7566. \oldcode
  7567. unsigned long screen = widget->x11Colormap();
  7568. \newcode
  7569. unsigned long screen = widget->x11Info().colormap();
  7570. \endcode
  7571. \sa QWidget::x11Info(), QPixmap::x11Info()
  7572. */
  7573. /*! \fn bool QPaintDevice::x11DefaultColormap() const
  7574. Use QX11Info::defaultColormap() instead.
  7575. \oldcode
  7576. bool isDefault = widget->x11DefaultColormap();
  7577. \newcode
  7578. bool isDefault = widget->x11Info().defaultColormap();
  7579. \endcode
  7580. \sa QWidget::x11Info(), QPixmap::x11Info()
  7581. */
  7582. /*! \fn bool QPaintDevice::x11DefaultVisual() const
  7583. Use QX11Info::defaultVisual() instead.
  7584. \oldcode
  7585. bool isDefault = widget->x11DefaultVisual();
  7586. \newcode
  7587. bool isDefault = widget->x11Info().defaultVisual();
  7588. \endcode
  7589. \sa QWidget::x11Info(), QPixmap::x11Info()
  7590. */
  7591. /*! \fn void *QPaintDevice::x11AppVisual(int screen)
  7592. Use QX11Info::visual() instead.
  7593. \oldcode
  7594. void *visual = QPaintDevice::x11AppVisual(screen);
  7595. \newcode
  7596. void *visual = widget->x11Info().appVisual(screen);
  7597. \endcode
  7598. \sa QWidget::x11Info(), QPixmap::x11Info()
  7599. */
  7600. /*! \fn Qt::HANDLE QPaintDevice::x11AppColormap(int screen)
  7601. Use QX11Info::colormap() instead.
  7602. \oldcode
  7603. unsigned long colormap = QPaintDevice::x11AppColormap(screen);
  7604. \newcode
  7605. unsigned long colormap = widget->x11Info().appColormap(screen);
  7606. \endcode
  7607. \sa QWidget::x11Info(), QPixmap::x11Info()
  7608. */
  7609. /*! \fn Display *QPaintDevice::x11AppDisplay()
  7610. Use QX11Info::display() instead.
  7611. \oldcode
  7612. Display *display = QPaintDevice::x11AppDisplay();
  7613. \newcode
  7614. Display *display = widget->x11Info().display();
  7615. \endcode
  7616. \sa QWidget::x11Info(), QPixmap::x11Info()
  7617. */
  7618. /*! \fn int QPaintDevice::x11AppScreen()
  7619. Use QX11Info::screen() instead.
  7620. \oldcode
  7621. int screen = QPaintDevice::x11AppScreen();
  7622. \newcode
  7623. int screen = widget->x11Info().appScreen();
  7624. \endcode
  7625. \sa QWidget::x11Info(), QPixmap::x11Info()
  7626. */
  7627. /*! \fn int QPaintDevice::x11AppDepth(int screen)
  7628. Use QX11Info::depth() instead.
  7629. \oldcode
  7630. int depth = QPaintDevice::x11AppDepth(screen);
  7631. \newcode
  7632. int depth = widget->x11Info().appDepth(screen);
  7633. \endcode
  7634. \sa QWidget::x11Info(), QPixmap::x11Info()
  7635. */
  7636. /*! \fn int QPaintDevice::x11AppCells(int screen)
  7637. Use QX11Info::cells() instead.
  7638. \oldcode
  7639. int cells = QPaintDevice::x11AppCells(screen);
  7640. \newcode
  7641. int cells = widget->x11Info().appCells(screen);
  7642. \endcode
  7643. \sa QWidget::x11Info(), QPixmap::x11Info()
  7644. */
  7645. /*! \fn Qt::HANDLE QPaintDevice::x11AppRootWindow(int screen)
  7646. Use QX11Info::appRootWindow() instead.
  7647. \oldcode
  7648. unsigned long window = QPaintDevice::x11AppRootWindow(screen);
  7649. \newcode
  7650. unsigned long window = widget->x11Info().appRootWindow(screen);
  7651. \endcode
  7652. \sa QWidget::x11Info(), QPixmap::x11Info()
  7653. */
  7654. /*! \fn bool QPaintDevice::x11AppDefaultColormap(int screen)
  7655. Use QX11Info::defaultColormap() instead.
  7656. \oldcode
  7657. bool isDefault = QPaintDevice::x11AppDefaultColormap(screen);
  7658. \newcode
  7659. bool isDefault = widget->x11Info().appDefaultColormap(screen);
  7660. \endcode
  7661. \sa QWidget::x11Info(), QPixmap::x11Info()
  7662. */
  7663. /*! \fn bool QPaintDevice::x11AppDefaultVisual(int screen)
  7664. Use QX11Info::defaultVisual() instead.
  7665. \oldcode
  7666. bool isDefault = QPaintDevice::x11AppDefaultVisual(screen);
  7667. \newcode
  7668. bool isDefault = widget->x11Info().appDefaultVisual(screen);
  7669. \endcode
  7670. \sa QWidget::x11Info(), QPixmap::x11Info()
  7671. */
  7672. /*! \fn void QPaintDevice::x11SetAppDpiX(int dpi, int screen)
  7673. Use QX11Info::setAppDpiX() instead.
  7674. */
  7675. /*! \fn void QPaintDevice::x11SetAppDpiY(int dpi, int screen)
  7676. Use QX11Info::setAppDpiY() instead.
  7677. */
  7678. /*! \fn int QPaintDevice::x11AppDpiX(int screen)
  7679. Use QX11Info::appDpiX() instead.
  7680. \oldcode
  7681. bool isDefault = QPaintDevice::x11AppDpiX(screen);
  7682. \newcode
  7683. bool isDefault = widget->x11Info().appDpiX(screen);
  7684. \endcode
  7685. \sa QWidget::x11Info(), QPixmap::x11Info()
  7686. */
  7687. /*! \fn int QPaintDevice::x11AppDpiY(int screen)
  7688. Use QX11Info::appDpiY() instead.
  7689. \oldcode
  7690. bool isDefault = QPaintDevice::x11AppDpiY(screen);
  7691. \newcode
  7692. bool isDefault = widget->x11Info().appDpiY(screen);
  7693. \endcode
  7694. \sa QWidget::x11Info(), QPixmap::x11Info()
  7695. */
  7696. /*! \fn HDC QPaintDevice::getDC() const
  7697. \internal
  7698. */
  7699. /*! \fn void QPaintDevice::releaseDC(HDC) const
  7700. \internal
  7701. */
  7702. /*! \fn QWSDisplay *QPaintDevice::qwsDisplay()
  7703. \internal
  7704. */
  7705. QT_END_NAMESPACE