Changeset 561 for trunk/src/gui/painting/qpainter.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
src/gui/painting/qpainter.cpp (modified) (121 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/painting/qpainter.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information ([email protected]) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation ([email protected]) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you 37 ** @nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 76 76 #define QPaintEngine_OpaqueBackground 0x40000000 77 77 78 // use the same rounding as in qrasterizer.cpp (6 bit fixed point)79 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;80 81 78 // #define QT_DEBUG_DRAW 82 79 #ifdef QT_DEBUG_DRAW … … 166 163 { 167 164 Q_ASSERT(extended); 165 166 167 168 168 bool doEmulation = false; 169 169 if (state->bgMode == Qt::OpaqueMode) … … 185 185 extended->setState(state); 186 186 } 187 } else if (emulationEngine && emulationEngine != extended) {187 } else if (emulationEngine = extended) { 188 188 extended = emulationEngine->real_engine; 189 189 } … … 260 260 sp->d_ptr->d_ptrs_size = 4; 261 261 sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *)); 262 262 263 } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) { 263 264 // However, to support corner cases we grow the array dynamically if needed. 264 265 sp->d_ptr->d_ptrs_size <<= 1; 265 266 const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *); 266 sp->d_ptr->d_ptrs = (QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize); 267 } 268 sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr; 269 q->d_ptr = sp->d_ptr; 267 sp->d_ptr->d_ptrs = q_check_ptr((QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize)); 268 } 269 sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr.data(); 270 q->d_ptr.take(); 271 q->d_ptr.reset(sp->d_ptr.data()); 270 272 271 273 Q_ASSERT(q->d_ptr->state); … … 282 284 283 285 // Update matrix. 284 if (q->d_ptr->state->WxF) 285 q->d_ptr->state->worldMatrix.translate(-offset.x(), -offset.y()); 286 else 287 q->d_ptr->state->redirection_offset = offset; 286 if (q->d_ptr->state->WxF) { 287 q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix; 288 q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y()); 289 q->d_ptr->state->worldMatrix = QTransform(); 290 q->d_ptr->state->WxF = false; 291 } else { 292 q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y()); 293 } 288 294 q->d_ptr->updateMatrix(); 289 295 … … 316 322 d_ptrs[refcount - 1] = 0; 317 323 q->restore(); 318 q->d_ptr = original; 324 q->d_ptr.take(); 325 q->d_ptr.reset(original); 319 326 320 327 if (emulationEngine) { … … 411 418 QTransform old_invMatrix = invMatrix; 412 419 txinv = true; 413 invMatrix = QTransform() .translate(-state->redirection_offset.x(), -state->redirection_offset.y());420 invMatrix = QTransform(); 414 421 QPainterPath clipPath = q->clipPath(); 415 422 QRectF r = clipPath.boundingRect().intersected(absPathRect); … … 469 476 470 477 q->save(); 471 q->resetMatrix(); 478 state->matrix = QTransform(); 479 state->dirtyFlags |= QPaintEngine::DirtyTransform; 472 480 updateState(state); 473 481 engine->drawImage(absPathRect, … … 635 643 636 644 txinv = false; // no inverted matrix 637 if (!state->redirection_offset.isNull()) { 638 // We want to translate in dev space so we do the adding of the redirection 639 // offset manually. 640 if (state->matrix.isAffine()) { 641 state->matrix = QTransform(state->matrix.m11(), state->matrix.m12(), 642 state->matrix.m21(), state->matrix.m22(), 643 state->matrix.dx()-state->redirection_offset.x(), 644 state->matrix.dy()-state->redirection_offset.y()); 645 } else { 646 QTransform temp; 647 temp.translate(-state->redirection_offset.x(), -state->redirection_offset.y()); 648 state->matrix *= temp; 649 } 650 } 645 state->matrix *= state->redirectionMatrix; 651 646 if (extended) 652 647 extended->transformChanged(); … … 663 658 Q_ASSERT(txinv == false); 664 659 txinv = true; // creating inverted matrix 665 QTransform m; 666 667 if (state->VxF) 668 m = viewTransform(); 669 670 if (state->WxF) { 671 if (state->VxF) 672 m = state->worldMatrix * m; 673 else 674 m = state->worldMatrix; 675 } 676 invMatrix = m.inverted(); // invert matrix 660 invMatrix = state->matrix.inverted(); 677 661 } 678 662 … … 945 929 other paint devices. 946 930 947 \ingroup multimedia948 \mainclass 931 \ingroup 932 949 933 \reentrant 950 934 … … 1026 1010 the origin of widget's background. 1027 1011 1028 \o viewport(), window(), world Matrix() make up the painter's coordinate1012 \o viewport(), window(), world() make up the painter's coordinate 1029 1013 transformation system. For more information, see the \l 1030 1014 {Coordinate Transformations} section and the \l {The Coordinate … … 1037 1021 painter when drawing text. 1038 1022 1039 \o matrixEnabled() tells whether world transformation is enabled.1023 \o atrixEnabled() tells whether world transformation is enabled. 1040 1024 1041 1025 \o viewTransformEnabled() tells whether view transformation is … … 1233 1217 1234 1218 All the tranformation operations operate on the transformation 1235 world Matrix(). A matrix transforms a point in the plane to another1219 world(). A matrix transforms a point in the plane to another 1236 1220 point. For more information about the transformation matrix, see 1237 the \l {The Coordinate System} and Q Matrixdocumentation.1238 1239 The setWorld Matrix() function can replace or add to the currently1240 set world Matrix(). The resetMatrix() function resets any1221 the \l {The Coordinate System} and Q documentation. 1222 1223 The setWorld() function can replace or add to the currently 1224 set world() function resets any 1241 1225 transformations that were made using translate(), scale(), 1242 shear(), rotate(), setWorld Matrix(), setViewport() and setWindow()1243 functions. The device Matrix() returns the matrix that transforms1226 shear(), rotate(), setWorld(), setViewport() and setWindow() 1227 functions. The device() returns the matrix that transforms 1244 1228 from logical coordinates to device coordinates of the platform 1245 1229 dependent paint device. The latter function is only needed when … … 1250 1234 coordinates which then are converted into the physical coordinates 1251 1235 of the paint device. The mapping of the logical coordinates to the 1252 physical coordinates are handled by QPainter's combined Matrix(), a1253 combination of viewport() and window() and world Matrix().The1236 physical coordinates are handled by QPainter's combined(), a 1237 combination of viewport() and window() and world The 1254 1238 viewport() represents the physical coordinates specifying an 1255 1239 arbitrary rectangle, the window() describes the same rectangle in 1256 logical coordinates, and the world Matrix() is identical with the1240 logical coordinates, and the world() is identical with the 1257 1241 transformation matrix. 1258 1242 … … 1334 1318 polygons instead. 1335 1319 1336 \sa QPaintDevice, QPaintEngine, {QtSvg Module}, {Basic Drawing Example} 1320 \section1 Performance 1321 1322 QPainter is a rich framework that allows developers to do a great 1323 variety of graphical operations, such as gradients, composition 1324 modes and vector graphics. And QPainter can do this across a 1325 variety of different hardware and software stacks. Naturally the 1326 underlying combination of hardware and software has some 1327 implications for performance, and ensuring that every single 1328 operation is fast in combination with all the various combinations 1329 of composition modes, brushes, clipping, transformation, etc, is 1330 close to an impossible task because of the number of 1331 permutations. As a compromise we have selected a subset of the 1332 QPainter API and backends, were performance is guaranteed to be as 1333 good as we can sensibly get it for the given combination of 1334 hardware and software. 1335 1336 The backends we focus on as high-performance engines are: 1337 1338 \list 1339 1340 \o Raster - This backend implements all rendering in pure software 1341 and is always used to render into QImages. For optimal performance 1342 only use the format types QImage::Format_ARGB32_Premultiplied, 1343 QImage::Format_RGB32 or QImage::Format_RGB16. Any other format, 1344 including QImage::Format_ARGB32, has significantly worse 1345 performance. This engine is also used by default on Windows and on 1346 QWS. It can be used as default graphics system on any 1347 OS/hardware/software combination by passing \c {-graphicssystem 1348 raster} on the command line 1349 1350 \o OpenGL 2.0 (ES) - This backend is the primary backend for 1351 hardware accelerated graphics. It can be run on desktop machines 1352 and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0 1353 specification. This includes most graphics chips produced in the 1354 last couple of years. The engine can be enabled by using QPainter 1355 onto a QGLWidget or by passing \c {-graphicssystem opengl} on the 1356 command line when the underlying system supports it. 1357 1358 \o OpenVG - This backend implements the Khronos standard for 2D 1359 and Vector Graphics. It is primarily for embedded devices with 1360 hardware support for OpenVG. The engine can be enabled by 1361 passing \c {-graphicssystem openvg} on the command line when 1362 the underlying system supports it. 1363 1364 \endlist 1365 1366 These operations are: 1367 1368 \list 1369 1370 \o Simple transformations, meaning translation and scaling, pluss 1371 0, 90, 180, 270 degree rotations. 1372 1373 \o \c drawPixmap() in combination with simple transformations and 1374 opacity with non-smooth transformation mode 1375 (\c QPainter::SmoothPixmapTransform not enabled as a render hint). 1376 1377 \o Text drawing with regular font sizes with simple 1378 transformations with solid colors using no or 8-bit antialiasing. 1379 1380 \o Rectangle fills with solid color, two-color linear gradients 1381 and simple transforms. 1382 1383 \o Rectangular clipping with simple transformations and intersect 1384 clip. 1385 1386 \o Composition Modes \c QPainter::CompositionMode_Source and 1387 QPainter::CompositionMode_SourceOver 1388 1389 \o Rounded rectangle filling using solid color and two-color 1390 linear gradients fills. 1391 1392 \o 3x3 patched pixmaps, via qDrawBorderPixmap. 1393 1394 \endlist 1395 1396 This list gives an indication of which features to safely use in 1397 an application where performance is critical. For certain setups, 1398 other operations may be fast too, but before making extensive use 1399 of them, it is recommended to benchmark and verify them on the 1400 system where the software will run in the end. There are also 1401 cases where expensive operations are ok to use, for instance when 1402 the result is cached in a QPixmap. 1403 1404 \sa QPaintDevice, QPaintEngine, {QtSvg Module}, {Basic Drawing Example}, 1405 {Drawing Utility Functions} 1337 1406 */ 1338 1407 … … 1375 1444 1376 1445 QPainter::QPainter() 1377 { 1378 d_ptr = new QPainterPrivate(this); 1446 : d_ptr(new QPainterPrivate(this)) 1447 { 1379 1448 } 1380 1449 … … 1408 1477 Q_ASSERT(pd != 0); 1409 1478 if (!QPainterPrivate::attachPainterPrivate(this, pd)) { 1410 d_ptr = new QPainterPrivate(this);1479 d_ptr); 1411 1480 begin(pd); 1412 1481 } … … 1420 1489 { 1421 1490 d_ptr->inDestructor = true; 1422 if (isActive()) 1423 end(); 1424 else if (d_ptr->refcount > 1) 1425 d_ptr->detachPainterPrivate(this); 1426 1491 QT_TRY { 1492 if (isActive()) 1493 end(); 1494 else if (d_ptr->refcount > 1) 1495 d_ptr->detachPainterPrivate(this); 1496 } QT_CATCH(...) { 1497 // don't throw anything in the destructor. 1498 } 1427 1499 if (d_ptr) { 1428 1500 // Make sure we haven't messed things up. … … 1432 1504 if (d_ptr->d_ptrs) 1433 1505 free(d_ptr->d_ptrs); 1434 delete d_ptr;1435 1506 } 1436 1507 } … … 1485 1556 d->state->deviceFont = QFont(widget->font(), const_cast<QWidget*> (widget)); 1486 1557 d->state->font = d->state->deviceFont; 1487 if (d->engine) { 1558 if (d->extended) { 1559 d->extended->penChanged(); 1560 } else if (d->engine) { 1488 1561 d->engine->setDirty(QPaintEngine::DirtyPen); 1489 1562 d->engine->setDirty(QPaintEngine::DirtyBrush); … … 1571 1644 for (int i=0; i<d->state->clipInfo.size(); ++i) { 1572 1645 const QPainterClipInfo &info = d->state->clipInfo.at(i); 1573 tmp->matrix.setMatrix(info.matrix.m11(), info.matrix.m12(), info.matrix.m13(), 1574 info.matrix.m21(), info.matrix.m22(), info.matrix.m23(), 1575 info.matrix.dx() - d->state->redirection_offset.x(), 1576 info.matrix.dy() - d->state->redirection_offset.y(), info.matrix.m33()); 1646 tmp->matrix = info.matrix; 1647 tmp->matrix *= d->state->redirectionMatrix; 1577 1648 tmp->clipOperation = info.operation; 1578 1649 if (info.clipType == QPainterClipInfo::RectClip) { … … 1622 1693 time. 1623 1694 1695 1696 1697 1624 1698 \sa end(), QPainter() 1625 1699 */ 1700 1701 1702 1703 1704 1705 1706 1707 1708 1626 1709 1627 1710 bool QPainter::begin(QPaintDevice *pd) … … 1670 1753 #endif 1671 1754 1672 1673 d->device = pd;1674 1755 if (pd->devType() == QInternal::Pixmap) 1675 1756 static_cast<QPixmap *>(pd)->detach(); … … 1678 1759 1679 1760 d->engine = pd->paintEngine(); 1680 d->extended = d->engine && d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : 0; 1761 1762 if (!d->engine) { 1763 qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType()); 1764 return false; 1765 } 1766 1767 d->device = pd; 1768 1769 d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : 0; 1681 1770 if (d->emulationEngine) 1682 1771 d->emulationEngine->real_engine = d->extended; … … 1688 1777 d->states.push_back(d->state); 1689 1778 1690 d->state->redirection _offset = redirectionOffset;1779 d->state->redirection; 1691 1780 d->state->brushOrigin = QPointF(); 1692 1693 if (!d->engine) {1694 qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());1695 return true;1696 }1697 1781 1698 1782 // Slip a painter state into the engine before we do any other operations … … 1714 1798 qWarning("QPainter::begin: Widget painting can only begin as a " 1715 1799 "result of a paintEvent"); 1716 d->engine = 0; 1717 d->device = 0; 1800 qt_cleanup_painter_state(d); 1718 1801 return false; 1719 1802 } … … 1722 1805 if (!inPaintEvent && paintOutsidePaintEvent && !widget->internalWinId() 1723 1806 && widget->testAttribute(Qt::WA_WState_Created)) { 1724 d->state->redirection_offset -= widget->mapTo(widget->nativeParentWidget(), QPoint()); 1807 const QPoint offset = widget->mapTo(widget->nativeParentWidget(), QPoint()); 1808 d->state->redirectionMatrix.translate(offset.x(), offset.y()); 1725 1809 } 1726 1810 break; … … 1732 1816 if (pm->isNull()) { 1733 1817 qWarning("QPainter::begin: Cannot paint on a null pixmap"); 1734 d->engine = 0; 1735 d->device = 0; 1818 qt_cleanup_painter_state(d); 1736 1819 return false; 1737 1820 } … … 1749 1832 if (img->isNull()) { 1750 1833 qWarning("QPainter::begin: Cannot paint on a null image"); 1751 d->engine = 0; 1752 d->device = 0; 1834 qt_cleanup_painter_state(d); 1835 return false; 1836 } else if (img->format() == QImage::Format_Indexed8) { 1837 // Painting on indexed8 images is not supported. 1838 qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format"); 1839 qt_cleanup_painter_state(d); 1753 1840 return false; 1754 1841 } … … 1773 1860 end(); 1774 1861 } else { 1775 d->states.clear(); 1776 delete d->state; 1777 d->state = 0; 1862 qt_cleanup_painter_state(d); 1778 1863 } 1779 d->engine = 0;1780 d->device = 0;1781 1864 return false; 1782 1865 } else { … … 1804 1887 } 1805 1888 1806 d->state->redirection_offset += d->engine->coordinateOffset(); 1889 const QPoint coordinateOffset = d->engine->coordinateOffset(); 1890 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y()); 1807 1891 1808 1892 Q_ASSERT(d->engine->isActive()); 1809 1893 1810 if (!d->state->redirection _offset.isNull())1894 if (!d->state->redirection()) 1811 1895 d->updateMatrix(); 1812 1896 … … 1840 1924 if (!d->engine) { 1841 1925 qWarning("QPainter::end: Painter not active, aborted"); 1842 d->states.clear(); 1843 delete d->state; 1844 d->state = 0; 1845 d->device = 0; 1926 qt_cleanup_painter_state(d); 1846 1927 return false; 1847 1928 } … … 1850 1931 d->detachPainterPrivate(this); 1851 1932 return true; 1852 }1853 1854 if (d->states.size() > 1) {1855 qWarning("QPainter::end: Painter ended with %d saved states",1856 d->states.size());1857 1933 } 1858 1934 … … 1870 1946 } 1871 1947 1948 1949 1950 1951 1952 1872 1953 if (d->engine->autoDestruct()) { 1873 1954 delete d->engine; 1874 1955 } 1875 1876 d->engine = 0;1877 1956 1878 1957 if (d->emulationEngine) { … … 1885 1964 } 1886 1965 1887 d->states.clear(); 1888 delete d->state; 1889 d->state = 0; 1890 1891 d->device = 0; 1966 qt_cleanup_painter_state(d); 1967 1892 1968 return ended; 1893 1969 } … … 1906 1982 } 1907 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 1908 2032 1909 2033 /*! … … 2015 2139 2016 2140 The brush origin specifies the (0, 0) coordinate of the painter's 2017 brush. This setting only applies to pattern brushes and pixmap 2018 brushes. 2141 brush. 2019 2142 2020 2143 Note that while the brushOrigin() was necessary to adopt the … … 2237 2360 Sets the composition mode to the given \a mode. 2238 2361 2239 \warning You can only set the composition mode for QPainter 2240 objects that operates on a QImage. 2362 \warning Only a QPainter operating on a QImage fully supports all 2363 composition modes. The RasterOp modes are supported for X11 as 2364 described in compositionMode(). 2241 2365 2242 2366 \sa compositionMode() … … 2372 2496 is given in logical coordinates. 2373 2497 2498 2499 2500 2501 2502 2374 2503 \sa setClipRegion(), clipPath(), setClipping() 2375 2504 */ … … 2392 2521 for (int i=0; i<d->state->clipInfo.size(); ++i) { 2393 2522 const QPainterClipInfo &info = d->state->clipInfo.at(i); 2394 QRegion other;2395 2523 switch (info.clipType) { 2396 2524 … … 2445 2573 continue; 2446 2574 } 2447 if (info.operation == Qt::IntersectClip) 2448 region &= QRegion(info.rect) * matrix; 2449 else if (info.operation == Qt::UniteClip) 2575 if (info.operation == Qt::IntersectClip) { 2576 // Use rect intersection if possible. 2577 if (matrix.type() <= QTransform::TxScale) 2578 region &= matrix.mapRect(info.rect); 2579 else 2580 region &= matrix.map(QRegion(info.rect)); 2581 } else if (info.operation == Qt::UniteClip) { 2450 2582 region |= QRegion(info.rect) * matrix; 2451 else if (info.operation == Qt::NoClip) {2583 else if (info.operation == Qt::NoClip) { 2452 2584 lastWasNothing = true; 2453 2585 region = QRegion(); 2454 } else 2586 } else 2455 2587 region = QRegion(info.rect) * matrix; 2588 2456 2589 break; 2457 2590 } … … 2464 2597 continue; 2465 2598 } 2466 if (info.operation == Qt::IntersectClip) 2467 region &= QRegion(info.rectf.toRect()) * matrix; 2468 else if (info.operation == Qt::UniteClip) 2599 if (info.operation == Qt::IntersectClip) { 2600 // Use rect intersection if possible. 2601 if (matrix.type() <= QTransform::TxScale) 2602 region &= matrix.mapRect(info.rectf.toRect()); 2603 else 2604 region &= matrix.map(QRegion(info.rectf.toRect())); 2605 } else if (info.operation == Qt::UniteClip) { 2469 2606 region |= QRegion(info.rectf.toRect()) * matrix; 2470 else if (info.operation == Qt::NoClip) {2607 else if (info.operation == Qt::NoClip) { 2471 2608 lastWasNothing = true; 2472 2609 region = QRegion(); 2473 } else 2610 } else 2474 2611 region = QRegion(info.rectf.toRect()) * matrix; 2612 2475 2613 break; 2476 2614 } … … 2486 2624 Returns the currently clip as a path. Note that the clip path is 2487 2625 given in logical coordinates. 2626 2627 2628 2629 2630 2488 2631 2489 2632 \sa setClipPath(), clipRegion(), setClipping() … … 2545 2688 2546 2689 if (d->extended) { 2690 2691 2692 2547 2693 if (!d->engine) { 2548 2694 qWarning("QPainter::setClipRect: Painter not active"); … … 2558 2704 d->state->clipEnabled = true; 2559 2705 d->extended->clip(vp, op); 2560 d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform()); 2706 if (op == Qt::ReplaceClip || op == Qt::NoClip) 2707 d->state->clipInfo.clear(); 2708 d->state->clipInfo << QPainterClipInfo(rect, op, d->state->matrix); 2561 2709 d->state->clipOperation = op; 2562 2710 return; … … 2598 2746 } 2599 2747 2748 2749 2750 2600 2751 if (d->extended) { 2601 2752 d->state->clipEnabled = true; 2602 2753 d->extended->clip(rect, op); 2603 d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform()); 2754 if (op == Qt::ReplaceClip || op == Qt::NoClip) 2755 d->state->clipInfo.clear(); 2756 d->state->clipInfo << QPainterClipInfo(rect, op, d->state->matrix); 2604 2757 d->state->clipOperation = op; 2605 2758 return; 2606 2759 } 2607 2608 if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))2609 op = Qt::ReplaceClip;2610 2760 2611 2761 d->state->clipRegion = rect; … … 2613 2763 if (op == Qt::NoClip || op == Qt::ReplaceClip) 2614 2764 d->state->clipInfo.clear(); 2615 d->state->clipInfo << QPainterClipInfo(rect, op, combinedTransform());2765 d->state->clipInfo << QPainterClipInfo(rect, op, ); 2616 2766 d->state->clipEnabled = true; 2617 2767 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled; … … 2651 2801 } 2652 2802 2803 2804 2805 2653 2806 if (d->extended) { 2654 2807 d->state->clipEnabled = true; 2655 2808 d->extended->clip(r, op); 2656 d->state->clipInfo << QPainterClipInfo(r, op, combinedTransform()); 2809 if (op == Qt::NoClip || op == Qt::ReplaceClip) 2810 d->state->clipInfo.clear(); 2811 d->state->clipInfo << QPainterClipInfo(r, op, d->state->matrix); 2657 2812 d->state->clipOperation = op; 2658 2813 return; 2659 2814 } 2660 2661 if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))2662 op = Qt::ReplaceClip;2663 2815 2664 2816 d->state->clipRegion = r; … … 2666 2818 if (op == Qt::NoClip || op == Qt::ReplaceClip) 2667 2819 d->state->clipInfo.clear(); 2668 d->state->clipInfo << QPainterClipInfo(r, op, combinedTransform());2820 d->state->clipInfo << QPainterClipInfo(r, op, ); 2669 2821 d->state->clipEnabled = true; 2670 2822 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled; … … 2674 2826 /*! 2675 2827 \since 4.2 2828 2676 2829 2677 2830 Sets the transformation matrix to \a matrix and enables transformations. … … 2712 2865 documentation. 2713 2866 2714 \sa worldMatrixEnabled(), QMatrix2867 \sa 2715 2868 */ 2716 2869 … … 2722 2875 /*! 2723 2876 \since 4.2 2877 2724 2878 2725 2879 Returns the world transformation matrix. … … 2771 2925 /*! 2772 2926 \since 4.2 2927 2773 2928 2774 2929 Returns the transformation matrix combining the current … … 2778 2933 function to preserve the properties of perspective transformations. 2779 2934 2780 \sa setWorld Matrix(), setWindow(), setViewport()2935 \sa setWorld(), setWindow(), setViewport() 2781 2936 */ 2782 2937 QMatrix QPainter::combinedMatrix() const … … 2787 2942 2788 2943 /*! 2944 2945 2789 2946 Returns the matrix that transforms from logical coordinates to 2790 2947 device coordinates of the platform dependent paint device. … … 2814 2971 2815 2972 /*! 2973 2974 2816 2975 Resets any transformations that were made using translate(), scale(), 2817 2976 shear(), rotate(), setWorldMatrix(), setViewport() and … … 2838 2997 matrix is not changed. 2839 2998 2840 \sa worldMatrixEnabled(), world Matrix(), {QPainter#Coordinate2999 \sa worldMatrixEnabled(), world(), {QPainter#Coordinate 2841 3000 Transformations}{Coordinate Transformations} 2842 3001 */ … … 2867 3026 false. 2868 3027 2869 \sa setWorldMatrixEnabled(), world Matrix(), {The Coordinate System}3028 \sa setWorldMatrixEnabled(), world(), {The Coordinate System} 2870 3029 */ 2871 3030 … … 2909 3068 Scales the coordinate system by (\a{sx}, \a{sy}). 2910 3069 2911 \sa setWorld Matrix() {QPainter#Coordinate Transformations}{Coordinate3070 \sa setWorld() {QPainter#Coordinate Transformations}{Coordinate 2912 3071 Transformations} 2913 3072 */ … … 2933 3092 Shears the coordinate system by (\a{sh}, \a{sv}). 2934 3093 2935 \sa setWorld Matrix(), {QPainter#Coordinate Transformations}{Coordinate3094 \sa setWorld(), {QPainter#Coordinate Transformations}{Coordinate 2936 3095 Transformations} 2937 3096 */ … … 2959 3118 Rotates the coordinate system the given \a angle clockwise. 2960 3119 2961 \sa setWorld Matrix(), {QPainter#Coordinate Transformations}{Coordinate3120 \sa setWorld(), {QPainter#Coordinate Transformations}{Coordinate 2962 3121 Transformations} 2963 3122 */ … … 2984 3143 given \a offset is added to points. 2985 3144 2986 \sa setWorld Matrix(), {QPainter#Coordinate Transformations}{Coordinate3145 \sa setWorld(), {QPainter#Coordinate Transformations}{Coordinate 2987 3146 Transformations} 2988 3147 */ … … 3048 3207 } 3049 3208 3209 3210 3211 3050 3212 if (d->extended) { 3051 3213 d->state->clipEnabled = true; 3052 3214 d->extended->clip(path, op); 3053 d->state->clipInfo << QPainterClipInfo(path, op, combinedTransform()); 3215 if (op == Qt::NoClip || op == Qt::ReplaceClip) 3216 d->state->clipInfo.clear(); 3217 d->state->clipInfo << QPainterClipInfo(path, op, d->state->matrix); 3054 3218 d->state->clipOperation = op; 3055 3219 return; 3056 3220 } 3057 3058 3059 3060 if (!hasClipping() && (op == Qt::IntersectClip || op == Qt::UniteClip))3061 op = Qt::ReplaceClip;3062 3221 3063 3222 d->state->clipPath = path; … … 3065 3224 if (op == Qt::NoClip || op == Qt::ReplaceClip) 3066 3225 d->state->clipInfo.clear(); 3067 d->state->clipInfo << QPainterClipInfo(path, op, combinedTransform());3226 d->state->clipInfo << QPainterClipInfo(path, op, ); 3068 3227 d->state->clipEnabled = true; 3069 3228 d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled; … … 3713 3872 return; 3714 3873 3874 3875 3715 3876 if (d->extended) { 3716 d->state->pen = pen;3717 3877 d->checkEmulation(); 3718 3878 d->extended->penChanged(); … … 3720 3880 } 3721 3881 3722 // Do some checks to see if we are the same pen.3723 Qt::PenStyle currentStyle = d->state->pen.style();3724 if (currentStyle == pen.style() && currentStyle != Qt::CustomDashLine) {3725 if (currentStyle == Qt::NoPen ||3726 (d->state->pen.isSolid() && pen.isSolid()3727 && d->state->pen.color() == pen.color()3728 && d->state->pen.widthF() == pen.widthF()3729 && d->state->pen.capStyle() == pen.capStyle()3730 && d->state->pen.joinStyle() == pen.joinStyle()3731 && d->state->pen.isCosmetic() == pen.isCosmetic()))3732 return;3733 }3734 3735 d->state->pen = pen;3736 3882 d->state->dirtyFlags |= QPaintEngine::DirtyPen; 3737 3883 } … … 3816 3962 } 3817 3963 3818 Qt::BrushStyle currentStyle = d->state->brush.style();3819 if (currentStyle == brush.style()) {3820 if (currentStyle == Qt::NoBrush3821 || (currentStyle == Qt::SolidPattern3822 && d->state->brush.color() == brush.color()))3823 return;3824 }3825 3826 3964 d->state->brush = brush; 3827 3965 d->state->dirtyFlags |= QPaintEngine::DirtyBrush; … … 3971 4109 \sa drawRect(), QPen 3972 4110 */ 3973 // FALCON: Should we add a specialized method in QPaintEngineEx?3974 4111 void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode) 3975 4112 { … … 3989 4126 3990 4127 if (d->extended) { 3991 QPainterPath::ElementType types[] = { 3992 QPainterPath::MoveToElement, 3993 QPainterPath::LineToElement, 3994 QPainterPath::CurveToElement, 3995 QPainterPath::CurveToDataElement, 3996 QPainterPath::CurveToDataElement, 3997 QPainterPath::LineToElement, 3998 QPainterPath::CurveToElement, 3999 QPainterPath::CurveToDataElement, 4000 QPainterPath::CurveToDataElement, 4001 QPainterPath::LineToElement, 4002 QPainterPath::CurveToElement, 4003 QPainterPath::CurveToDataElement, 4004 QPainterPath::CurveToDataElement, 4005 QPainterPath::LineToElement, 4006 QPainterPath::CurveToElement, 4007 QPainterPath::CurveToDataElement, 4008 QPainterPath::CurveToDataElement 4009 }; 4010 4011 qreal x1 = rect.left(); 4012 qreal x2 = rect.right(); 4013 qreal y1 = rect.top(); 4014 qreal y2 = rect.bottom(); 4015 4016 if (mode == Qt::RelativeSize) { 4017 xRadius = xRadius * rect.width() / 200.; 4018 yRadius = yRadius * rect.height() / 200.; 4019 } 4020 4021 xRadius = qMin(xRadius, rect.width() / 2); 4022 yRadius = qMin(yRadius, rect.height() / 2); 4023 4024 qreal pts[] = { 4025 x1 + xRadius, y1, // MoveTo 4026 x2 - xRadius, y1, // LineTo 4027 x2 - (1 - KAPPA) * xRadius, y1, // CurveTo 4028 x2, y1 + (1 - KAPPA) * yRadius, 4029 x2, y1 + yRadius, 4030 x2, y2 - yRadius, // LineTo 4031 x2, y2 - (1 - KAPPA) * yRadius, // CurveTo 4032 x2 - (1 - KAPPA) * xRadius, y2, 4033 x2 - xRadius, y2, 4034 x1 + xRadius, y2, // LineTo 4035 x1 + (1 - KAPPA) * xRadius, y2, // CurveTo 4036 x1, y2 - (1 - KAPPA) * yRadius, 4037 x1, y2 - yRadius, 4038 x1, y1 + yRadius, // LineTo 4039 x1, y1 + KAPPA * yRadius, // CurveTo 4040 x1 + (1 - KAPPA) * xRadius, y1, 4041 x1 + xRadius, y1 4042 }; 4043 4044 QVectorPath path(pts, 17, types); 4045 d->extended->draw(path); 4128 d->extended->drawRoundedRect(rect, xRadius, yRadius, mode); 4046 4129 return; 4047 4130 } … … 4085 4168 void QPainter::drawRoundRect(const QRectF &r, int xRnd, int yRnd) 4086 4169 { 4087 #ifdef QT_DEBUG_DRAW 4088 if (qt_show_painter_debug_output) 4089 printf("QPainter::drawRoundRectangle(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height()); 4090 #endif 4091 Q_D(QPainter); 4092 4093 if (!d->engine) 4094 return; 4095 4096 if(xRnd <= 0 || yRnd <= 0) { // draw normal rectangle 4097 drawRect(r); 4098 return; 4099 } 4100 4101 QPainterPath path; 4102 path.addRoundRect(r, xRnd, yRnd); 4103 drawPath(path); 4170 drawRoundedRect(r, xRnd, yRnd, Qt::RelativeSize); 4104 4171 } 4105 4172 … … 5122 5189 } 5123 5190 5191 5192 5193 5194 5195 5124 5196 /*! 5125 5197 \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source) … … 5174 5246 int h = pm.height(); 5175 5247 5248 5249 5250 5176 5251 // Emulate opaque background for bitmaps 5177 5252 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) { … … 5187 5262 { 5188 5263 save(); 5189 // If there is no scaling or transformation involved we have to make sure we use the5264 // If there is no ation involved we have to make sure we use the 5190 5265 // antialiased and not the aliased coordinate system by rounding the coordinates. 5191 if (d->state->matrix.type() <= QTransform::TxTranslate) { 5192 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); 5193 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); 5266 if (d->state->matrix.type() <= QTransform::TxScale) { 5267 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); 5268 x = p.x(); 5269 y = p.y(); 5194 5270 } 5195 5271 translate(x, y); … … 5301 5377 { 5302 5378 save(); 5303 // If there is no scaling or transformation involved we have to make sure we use the5379 // If there is no ation involved we have to make sure we use the 5304 5380 // antialiased and not the aliased coordinate system by rounding the coordinates. 5381 5382 5383 5384 5385 5386 5305 5387 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) { 5306 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();5307 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();5308 5388 sx = qRound(sx); 5309 5389 sy = qRound(sy); … … 5311 5391 sh = qRound(sh); 5312 5392 } 5393 5313 5394 translate(x, y); 5314 5395 scale(w / sw, h / sh); … … 5460 5541 { 5461 5542 save(); 5462 // If there is no scaling or transformation involved we have to make sure we use the5543 // If there is no ation involved we have to make sure we use the 5463 5544 // antialiased and not the aliased coordinate system by rounding the coordinates. 5464 if (d->state->matrix.type() <= QTransform::TxTranslate) { 5465 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx(); 5466 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy(); 5545 if (d->state->matrix.type() <= QTransform::TxScale) { 5546 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix); 5547 x = p.x(); 5548 y = p.y(); 5467 5549 } 5468 5550 translate(x, y); … … 5563 5645 { 5564 5646 save(); 5565 // If there is no scaling or transformation involved we have to make sure we use the5647 // If there is no ation involved we have to make sure we use the 5566 5648 // antialiased and not the aliased coordinate system by rounding the coordinates. 5649 5650 5651 5652 5653 5654 5567 5655 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) { 5568 x = qRound(x + d->state->matrix.dx()) - d->state->matrix.dx();5569 y = qRound(y + d->state->matrix.dy()) - d->state->matrix.dy();5570 5656 sx = qRound(sx); 5571 5657 sy = qRound(sy); … … 5659 5745 } 5660 5746 QFixed x = QFixed::fromReal(p.x()); 5661 QFixed ox = x;5662 5747 5663 5748 for (int i = 0; i < nItems; ++i) { … … 5886 5971 */ 5887 5972 5888 /*! \internal 5973 /*! 5974 \fn void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti) 5975 5976 \internal 5977 \since 4.1 5978 5889 5979 Draws the text item \a ti at position \a p. 5890 5980 … … 5899 5989 underlining and strikeout. 5900 5990 */ 5901 static QPainterPath generateWavyPath(qreal minWidth, qreal maxRadius, QPaintDevice *device) 5902 { 5903 extern int qt_defaultDpi(); 5991 5992 static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) 5993 { 5994 const qreal radiusBase = qMax(qreal(1), maxRadius); 5995 5996 QString key = QLatin1String("WaveUnderline-"); 5997 key += pen.color().name(); 5998 key += QLatin1Char('-'); 5999 key += QString::number(radiusBase); 6000 6001 QPixmap pixmap; 6002 if (QPixmapCache::find(key, pixmap)) 6003 return pixmap; 6004 6005 const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio 6006 const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod); 6007 const int radius = qFloor(radiusBase); 6008 5904 6009 QPainterPath path; 5905 6010 5906 bool up = true; 5907 const qreal radius = qMax(qreal(.5), qMin(qreal(1.25 * device->logicalDpiY() / qt_defaultDpi()), maxRadius)); 5908 qreal xs, ys; 5909 int i = 0; 5910 path.moveTo(0, radius); 5911 do { 5912 xs = i*(2*radius); 5913 ys = 0; 5914 5915 qreal remaining = minWidth - xs; 5916 qreal angle = 180; 5917 5918 // cut-off at the last arc segment 5919 if (remaining < 2 * radius) 5920 angle = 180 * remaining / (2 * radius); 5921 5922 path.arcTo(xs, ys, 2*radius, 2*radius, 180, up ? angle : -angle); 5923 5924 up = !up; 5925 ++i; 5926 } while (xs + 2*radius < minWidth); 5927 5928 return path; 6011 qreal xs = 0; 6012 qreal ys = radius; 6013 6014 while (xs < width) { 6015 xs += halfPeriod; 6016 ys = -ys; 6017 path.quadTo(xs - halfPeriod / 2, ys, xs, 0); 6018 } 6019 6020 pixmap = QPixmap(width, radius * 2); 6021 pixmap.fill(Qt::transparent); 6022 { 6023 QPen wavePen = pen; 6024 wavePen.setCapStyle(Qt::SquareCap); 6025 6026 // This is to protect against making the line too fat, as happens on Mac OS X 6027 // due to it having a rather thick width for the regular underline. 6028 const qreal maxPenWidth = .8 * radius; 6029 if (wavePen.widthF() > maxPenWidth) 6030 wavePen.setWidth(maxPenWidth); 6031 6032 QPainter imgPainter(&pixmap); 6033 imgPainter.setPen(wavePen); 6034 imgPainter.setRenderHint(QPainter::Antialiasing); 6035 imgPainter.translate(0, radius); 6036 imgPainter.drawPath(path); 6037 } 6038 6039 QPixmapCache::insert(key, pixmap); 6040 6041 return pixmap; 5929 6042 } 5930 6043 … … 5947 6060 5948 6061 QLineF line(pos.x(), pos.y(), pos.x() + ti.width.toReal(), pos.y()); 6062 6063 5949 6064 // deliberately ceil the offset to avoid the underline coming too close to 5950 6065 // the text above it. 5951 const qreal underlinePos = pos.y() + qCeil( fe->underlinePosition().toReal());6066 const qreal underlinePos = pos.y() + qCeil(); 5952 6067 5953 6068 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { … … 5957 6072 if (underlineStyle == QTextCharFormat::WaveUnderline) { 5958 6073 painter->save(); 5959 painter->setRenderHint(QPainter::Antialiasing); 5960 painter->translate(pos.x(), underlinePos); 6074 painter->translate(0, pos.y() + 1); 5961 6075 5962 6076 QColor uc = ti.charFormat.underlineColor(); 5963 6077 if (uc.isValid()) 5964 painter->setPen(uc); 5965 5966 painter->drawPath(generateWavyPath(ti.width.toReal(), 5967 fe->underlinePosition().toReal(), 5968 painter->device())); 6078 pen.setColor(uc); 6079 6080 // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms 6081 const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen); 6082 const int descent = (int) ti.descent.toReal(); 6083 6084 painter->setBrushOrigin(painter->brushOrigin().x(), 0); 6085 painter->fillRect(pos.x(), 0, qCeil(ti.width.toReal()), qMin(wave.height(), descent), wave); 5969 6086 painter->restore(); 5970 6087 } else if (underlineStyle != QTextCharFormat::NoUnderline) { … … 6001 6118 } 6002 6119 6003 /*!6004 \internal6005 \since 4.16006 */6007 6120 void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) 6008 6121 { … … 6043 6156 if (d->state->matrix.type() < QTransform::TxShear) { 6044 6157 bool isPlain90DegreeRotation = 6045 (qFuzzy Compare(m.m11() + 1, qreal(1))6046 && qFuzzy Compare(m.m12(),qreal(1))6047 && qFuzzy Compare(m.m21(), qreal(-1))6048 && qFuzzy Compare(m.m22() + 1, qreal(1))6158 (qFuzzy)) 6159 && qFuzzy qreal(1)) 6160 && qFuzzy1)) 6161 && qFuzzy)) 6049 6162 ) 6050 6163 || 6051 (qFuzzy Compare(m.m11(), qreal(-1))6052 && qFuzzy Compare(m.m12() + 1, qreal(1))6053 && qFuzzy Compare(m.m21() + 1, qreal(1))6054 && qFuzzy Compare(m.m22(), qreal(-1))6164 (qFuzzy1)) 6165 && qFuzzy)) 6166 && qFuzzy)) 6167 && qFuzzy1)) 6055 6168 ) 6056 6169 || 6057 (qFuzzy Compare(m.m11() + 1, qreal(1))6058 && qFuzzy Compare(m.m12(), qreal(-1))6059 && qFuzzy Compare(m.m21(),qreal(1))6060 && qFuzzy Compare(m.m22() + 1, qreal(1))6170 (qFuzzy)) 6171 && qFuzzy1)) 6172 && qFuzzy qreal(1)) 6173 && qFuzzy)) 6061 6174 ) 6062 6175 ; … … 6310 6423 setPen(Qt::NoPen); 6311 6424 6312 // If there is no scaling or transformation involved we have to make sure we use the6425 // If there is no ation involved we have to make sure we use the 6313 6426 // antialiased and not the aliased coordinate system by rounding the coordinates. 6314 if (d->state->matrix.type() <= QTransform::TxTranslate) { 6315 qreal x = qRound(r.x() + d->state->matrix.dx()) - d->state->matrix.dx(); 6316 qreal y = qRound(r.y() + d->state->matrix.dy()) - d->state->matrix.dy(); 6317 qreal w = qRound(r.width()); 6318 qreal h = qRound(r.height()); 6319 sx = qRound(sx); 6320 sy = qRound(sy); 6427 if (d->state->matrix.type() <= QTransform::TxScale) { 6428 const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix); 6429 6430 if (d->state->matrix.type() <= QTransform::TxTranslate) { 6431 sx = qRound(sx); 6432 sy = qRound(sy); 6433 } 6434 6321 6435 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy)); 6322 drawRect(QRectF( x, y, w, h));6436 drawRect(QRectF()); 6323 6437 } else { 6324 6438 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy)); … … 6748 6862 false. 6749 6863 6750 \sa setViewTransformEnabled(), world Matrix()6864 \sa setViewTransformEnabled(), world() 6751 6865 */ 6752 6866 … … 6904 7018 \compat 6905 7019 6906 Use reset Matrix() instead.7020 Use reset() instead. 6907 7021 */ 6908 7022 … … 6950 7064 6951 7065 /*! 6952 Use the worldMatrix() combined with QMatrix::dx() instead. 7066 \obsolete 7067 7068 Use the worldTransform() combined with QTransform::dx() instead. 6953 7069 6954 7070 \oldcode … … 6957 7073 \newcode 6958 7074 QPainter painter(this); 6959 qreal x = painter.world Matrix().dx();7075 qreal x = painter.world().dx(); 6960 7076 \endcode 6961 7077 */ … … 6971 7087 6972 7088 /*! 6973 Use the worldMatrix() combined with QMatrix::dy() instead. 7089 \obsolete 7090 7091 Use the worldTransform() combined with QTransform::dy() instead. 6974 7092 6975 7093 \oldcode … … 6978 7096 \newcode 6979 7097 QPainter painter(this); 6980 qreal y = painter.world Matrix().dy();7098 qreal y = painter.world().dy(); 6981 7099 \endcode 6982 7100 */ … … 7076 7194 \newcode 7077 7195 QPainter painter(this); 7078 QPolygon transformed = polygon.mid(index, count) * painter.combined Matrix();7196 QPolygon transformed = polygon.mid(index, count) * painter.combined(); 7079 7197 \endcode 7080 7198 */ … … 7091 7209 \fn QPoint QPainter::xFormDev(const QPoint &point) const 7092 7210 \overload 7093 7094 Use combinedTransform() combined with QMatrix::inverted() instead. 7211 \obsolete 7212 7213 Use combinedTransform() combined with QTransform::inverted() instead. 7095 7214 7096 7215 \oldcode … … 7099 7218 \newcode 7100 7219 QPainter painter(this); 7101 QPoint transformed = point * painter.combined Matrix().inverted();7220 QPoint transformed = point * painter.combined().inverted(); 7102 7221 \endcode 7103 7222 */ … … 7118 7237 \fn QRect QPainter::xFormDev(const QRect &rectangle) const 7119 7238 \overload 7120 7121 Use combineMatrix() combined with QMatrix::inverted() instead. 7239 \obsolete 7240 7241 Use combinedTransform() combined with QTransform::inverted() instead. 7122 7242 7123 7243 \oldcode … … 7126 7246 \newcode 7127 7247 QPainter painter(this); 7128 QRect transformed = rectangle * painter.combinedMatrix().inverted(); 7248 QRegion region = QRegion(rectangle) * painter.combinedTransform().inverted(); 7249 QRect transformed = region.boundingRect(); 7129 7250 \endcode 7130 7251 */ … … 7146 7267 7147 7268 \fn QPoint QPainter::xFormDev(const QPolygon &polygon) const 7148 \o verload7149 7150 Use combined Matrix() combined with QMatrix::inverted() instead.7269 \o 7270 7271 Use combined::inverted() instead. 7151 7272 7152 7273 \oldcode … … 7155 7276 \newcode 7156 7277 QPainter painter(this); 7157 QPolygon transformed = polygon * painter.combined Matrix().inverted();7278 QPolygon transformed = polygon * painter.combined().inverted(); 7158 7279 \endcode 7159 7280 */ … … 7174 7295 \fn QPolygon QPainter::xFormDev(const QPolygon &polygon, int index, int count) const 7175 7296 \overload 7176 7177 Use combinedMatrix() combined with QPolygon::mid() and QMatrix::inverted() instead. 7297 \obsolete 7298 7299 Use combinedTransform() combined with QPolygon::mid() and QTransform::inverted() instead. 7178 7300 7179 7301 \oldcode … … 7182 7304 \newcode 7183 7305 QPainter painter(this); 7184 QPolygon transformed = polygon.mid(index, count) * painter.combined Matrix().inverted();7306 QPolygon transformed = polygon.mid(index, count) * painter.combined().inverted(); 7185 7307 \endcode 7186 7308 */ … … 7377 7499 void qt_painter_removePaintDevice(QPaintDevice *dev) 7378 7500 { 7379 QMutexLocker locker(globalRedirectionsMutex()); 7380 if(QPaintDeviceRedirectionList *redirections = globalRedirections()) { 7501 QMutex *mutex = 0; 7502 QT_TRY { 7503 mutex = globalRedirectionsMutex(); 7504 } QT_CATCH(...) { 7505 // ignore the missing mutex, since we could be called from 7506 // a destructor, and destructors shall not throw 7507 } 7508 QMutexLocker locker(mutex); 7509 QPaintDeviceRedirectionList *redirections = 0; 7510 QT_TRY { 7511 redirections = globalRedirections(); 7512 } QT_CATCH(...) { 7513 // do nothing - code below is safe with redirections being 0. 7514 } 7515 if (redirections) { 7381 7516 for (int i = 0; i < redirections->size(); ) { 7382 7517 if(redirections->at(i) == dev || redirections->at(i).replacement == dev) … … 7428 7563 7429 7564 Qt::LayoutDirection layout_direction; 7430 if(option) 7565 if (tf & Qt::TextForceLeftToRight) 7566 layout_direction = Qt::LeftToRight; 7567 else if (tf & Qt::TextForceRightToLeft) 7568 layout_direction = Qt::RightToLeft; 7569 else if (option) 7431 7570 layout_direction = option->textDirection(); 7432 7571 else if (painter) … … 7445 7584 tf |= Qt::TextDontPrint; 7446 7585 7447 int maxUnderlines = 0;7586 int maxUnderlines = 0; 7448 7587 int numUnderlines = 0; 7449 int underlinePositionStack[32]; 7450 int *underlinePositions = underlinePositionStack; 7588 QVarLengthArray<int, 32> underlinePositions(1); 7451 7589 7452 7590 QFontMetricsF fm(fnt); 7453 7454 7591 QString text = str; 7592 7593 7594 7455 7595 // compatible behaviour to the old implementation. Replace 7456 7596 // tabs by spaces 7457 QChar *chr = text.data(); 7458 const QChar *end = chr + str.length(); 7459 bool has_tab = false; 7460 while (chr != end) { 7461 if (*chr == QLatin1Char('\r') || (singleline && *chr == QLatin1Char('\n'))) { 7462 *chr = QLatin1Char(' '); 7463 } else if (*chr == QLatin1Char('\n')) { 7464 *chr = QChar::LineSeparator; 7465 } else if (*chr == QLatin1Char('&')) { 7597 int old_offset = offset; 7598 for (; offset < text.length(); offset++) { 7599 QChar chr = text.at(offset); 7600 if (chr == QLatin1Char('\r') || (singleline && chr == QLatin1Char('\n'))) { 7601 text[offset] = QLatin1Char(' '); 7602 } else if (chr == QLatin1Char('\n')) { 7603 text[offset] = QChar::LineSeparator; 7604 } else if (chr == QLatin1Char('&')) { 7466 7605 ++maxUnderlines; 7467 } else if (*chr == QLatin1Char('\t')) { 7468 has_tab = true; 7606 } else if (chr == QLatin1Char('\t')) { 7607 if (!expandtabs) { 7608 text[offset] = QLatin1Char(' '); 7609 } else if (!tabarraylen && !tabstops) { 7610 tabstops = qRound(fm.width(QLatin1Char('x'))*8); 7611 } 7612 } else if (chr == QChar(ushort(0x9c))) { 7613 // string with multiple length variants 7614 hasMoreLengthVariants = true; 7615 break; 7469 7616 } 7470 ++chr; 7471 } 7472 if (has_tab) { 7473 if (!expandtabs) { 7474 chr = text.data(); 7475 while (chr != end) { 7476 if (*chr == QLatin1Char('\t')) 7477 *chr = QLatin1Char(' '); 7478 ++chr; 7479 } 7480 } else if (!tabarraylen && !tabstops) { 7481 tabstops = qRound(fm.width(QLatin1Char('x'))*8); 7482 } 7483 } 7484 7485 if (hidemnmemonic || showmnemonic) { 7486 if (maxUnderlines > 32) 7487 underlinePositions = new int[maxUnderlines]; 7488 QChar *cout = text.data(); 7617 } 7618 7619 int length = offset - old_offset; 7620 if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) { 7621 underlinePositions.resize(maxUnderlines + 1); 7622 7623 QChar *cout = text.data() + old_offset; 7489 7624 QChar *cin = cout; 7490 int l = str.length();7625 int l = ; 7491 7626 while (l) { 7492 7627 if (*cin == QLatin1Char('&')) { 7493 7628 ++cin; 7629 7494 7630 --l; 7495 7631 if (!l) 7496 7632 break; 7497 7633 if (*cin != QLatin1Char('&') && !hidemnmemonic) 7498 underlinePositions[numUnderlines++] = cout - text. unicode();7634 underlinePositions[numUnderlines++] = cout - text.; 7499 7635 } 7500 7636 *cout = *cin; … … 7503 7639 --l; 7504 7640 } 7505 int newlen = cout - text.unicode();7506 if (newlen != text.length())7507 text.resize(newlen);7508 7641 } 7509 7642 … … 7516 7649 qreal width = 0; 7517 7650 7518 QStackTextEngine engine(text, fnt); 7651 QString finalText = text.mid(old_offset, length); 7652 QStackTextEngine engine(finalText, fnt); 7519 7653 if (option) { 7520 7654 engine.option = *option; 7521 7655 } 7522 7523 7524 7656 7525 7657 engine.option.setTextDirection(layout_direction); … … 7536 7668 QTextLayout textLayout(&engine); 7537 7669 textLayout.setCacheEnabled(true); 7538 textLayout.engine()->underlinePositions = underlinePositions ;7539 7540 if ( text.isEmpty()) {7670 textLayout.engine()->underlinePositions = underlinePositions; 7671 7672 if (ext.isEmpty()) { 7541 7673 height = fm.height(); 7542 7674 width = 0; … … 7564 7696 height += l.height(); 7565 7697 width = qMax(width, l.naturalTextWidth()); 7566 if (! brect && height >= r.height())7698 if (!brect && height >= r.height()) 7567 7699 break; 7568 7700 } … … 7583 7715 const qreal scale = painter->transform().m22(); 7584 7716 if (scale != 0) 7585 yoff = qRound(yoff * scale) / scale;7717 yoff = yoff * scale) / scale; 7586 7718 } 7587 7719 } … … 7603 7735 } 7604 7736 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height); 7737 7738 7739 7740 7741 7605 7742 if (brect) 7606 7743 *brect = bounds; … … 7629 7766 } 7630 7767 } 7631 7632 if (underlinePositions != underlinePositionStack)7633 delete [] underlinePositions;7634 7768 } 7635 7769 … … 7664 7798 clipOperation(s->clipOperation), 7665 7799 renderHints(s->renderHints), clipInfo(s->clipInfo), 7666 worldMatrix(s->worldMatrix), matrix(s->matrix), redirection _offset(s->redirection_offset),7800 worldMatrix(s->worldMatrix), matrix(s->matrix), redirection), 7667 7801 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh), 7668 7802 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh), … … 8086 8220 \row \o QPaintEngine::DirtyCompositionMode \o compositionMode() 8087 8221 \row \o QPaintEngine::DirtyFont \o font() 8088 \row \o QPaintEngine::DirtyTransform \o matrix()8222 \row \o QPaintEngine::DirtyTransform \o () 8089 8223 \row \o QPaintEngine::DirtyClipEnabled \o isClipEnabled() 8090 8224 \row \o QPaintEngine::DirtyPen \o pen() … … 8205 8339 /*! 8206 8340 \since 4.2 8341 8207 8342 8208 8343 Returns the matrix in the current paint engine 8209 8344 state. 8345 8346 8347 8210 8348 8211 8349 This variable should only be used when the state() returns a … … 8389 8527 the current matrix; otherwise it replaces the current matrix. 8390 8528 8391 This function has been added for compatibility with setMatrix(), 8392 but as with setMatrix() the preferred method of setting a 8393 transformation on the painter is through setWorldTransform(). 8394 8395 \sa transform() 8529 \sa transform() setWorldTransform() 8396 8530 */ 8397 8531 … … 8403 8537 /*! 8404 8538 Returns the world transformation matrix. 8539 8540 8405 8541 */ 8406 8542 … … 8513 8649 window/viewport and world transformation. 8514 8650 8515 \sa setWorld Matrix(), setWindow(), setViewport()8651 \sa setWorld(), setWindow(), setViewport() 8516 8652 */ 8517 8653 … … 8531 8667 } 8532 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8533 8917 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.
