diff options
Diffstat (limited to 'src/gui/painting')
76 files changed, 3937 insertions, 1538 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index b3b647a..f1496b1 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -35,6 +35,7 @@ HEADERS += \ painting/qprinter.h \ painting/qprinter_p.h \ painting/qprinterinfo.h \ + painting/qprinterinfo_p.h \ painting/qrasterizer_p.h \ painting/qregion.h \ painting/qstroker_p.h \ @@ -74,6 +75,7 @@ SOURCES += \ painting/qprintengine_pdf.cpp \ painting/qprintengine_ps.cpp \ painting/qprinter.cpp \ + painting/qprinterinfo.cpp \ painting/qrasterizer.cpp \ painting/qregion.cpp \ painting/qstroker.cpp \ @@ -88,14 +90,18 @@ SOURCES += \ painting/qpaintengine_raster.cpp \ painting/qdrawhelper.cpp \ painting/qimagescale.cpp \ - painting/qgrayraster.c + painting/qgrayraster.c \ + painting/qpaintengine_blitter.cpp \ + painting/qblittable.cpp \ HEADERS += \ painting/qpaintengine_raster_p.h \ painting/qdrawhelper_p.h \ painting/qblendfunctions_p.h \ painting/qrasterdefs_p.h \ - painting/qgrayraster_p.h + painting/qgrayraster_p.h \ + painting/qpaintengine_blitter_p.h \ + painting/qblittable_p.h \ win32 { HEADERS += painting/qprintengine_win_p.h @@ -116,20 +122,20 @@ embedded { SOURCES += \ painting/qgraphicssystem_qws.cpp \ -} else { +} else: if(!qpa) { HEADERS += \ painting/qgraphicssystem_raster_p.h \ painting/qgraphicssystem_runtime_p.h \ painting/qgraphicssystemfactory_p.h \ painting/qgraphicssystemplugin_p.h \ - painting/qwindowsurface_raster_p.h \ + painting/qwindowsurface_raster_p.h SOURCES += \ painting/qgraphicssystem_raster.cpp \ painting/qgraphicssystem_runtime.cpp \ painting/qgraphicssystemfactory.cpp \ painting/qgraphicssystemplugin.cpp \ - painting/qwindowsurface_raster.cpp \ + painting/qwindowsurface_raster.cpp } unix:x11 { @@ -142,7 +148,7 @@ unix:x11 { painting/qpaintengine_x11.cpp } -!embedded:!x11:mac { +!embedded:!qpa:!x11:mac { HEADERS += \ painting/qpaintengine_mac_p.h \ painting/qgraphicssystem_mac_p.h \ @@ -158,14 +164,14 @@ unix:x11 { painting/qprintengine_mac.mm \ } -unix:!mac:!symbian { +unix:!mac:!symbian|qpa { HEADERS += \ painting/qprinterinfo_unix_p.h SOURCES += \ painting/qprinterinfo_unix.cpp } -win32|x11|mac|embedded|symbian { +win32|x11|mac|embedded|qpa|symbian { SOURCES += painting/qbackingstore.cpp HEADERS += painting/qbackingstore_p.h } @@ -182,6 +188,12 @@ embedded { painting/qpaintdevice_qws.cpp } +qpa { + SOURCES += \ + painting/qcolormap_qpa.cpp \ + painting/qpaintdevice_qpa.cpp +} + symbian { SOURCES += \ painting/qpaintengine_s60.cpp \ @@ -192,7 +204,7 @@ symbian { painting/qpaintengine_s60_p.h } -x11|embedded { +x11|embedded|qpa { contains(QT_CONFIG,qtopia) { DEFINES += QT_NO_CUPS QT_NO_LPR } else { @@ -222,9 +234,11 @@ x11 { SOURCES += painting/qwindowsurface_x11.cpp } -mac { - HEADERS += painting/qwindowsurface_mac_p.h - SOURCES += painting/qwindowsurface_mac.cpp +!embedded:!qpa:mac { + HEADERS += painting/qwindowsurface_mac_p.h \ + painting/qunifiedtoolbarsurface_mac_p.h + SOURCES += painting/qwindowsurface_mac.cpp \ + painting/qunifiedtoolbarsurface_mac.cpp } embedded { diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 4fcff1d..42c1c35 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -98,6 +98,21 @@ static inline void qt_flush(QWidget *widget, const QRegion ®ion, QWindowSurfa QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false); #endif + //The performance hit by doing this should be negligible. However, be aware that + //using this FPS when you have > 1 windowsurface can give you inaccurate FPS + static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt(); + if (fpsDebug) { + static QTime time = QTime::currentTime(); + static int frames = 0; + + frames++; + + if(time.elapsed() > 5000) { + double fps = double(frames * 1000) /time.restart(); + fprintf(stderr,"FPS: %.1f\n",fps); + frames = 0; + } + } if (widget != tlw) windowSurface->flush(widget, region, tlwOffset + widget->mapTo(tlw, QPoint())); else @@ -271,7 +286,11 @@ bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *wi void QWidgetBackingStore::releaseBuffer() { if (windowSurface) +#if defined(Q_WS_QPA) + windowSurface->resize(QSize()); +#else windowSurface->setGeometry(QRect()); +#endif #ifdef Q_BACKINGSTORE_SUBSURFACES for (int i = 0; i < subSurfaces.size(); ++i) subSurfaces.at(i)->setGeometry(QRect()); @@ -401,7 +420,11 @@ QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const { const bool widgetDirty = widget && widget != tlw; const QRect tlwRect(topLevelRect()); +#if defined(Q_WS_QPA) + const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size()); +#else const QRect surfaceGeometry(windowSurface->geometry()); +#endif if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) { if (widgetDirty) { const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); @@ -452,7 +475,11 @@ QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const { if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) { +#if defined(Q_WS_QPA) + const QSize surfaceGeometry(windowSurface->size()); +#else const QRect surfaceGeometry(windowSurface->geometry()); +#endif QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); if (!withinClipRect.isEmpty()) surfaceRect &= withinClipRect; @@ -561,7 +588,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up return; } - if (!windowSurface->hasPartialUpdateSupport()) { + if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { fullUpdatePending = true; sendUpdateRequest(tlw, updateImmediately); return; @@ -656,7 +683,7 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd return; } - if (!windowSurface->hasPartialUpdateSupport()) { + if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { fullUpdatePending = true; sendUpdateRequest(tlw, updateImmediately); return; @@ -720,9 +747,8 @@ void QWidgetBackingStore::markDirtyOnScreen(const QRegion ®ion, QWidget *widg } // Alien widgets. - if (!widget->internalWinId()) { - QWidget *nativeParent = widget->nativeParentWidget(); - // Alien widgets with the top-level as the native parent (common case). + if (!widget->internalWinId() && !widget->isWindow()) { + QWidget *nativeParent = widget->nativeParentWidget(); // Alien widgets with the top-level as the native parent (common case). if (nativeParent == tlw) { if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) dirtyOnScreen += region.translated(topLevelOffset); @@ -1117,9 +1143,9 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg return; } - // If there's no partial update support we always need + // If there's no preserved contents support we always need // to do a full repaint before flushing - if (!windowSurface->hasPartialUpdateSupport()) + if (!windowSurface->hasFeature(QWindowSurface::PreservedContents)) fullUpdatePending = true; // Nothing to repaint. @@ -1157,12 +1183,16 @@ void QWidgetBackingStore::sync() return; } - const bool inTopLevelResize = tlwExtra->inTopLevelResize; const bool updatesDisabled = !tlw->updatesEnabled(); - const QRect tlwRect(topLevelRect()); - const QRect surfaceGeometry(windowSurface->geometry()); bool repaintAllWidgets = false; + const bool inTopLevelResize = tlwExtra->inTopLevelResize; + const QRect tlwRect(topLevelRect()); +#ifdef Q_WS_QPA + const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size()); +#else + const QRect surfaceGeometry(windowSurface->geometry()); +#endif if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { if (hasStaticContents()) { // Repaint existing dirty area and newly visible area. @@ -1182,8 +1212,13 @@ void QWidgetBackingStore::sync() } } +#ifdef Q_WS_QPA + if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) + windowSurface->resize(tlwRect.size()); +#else if (inTopLevelResize || surfaceGeometry != tlwRect) windowSurface->setGeometry(tlwRect); +#endif if (updatesDisabled) return; @@ -1590,7 +1625,11 @@ void QWidgetPrivate::repaint_sys(const QRegion &rgn) extra->staticContentsSize = data.crect.size(); } +#ifdef Q_WS_QPA //Dont even call q->p + QPaintEngine *engine = 0; +#else QPaintEngine *engine = q->paintEngine(); +#endif // QGLWidget does not support partial updates if: // 1) The context is double buffered // 2) The context is single buffered and auto-fill background is enabled. diff --git a/src/gui/painting/qbackingstore_p.h b/src/gui/painting/qbackingstore_p.h index e2b21c3..05f4bfc 100644 --- a/src/gui/painting/qbackingstore_p.h +++ b/src/gui/painting/qbackingstore_p.h @@ -209,8 +209,9 @@ private: { #ifdef Q_WS_QWS return tlw->frameGeometry(); -#endif +#else return tlw->data->crect; +#endif } inline void appendDirtyOnScreenWidget(QWidget *widget) @@ -261,7 +262,7 @@ private: } inline bool hasStaticContents() const - { return !staticWidgets.isEmpty() && windowSurface->hasStaticContentsSupport(); } + { return !staticWidgets.isEmpty() && windowSurface->hasFeature(QWindowSurface::StaticContents); } friend QRegion qt_dirtyRegion(QWidget *); friend class QWidgetPrivate; diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index 119cf1c..a2f0edd 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -65,13 +65,6 @@ QT_BEGIN_NAMESPACE #define M_SQRT2 1.41421356237309504880 #endif -#define log2(x) (qLn(x)/qLn(2.)) - -static inline qreal log4(qreal x) -{ - return qreal(0.5) * log2(x); -} - /*! \internal */ @@ -184,7 +177,7 @@ static inline bool findInflections(qreal a, qreal b, qreal c, *t2 = r1; } if (!qFuzzyIsNull(a)) - *tCups = 0.5 * (-b / a); + *tCups = qreal(0.5) * (-b / a); else *tCups = 2; @@ -274,8 +267,8 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse const qreal o2 = offset*offset; const qreal max_dist_line = threshold*offset*offset; const qreal max_dist_normal = threshold*offset; - const qreal spacing = 0.25; - for (qreal i = spacing; i < 0.99; i += spacing) { + const qreal spacing = qreal(0.25); + for (qreal i = spacing; i < qreal(0.99); i += spacing) { QPointF p1 = b1->pointAt(i); QPointF p2 = b2->pointAt(i); qreal d = (p1.x() - p2.x())*(p1.x() - p2.x()) + (p1.y() - p2.y())*(p1.y() - p2.y()); @@ -284,7 +277,7 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse QPointF normalPoint = b1->normalVector(i); qreal l = qAbs(normalPoint.x()) + qAbs(normalPoint.y()); - if (l != 0.) { + if (l != qreal(0.0)) { d = qAbs( normalPoint.x()*(p1.y() - p2.y()) - normalPoint.y()*(p1.x() - p2.x()) ) / l; if (d > max_dist_normal) return Split; @@ -350,7 +343,7 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr QPointF normal_sum = prev_normal + next_normal; - qreal r = 1.0 + prev_normal.x() * next_normal.x() + qreal r = qreal(1.0) + prev_normal.x() * next_normal.x() + prev_normal.y() * next_normal.y(); if (qFuzzyIsNull(r)) { @@ -374,7 +367,7 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr // This value is used to determine the length of control point vectors // when approximating arc segments as curves. The factor is multiplied // with the radius of the circle. -#define KAPPA 0.5522847498 +#define KAPPA qreal(0.5522847498) static bool addCircle(const QBezier *b, qreal offset, QBezier *o) @@ -417,11 +410,11 @@ static bool addCircle(const QBezier *b, qreal offset, QBezier *o) QPointF circle[3]; circle[0] = QPointF(b->x1, b->y1) + normals[0]*offset; - circle[1] = QPointF(0.5*(b->x1 + b->x4), 0.5*(b->y1 + b->y4)) + normals[1]*offset; + circle[1] = QPointF(qreal(0.5)*(b->x1 + b->x4), qreal(0.5)*(b->y1 + b->y4)) + normals[1]*offset; circle[2] = QPointF(b->x4, b->y4) + normals[2]*offset; for (int i = 0; i < 2; ++i) { - qreal kappa = 2.*KAPPA * sign * offset * angles[i]; + qreal kappa = qreal(2.0) * KAPPA * sign * offset * angles[i]; o->x1 = circle[i].x(); o->y1 = circle[i].y(); @@ -456,8 +449,8 @@ redo: while (b >= beziers) { int stack_segments = b - beziers + 1; if ((stack_segments == 10) || (o - curveSegments == maxSegments - stack_segments)) { - threshold *= 1.5; - if (threshold > 2.) + threshold *= qreal(1.5); + if (threshold > qreal(2.0)) goto give_up; goto redo; } @@ -535,7 +528,7 @@ static inline void splitBezierAt(const QBezier &bez, qreal t, qreal QBezier::length(qreal error) const { - qreal length = 0.0; + qreal length = qreal(0.0); addIfClose(&length, error); @@ -546,8 +539,8 @@ void QBezier::addIfClose(qreal *length, qreal error) const { QBezier left, right; /* bez poly splits */ - qreal len = 0.0; /* arc length */ - qreal chord; /* chord length */ + qreal len = qreal(0.0); /* arc length */ + qreal chord; /* chord length */ len = len + QLineF(QPointF(x1, y1),QPointF(x2, y2)).length(); len = len + QLineF(QPointF(x2, y2),QPointF(x3, y3)).length(); @@ -589,7 +582,7 @@ qreal QBezier::tForY(qreal t0, qreal t1, qreal y) const qreal lt = t0; qreal dt; do { - qreal t = 0.5 * (t0 + t1); + qreal t = qreal(0.5) * (t0 + t1); qreal a, b, c, d; QBezier::coefficients(t, a, b, c, d); @@ -604,7 +597,7 @@ qreal QBezier::tForY(qreal t0, qreal t1, qreal y) const } dt = lt - t; lt = t; - } while (qAbs(dt) > 1e-7); + } while (qAbs(dt) > qreal(1e-7)); return t0; } @@ -661,15 +654,15 @@ int QBezier::stationaryYPoints(qreal &t0, qreal &t1) const qreal QBezier::tAtLength(qreal l) const { qreal len = length(); - qreal t = 1.0; - const qreal error = (qreal)0.01; + qreal t = qreal(1.0); + const qreal error = qreal(0.01); if (l > len || qFuzzyCompare(l, len)) return t; - t *= 0.5; + t *= qreal(0.5); //int iters = 0; //qDebug()<<"LEN is "<<l<<len; - qreal lastBigger = 1.; + qreal lastBigger = qreal(1.0); while (1) { //qDebug()<<"\tt is "<<t; QBezier right = *this; @@ -680,10 +673,10 @@ qreal QBezier::tAtLength(qreal l) const break; if (lLen < l) { - t += (lastBigger - t)*.5; + t += (lastBigger - t) * qreal(0.5); } else { lastBigger = t; - t -= t*.5; + t -= t * qreal(0.5); } //++iters; } diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 517959e..10674f8 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -309,9 +309,9 @@ template <typename T> void qt_blend_argb24_on_rgb16(uchar *destPixels, int dbpl, const uchar *src = srcPixels + y * sbpl; const uchar *srcEnd = src + srcOffset; while (src < srcEnd) { -#if defined(QT_ARCH_ARM) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU)) +#if defined(QT_ARCH_ARMV5) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU)) || (defined(QT_ARCH_INTEGRITY) && !defined(_X86_)) // non-16-bit aligned memory access is not possible on PowerPC, - // ARM <v6 (QT_ARCH_ARMV6) & SH & AVR32 & SPARC w/GCC + // ARM <v6 (QT_ARCH_ARMV5) & SH & AVR32 & SPARC w/GCC quint16 spix = (quint16(src[2])<<8) + src[1]; #else quint16 spix = *(quint16 *) (src + 1); diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h index 8aff912..81f8b70 100644 --- a/src/gui/painting/qblendfunctions_p.h +++ b/src/gui/painting/qblendfunctions_p.h @@ -275,8 +275,8 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl, qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y); int dx_l = int(leftSlope * 0x10000); int dx_r = int(rightSlope * 0x10000); - int x_l = int((topLeft.x + (0.5 + fromY - topLeft.y) * leftSlope + 0.5) * 0x10000); - int x_r = int((topRight.x + (0.5 + fromY - topRight.y) * rightSlope + 0.5) * 0x10000); + int x_l = int((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000); + int x_r = int((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000); int fromX, toX, x1, x2, u, v, i, ii; DestT *line; @@ -471,8 +471,8 @@ void qt_transform_image(DestT *destPixels, int dbpl, int dvdx = int(m21 * 0x10000); int dudy = int(m12 * 0x10000); int dvdy = int(m22 * 0x10000); - int u0 = qCeil((0.5 * m11 + 0.5 * m12 + mdx) * 0x10000) - 1; - int v0 = qCeil((0.5 * m21 + 0.5 * m22 + mdy) * 0x10000) - 1; + int u0 = qCeil((qreal(0.5) * m11 + qreal(0.5) * m12 + mdx) * 0x10000) - 1; + int v0 = qCeil((qreal(0.5) * m21 + qreal(0.5) * m22 + mdy) * 0x10000) - 1; int x1 = qFloor(sourceRect.left()); int y1 = qFloor(sourceRect.top()); diff --git a/src/gui/painting/qblittable.cpp b/src/gui/painting/qblittable.cpp new file mode 100644 index 0000000..5802531 --- /dev/null +++ b/src/gui/painting/qblittable.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qblittable_p.h" + +#ifndef QT_NO_BLITTABLE +QT_BEGIN_NAMESPACE + +class QBlittablePrivate +{ +public: + QBlittablePrivate(const QSize &size, QBlittable::Capabilities caps) + : caps(caps), m_size(size), locked(false), cachedImg(0) + {} + QBlittable::Capabilities caps; + QSize m_size; + bool locked; + QImage *cachedImg; +}; + + +QBlittable::QBlittable(const QSize &size, Capabilities caps) + : d_ptr(new QBlittablePrivate(size,caps)) +{ +} + +QBlittable::~QBlittable() +{ + delete d_ptr; +} + + +QBlittable::Capabilities QBlittable::capabilities() const +{ + Q_D(const QBlittable); + return d->caps; +} + +QSize QBlittable::size() const +{ + Q_D(const QBlittable); + return d->m_size; +} + +QImage *QBlittable::lock() +{ + Q_D(QBlittable); + if (!d->locked) { + d->cachedImg = doLock(); + d->locked = true; + } + + return d->cachedImg; +} + +void QBlittable::unlock() +{ + Q_D(QBlittable); + if (d->locked) { + doUnlock(); + d->locked = false; + } +} + +QT_END_NAMESPACE +#endif //QT_NO_BLITTABLE + diff --git a/src/gui/painting/qblittable_p.h b/src/gui/painting/qblittable_p.h new file mode 100644 index 0000000..9d0e822 --- /dev/null +++ b/src/gui/painting/qblittable_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBLITTABLE_P_H +#define QBLITTABLE_P_H + +#include <QtCore/qsize.h> +#include <QtGui/private/qpixmap_blitter_p.h> + + +#ifndef QT_NO_BLITTABLE +QT_BEGIN_NAMESPACE + +class QImage; +class QBlittablePrivate; + +class Q_GUI_EXPORT QBlittable +{ + Q_DECLARE_PRIVATE(QBlittable); +public: + enum Capability { + + SolidRectCapability = 0x0001, + SourcePixmapCapability = 0x0002, + SourceOverPixmapCapability = 0x0004, + SourceOverScaledPixmapCapability = 0x0008, + + // Internal ones + OutlineCapability = 0x0001000, + }; + Q_DECLARE_FLAGS (Capabilities, Capability); + + QBlittable(const QSize &size, Capabilities caps); + virtual ~QBlittable(); + + Capabilities capabilities() const; + QSize size() const; + + virtual void fillRect(const QRectF &rect, const QColor &color) = 0; + virtual void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect) = 0; + + QImage *lock(); + void unlock(); + +protected: + virtual QImage *doLock() = 0; + virtual void doUnlock() = 0; + QBlittablePrivate *d_ptr; +}; + +QT_END_NAMESPACE +#endif //QT_NO_BLITTABLE +#endif //QBLITTABLE_P_H diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 8f965c2..3ff7eb8 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -636,6 +636,15 @@ QBrush &QBrush::operator=(const QBrush &b) return *this; } + +/*! + \fn void QBrush::swap(QBrush &other) + \since 4.8 + + Swaps brush \a other with this brush. This operation is very + fast and never fails. +*/ + /*! Returns the brush as a QVariant */ @@ -831,6 +840,22 @@ const QGradient *QBrush::gradient() const return 0; } +Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush) +{ + if (brush.style() == Qt::RadialGradientPattern) { + const QGradient *g = brush.gradient(); + const QRadialGradient *rg = static_cast<const QRadialGradient *>(g); + + if (!qFuzzyIsNull(rg->focalRadius())) + return true; + + QPointF delta = rg->focalPoint() - rg->center(); + if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius()) + return true; + } + + return false; +} /*! Returns true if the brush is fully opaque otherwise false. A brush @@ -840,6 +865,7 @@ const QGradient *QBrush::gradient() const \i The alpha component of the color() is 255. \i Its texture() does not have an alpha channel and is not a QBitmap. \i The colors in the gradient() all have an alpha component that is 255. + \i It is an extended radial gradient. \endlist */ @@ -851,6 +877,9 @@ bool QBrush::isOpaque() const if (d->style == Qt::SolidPattern) return opaqueColor; + if (qt_isExtendedRadialGradient(*this)) + return false; + if (d->style == Qt::LinearGradientPattern || d->style == Qt::RadialGradientPattern || d->style == Qt::ConicalGradientPattern) { @@ -1200,8 +1229,10 @@ QDataStream &operator>>(QDataStream &s, QBrush &b) \list \o \e Linear gradients interpolate colors between start and end points. - \o \e Radial gradients interpolate colors between a focal point and end - points on a circle surrounding it. + \o \e Simple radial gradients interpolate colors between a focal point + and end points on a circle surrounding it. + \o \e Extended radial gradients interpolate colors between a center and + a focal circle. \o \e Conical gradients interpolate colors around a center point. \endlist @@ -1497,8 +1528,6 @@ void QGradient::setInterpolationMode(InterpolationMode mode) dummy = p; } -#undef Q_DUMMY_ACCESSOR - /*! \fn bool QGradient::operator!=(const QGradient &gradient) const \since 4.2 @@ -1532,7 +1561,7 @@ bool QGradient::operator==(const QGradient &gradient) const || m_data.radial.cy != gradient.m_data.radial.cy || m_data.radial.fx != gradient.m_data.radial.fx || m_data.radial.fy != gradient.m_data.radial.fy - || m_data.radial.radius != gradient.m_data.radial.radius) + || m_data.radial.cradius != gradient.m_data.radial.cradius) return false; } else { // m_type == ConicalGradient if (m_data.conical.cx != gradient.m_data.conical.cx @@ -1738,10 +1767,17 @@ void QLinearGradient::setFinalStop(const QPointF &stop) \brief The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush. - Radial gradients interpolate colors between a focal point and end - points on a circle surrounding it. Outside the end points the - gradient is either padded, reflected or repeated depending on the - currently set \l {QGradient::Spread}{spread} method: + Qt supports both simple and extended radial gradients. + + Simple radial gradients interpolate colors between a focal point and end + points on a circle surrounding it. Extended radial gradients interpolate + colors between a focal circle and a center circle. Points outside the cone + defined by the two circles will be transparent. For simple radial gradients + the focal point is adjusted to lie inside the center circle, whereas the + focal point can have any position in an extended radial gradient. + + Outside the end points the gradient is either padded, reflected or repeated + depending on the currently set \l {QGradient::Spread}{spread} method: \table \row @@ -1778,7 +1814,7 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF ¢er, // We have a one pixel buffer zone to avoid numerical instability on the // circle border //### this is hacky because technically we should adjust based on current matrix - const qreal compensated_radius = radius - radius * 0.001; + const qreal compensated_radius = radius - radius * qreal(0.001); QLineF line(center, focalPoint); if (line.length() > (compensated_radius)) line.setLength(compensated_radius); @@ -1786,9 +1822,14 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF ¢er, } /*! - Constructs a radial gradient with the given \a center, \a + Constructs a simple radial gradient with the given \a center, \a radius and \a focalPoint. + \note If the given focal point is outside the circle defined by the + center (\a cx, \a cy) and the \a radius it will be re-adjusted to + the intersection between the line from the center to the focal point + and the circle. + \sa QGradient::setColorAt(), QGradient::setStops() */ @@ -1798,7 +1839,7 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius, const QPoi m_spread = PadSpread; m_data.radial.cx = center.x(); m_data.radial.cy = center.y(); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint); m_data.radial.fx = adapted_focal.x(); @@ -1806,7 +1847,7 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius, const QPoi } /*! - Constructs a radial gradient with the given \a center, \a + Constructs a simple radial gradient with the given \a center, \a radius and the focal point in the circle center. \sa QGradient::setColorAt(), QGradient::setStops() @@ -1817,16 +1858,21 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius) m_spread = PadSpread; m_data.radial.cx = center.x(); m_data.radial.cy = center.y(); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; m_data.radial.fx = center.x(); m_data.radial.fy = center.y(); } /*! - Constructs a radial gradient with the given center (\a cx, \a cy), + Constructs a simple radial gradient with the given center (\a cx, \a cy), \a radius and focal point (\a fx, \a fy). + \note If the given focal point is outside the circle defined by the + center (\a cx, \a cy) and the \a radius it will be re-adjusted to + the intersection between the line from the center to the focal point + and the circle. + \sa QGradient::setColorAt(), QGradient::setStops() */ @@ -1836,7 +1882,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre m_spread = PadSpread; m_data.radial.cx = cx; m_data.radial.cy = cy; - m_data.radial.radius = radius; + m_data.radial.cradius = radius; QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(QPointF(cx, cy), radius, @@ -1847,7 +1893,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre } /*! - Constructs a radial gradient with the center at (\a cx, \a cy) and the + Constructs a simple radial gradient with the center at (\a cx, \a cy) and the specified \a radius. The focal point lies at the center of the circle. \sa QGradient::setColorAt(), QGradient::setStops() @@ -1858,14 +1904,14 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius) m_spread = PadSpread; m_data.radial.cx = cx; m_data.radial.cy = cy; - m_data.radial.radius = radius; + m_data.radial.cradius = radius; m_data.radial.fx = cx; m_data.radial.fy = cy; } /*! - Constructs a radial gradient with the center and focal point at + Constructs a simple radial gradient with the center and focal point at (0, 0) with a radius of 1. */ QRadialGradient::QRadialGradient() @@ -1874,11 +1920,51 @@ QRadialGradient::QRadialGradient() m_spread = PadSpread; m_data.radial.cx = 0; m_data.radial.cy = 0; - m_data.radial.radius = 1; + m_data.radial.cradius = 1; m_data.radial.fx = 0; m_data.radial.fy = 0; } +/*! + \since 4.8 + + Constructs an extended radial gradient with the given \a center, \a + centerRadius, \a focalPoint, and \a focalRadius. +*/ +QRadialGradient::QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius) +{ + m_type = RadialGradient; + m_spread = PadSpread; + m_data.radial.cx = center.x(); + m_data.radial.cy = center.y(); + m_data.radial.cradius = centerRadius; + + m_data.radial.fx = focalPoint.x(); + m_data.radial.fy = focalPoint.y(); + setFocalRadius(focalRadius); +} + +/*! + \since 4.8 + + Constructs an extended radial gradient with the given \a center, \a + centerRadius, \a focalPoint, and \a focalRadius. + Constructs a radial gradient with the given center (\a cx, \a cy), + center radius \a centerRadius, focal point (\a fx, \a fy), and + focal radius \a focalRadius. +*/ +QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius) +{ + m_type = RadialGradient; + m_spread = PadSpread; + m_data.radial.cx = cx; + m_data.radial.cy = cy; + m_data.radial.cradius = centerRadius; + + m_data.radial.fx = fx; + m_data.radial.fy = fy; + setFocalRadius(focalRadius); +} /*! Returns the center of this radial gradient in logical coordinates. @@ -1923,13 +2009,15 @@ void QRadialGradient::setCenter(const QPointF ¢er) /*! Returns the radius of this radial gradient in logical coordinates. + Equivalent to centerRadius() + \sa QGradient::stops() */ qreal QRadialGradient::radius() const { Q_ASSERT(m_type == RadialGradient); - return m_data.radial.radius; + return m_data.radial.cradius; } @@ -1938,13 +2026,81 @@ qreal QRadialGradient::radius() const Sets the radius of this radial gradient in logical coordinates to \a radius + + Equivalent to setCenterRadius() */ void QRadialGradient::setRadius(qreal radius) { Q_ASSERT(m_type == RadialGradient); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; +} + +/*! + \since 4.8 + + Returns the center radius of this radial gradient in logical + coordinates. + + \sa QGradient::stops() +*/ +qreal QRadialGradient::centerRadius() const +{ + Q_ASSERT(m_type == RadialGradient); + return m_data.radial.cradius; +} + +/* + \since 4.8 + + Sets the center radius of this radial gradient in logical coordinates + to \a radius +*/ +void QRadialGradient::setCenterRadius(qreal radius) +{ + Q_ASSERT(m_type == RadialGradient); + m_data.radial.cradius = radius; +} + +/*! + \since 4.8 + + Returns the focal radius of this radial gradient in logical + coordinates. + + \sa QGradient::stops() +*/ +qreal QRadialGradient::focalRadius() const +{ + Q_ASSERT(m_type == RadialGradient); + Q_DUMMY_ACCESSOR + + // mask away low three bits + union { float f; quint32 i; } u; + u.i = i & ~0x07; + return u.f; } +/* + \since 4.8 + + Sets the focal radius of this radial gradient in logical coordinates + to \a radius +*/ +void QRadialGradient::setFocalRadius(qreal radius) +{ + Q_ASSERT(m_type == RadialGradient); + Q_DUMMY_ACCESSOR + + // Since there's no QGradientData, we only have the dummy void * to + // store additional data in. The three lowest bits are already + // taken, thus we cut the three lowest bits from the significand + // and store the radius as a float. + union { float f; quint32 i; } u; + u.f = float(radius); + // add 0x04 to round up when we drop the three lowest bits + i |= (u.i + 0x04) & ~0x07; + dummy = p; +} /*! Returns the focal point of this radial gradient in logical @@ -2184,4 +2340,6 @@ void QConicalGradient::setAngle(qreal angle) \sa setTransform() */ +#undef Q_DUMMY_ACCESSOR + QT_END_NAMESPACE diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index ac247a6..d914c8c 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -92,6 +92,12 @@ public: ~QBrush(); QBrush &operator=(const QBrush &brush); +#ifdef Q_COMPILER_RVALUE_REFS + inline QBrush &operator=(QBrush &&other) + { qSwap(d, other.d); return *this; } +#endif + inline void swap(QBrush &other) { qSwap(d, other.d); } + operator QVariant() const; inline Qt::BrushStyle style() const; @@ -249,6 +255,7 @@ private: friend class QLinearGradient; friend class QRadialGradient; friend class QConicalGradient; + friend class QBrush; Type m_type; Spread m_spread; @@ -258,7 +265,7 @@ private: qreal x1, y1, x2, y2; } linear; struct { - qreal cx, cy, fx, fy, radius; + qreal cx, cy, fx, fy, cradius; } radial; struct { qreal cx, cy, angle; @@ -297,6 +304,9 @@ public: QRadialGradient(const QPointF ¢er, qreal radius); QRadialGradient(qreal cx, qreal cy, qreal radius); + QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius); + QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius); + QPointF center() const; void setCenter(const QPointF ¢er); inline void setCenter(qreal x, qreal y) { setCenter(QPointF(x, y)); } @@ -307,6 +317,12 @@ public: qreal radius() const; void setRadius(qreal radius); + + qreal centerRadius() const; + void setCenterRadius(qreal radius); + + qreal focalRadius() const; + void setFocalRadius(qreal radius); }; diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 8ebbe35..ff6c24e 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -629,7 +629,7 @@ void QColor::getHsvF(qreal *h, qreal *s, qreal *v, qreal *a) const return; } - *h = ct.ahsv.hue == USHRT_MAX ? -1.0 : ct.ahsv.hue / 36000.0; + *h = ct.ahsv.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsv.hue / qreal(36000.0); *s = ct.ahsv.saturation / qreal(USHRT_MAX); *v = ct.ahsv.value / qreal(USHRT_MAX); @@ -676,17 +676,17 @@ void QColor::getHsv(int *h, int *s, int *v, int *a) const */ void QColor::setHsvF(qreal h, qreal s, qreal v, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (v < 0.0 || v > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (v < qreal(0.0) || v > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::setHsvF: HSV parameters out of range"); return; } cspec = Hsv; ct.ahsv.alpha = qRound(a * USHRT_MAX); - ct.ahsv.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + ct.ahsv.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000); ct.ahsv.saturation = qRound(s * USHRT_MAX); ct.ahsv.value = qRound(v * USHRT_MAX); ct.ahsv.pad = 0; @@ -740,7 +740,7 @@ void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const return; } - *h = ct.ahsl.hue == USHRT_MAX ? -1.0 : ct.ahsl.hue / 36000.0; + *h = ct.ahsl.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsl.hue / qreal(36000.0); *s = ct.ahsl.saturation / qreal(USHRT_MAX); *l = ct.ahsl.lightness / qreal(USHRT_MAX); @@ -790,17 +790,17 @@ void QColor::getHsl(int *h, int *s, int *l, int *a) const */ void QColor::setHslF(qreal h, qreal s, qreal l, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (l < 0.0 || l > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (l < qreal(0.0) || l > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::setHsvF: HSV parameters out of range"); return; } cspec = Hsl; ct.ahsl.alpha = qRound(a * USHRT_MAX); - ct.ahsl.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + ct.ahsl.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000); ct.ahsl.saturation = qRound(s * USHRT_MAX); ct.ahsl.lightness = qRound(l * USHRT_MAX); ct.ahsl.pad = 0; @@ -909,10 +909,10 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const */ void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < 0.0 || r > 1.0 - || g < 0.0 || g > 1.0 - || b < 0.0 || b > 1.0 - || a < 0.0 || a > 1.0) { + if (r < qreal(0.0) || r > qreal(1.0) + || g < qreal(0.0) || g > qreal(1.0) + || b < qreal(0.0) || b > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::setRgbF: RGB parameters out of range"); invalidate(); return; @@ -1322,7 +1322,7 @@ qreal QColor::hsvHueF() const { if (cspec != Invalid && cspec != Hsv) return toHsv().hueF(); - return ct.ahsv.hue == USHRT_MAX ? -1.0 : ct.ahsv.hue / 36000.0; + return ct.ahsv.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsv.hue / qreal(36000.0); } /*! @@ -1418,7 +1418,7 @@ qreal QColor::hslHueF() const { if (cspec != Invalid && cspec != Hsl) return toHsl().hslHueF(); - return ct.ahsl.hue == USHRT_MAX ? -1.0 : ct.ahsl.hue / 36000.0; + return ct.ahsl.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsl.hue / qreal(36000.0); } /*! @@ -1584,10 +1584,10 @@ QColor QColor::toRgb() const const qreal v = ct.ahsv.value / qreal(USHRT_MAX); const int i = int(h); const qreal f = h - i; - const qreal p = v * (1.0 - s); + const qreal p = v * (qreal(1.0) - s); if (i & 1) { - const qreal q = v * (1.0 - (s * f)); + const qreal q = v * (qreal(1.0) - (s * f)); switch (i) { case 1: @@ -1607,7 +1607,7 @@ QColor QColor::toRgb() const break; } } else { - const qreal t = v * (1.0 - (s * (1.0 - f))); + const qreal t = v * (qreal(1.0) - (s * (qreal(1.0) - f))); switch (i) { case 0: @@ -1683,9 +1683,9 @@ QColor QColor::toRgb() const const qreal y = ct.acmyk.yellow / qreal(USHRT_MAX); const qreal k = ct.acmyk.black / qreal(USHRT_MAX); - color.ct.argb.red = qRound((1.0 - (c * (1.0 - k) + k)) * USHRT_MAX); - color.ct.argb.green = qRound((1.0 - (m * (1.0 - k) + k)) * USHRT_MAX); - color.ct.argb.blue = qRound((1.0 - (y * (1.0 - k) + k)) * USHRT_MAX); + color.ct.argb.red = qRound((qreal(1.0) - (c * (qreal(1.0) - k) + k)) * USHRT_MAX); + color.ct.argb.green = qRound((qreal(1.0) - (m * (qreal(1.0) - k) + k)) * USHRT_MAX); + color.ct.argb.blue = qRound((qreal(1.0) - (y * (qreal(1.0) - k) + k)) * USHRT_MAX); break; } default: @@ -1737,15 +1737,15 @@ QColor QColor::toHsv() const if (qFuzzyCompare(r, max)) { hue = ((g - b) /delta); } else if (qFuzzyCompare(g, max)) { - hue = (2.0 + (b - r) / delta); + hue = (qreal(2.0) + (b - r) / delta); } else if (qFuzzyCompare(b, max)) { - hue = (4.0 + (r - g) / delta); + hue = (qreal(4.0) + (r - g) / delta); } else { Q_ASSERT_X(false, "QColor::toHsv", "internal error"); } - hue *= 60.0; - if (hue < 0.0) - hue += 360.0; + hue *= qreal(60.0); + if (hue < qreal(0.0)) + hue += qreal(360.0); color.ct.ahsv.hue = qRound(hue * 100); } @@ -1781,7 +1781,7 @@ QColor QColor::toHsl() const color.ct.ahsl.lightness = qRound(lightness * USHRT_MAX); if (qFuzzyIsNull(delta)) { // achromatic case, hue is undefined - color.ct.ahsl.hue = 0; + color.ct.ahsl.hue = USHRT_MAX; color.ct.ahsl.saturation = 0; } else { // chromatic case @@ -1793,15 +1793,15 @@ QColor QColor::toHsl() const if (qFuzzyCompare(r, max)) { hue = ((g - b) /delta); } else if (qFuzzyCompare(g, max)) { - hue = (2.0 + (b - r) / delta); + hue = (qreal(2.0) + (b - r) / delta); } else if (qFuzzyCompare(b, max)) { - hue = (4.0 + (r - g) / delta); + hue = (qreal(4.0) + (r - g) / delta); } else { Q_ASSERT_X(false, "QColor::toHsv", "internal error"); } - hue *= 60.0; - if (hue < 0.0) - hue += 360.0; + hue *= qreal(60.0); + if (hue < qreal(0.0)) + hue += qreal(360.0); color.ct.ahsl.hue = qRound(hue * 100); } @@ -1829,17 +1829,17 @@ QColor QColor::toCmyk() const const qreal r = ct.argb.red / qreal(USHRT_MAX); const qreal g = ct.argb.green / qreal(USHRT_MAX); const qreal b = ct.argb.blue / qreal(USHRT_MAX); - qreal c = 1.0 - r; - qreal m = 1.0 - g; - qreal y = 1.0 - b; + qreal c = qreal(1.0) - r; + qreal m = qreal(1.0) - g; + qreal y = qreal(1.0) - b; // cmy -> cmyk const qreal k = qMin(c, qMin(m, y)); if (!qFuzzyIsNull(k - 1)) { - c = (c - k) / (1.0 - k); - m = (m - k) / (1.0 - k); - y = (y - k) / (1.0 - k); + c = (c - k) / (qreal(1.0) - k); + m = (m - k) / (qreal(1.0) - k); + y = (y - k) / (qreal(1.0) - k); } color.ct.acmyk.cyan = qRound(c * USHRT_MAX); @@ -1942,10 +1942,10 @@ QColor QColor::fromRgb(int r, int g, int b, int a) */ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < 0.0 || r > 1.0 - || g < 0.0 || g > 1.0 - || b < 0.0 || b > 1.0 - || a < 0.0 || a > 1.0) { + if (r < qreal(0.0) || r > qreal(1.0) + || g < qreal(0.0) || g > qreal(1.0) + || b < qreal(0.0) || b > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::fromRgbF: RGB parameters out of range"); return QColor(); } @@ -2005,10 +2005,10 @@ QColor QColor::fromHsv(int h, int s, int v, int a) */ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (v < 0.0 || v > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (v < qreal(0.0) || v > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::fromHsvF: HSV parameters out of range"); return QColor(); } @@ -2016,7 +2016,7 @@ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a) QColor color; color.cspec = Hsv; color.ct.ahsv.alpha = qRound(a * USHRT_MAX); - color.ct.ahsv.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + color.ct.ahsv.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000); color.ct.ahsv.saturation = qRound(s * USHRT_MAX); color.ct.ahsv.value = qRound(v * USHRT_MAX); color.ct.ahsv.pad = 0; @@ -2069,10 +2069,10 @@ QColor QColor::fromHsl(int h, int s, int l, int a) */ QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (l < 0.0 || l > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (l < qreal(0.0) || l > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::fromHsvF: HSV parameters out of range"); return QColor(); } @@ -2080,7 +2080,7 @@ QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a) QColor color; color.cspec = Hsl; color.ct.ahsl.alpha = qRound(a * USHRT_MAX); - color.ct.ahsl.hue = (h == -1.0) ? USHRT_MAX : qRound(h * 36000); + color.ct.ahsl.hue = (h == qreal(-1.0)) ? USHRT_MAX : qRound(h * 36000); if (color.ct.ahsl.hue == 36000) color.ct.ahsl.hue = 0; color.ct.ahsl.saturation = qRound(s * USHRT_MAX); @@ -2189,11 +2189,11 @@ void QColor::setCmyk(int c, int m, int y, int k, int a) */ void QColor::setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a) { - if (c < 0.0 || c > 1.0 - || m < 0.0 || m > 1.0 - || y < 0.0 || y > 1.0 - || k < 0.0 || k > 1.0 - || a < 0.0 || a > 1.0) { + if (c < qreal(0.0) || c > qreal(1.0) + || m < qreal(0.0) || m > qreal(1.0) + || y < qreal(0.0) || y > qreal(1.0) + || k < qreal(0.0) || k > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::setCmykF: CMYK parameters out of range"); return; } @@ -2251,11 +2251,11 @@ QColor QColor::fromCmyk(int c, int m, int y, int k, int a) */ QColor QColor::fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a) { - if (c < 0.0 || c > 1.0 - || m < 0.0 || m > 1.0 - || y < 0.0 || y > 1.0 - || k < 0.0 || k > 1.0 - || a < 0.0 || a > 1.0) { + if (c < qreal(0.0) || c > qreal(1.0) + || m < qreal(0.0) || m > qreal(1.0) + || y < qreal(0.0) || y > qreal(1.0) + || k < qreal(0.0) || k > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::fromCmykF: CMYK parameters out of range"); return QColor(); } diff --git a/src/gui/painting/qcolor_p.cpp b/src/gui/painting/qcolor_p.cpp index b9ec0d4..38fed71 100644 --- a/src/gui/painting/qcolor_p.cpp +++ b/src/gui/painting/qcolor_p.cpp @@ -49,9 +49,6 @@ #include "qrgb.h" #include "qstringlist.h" -#if defined(Q_WS_WINCE) -#include "qguifunctions_wince.h" -#endif QT_BEGIN_NAMESPACE static inline int h2i(char hex) @@ -290,33 +287,16 @@ static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData); #undef rgb -QT_BEGIN_INCLUDE_NAMESPACE -#include <stdlib.h> -QT_END_INCLUDE_NAMESPACE - -#if defined(Q_C_CALLBACKS) -extern "C" { -#endif - -#ifdef Q_OS_WINCE -static int __cdecl rgb_cmp(const void *d1, const void *d2) -#else -static int rgb_cmp(const void *d1, const void *d2) -#endif -{ - return qstricmp(((RGBData *)d1)->name, ((RGBData *)d2)->name); -} - -#if defined(Q_C_CALLBACKS) -} -#endif +inline bool operator<(const char *name, const RGBData &data) +{ return qstrcmp(name, data.name) < 0; } +inline bool operator<(const RGBData &data, const char *name) +{ return qstrcmp(data.name, name) < 0; } -static bool get_named_rgb(const char *name, QRgb *rgb) +static bool get_named_rgb(const char *name_no_space, QRgb *rgb) { - RGBData x; - x.name = name; - RGBData *r = (RGBData*)bsearch(&x, rgbTbl, rgbTblSize, sizeof(RGBData), rgb_cmp); - if (r) { + QByteArray name = QByteArray(name_no_space).toLower(); + const RGBData *r = qBinaryFind(rgbTbl, rgbTbl + rgbTblSize, name.constData()); + if (r != rgbTbl + rgbTblSize) { *rgb = r->value; return true; } diff --git a/src/gui/painting/qcolormap_qpa.cpp b/src/gui/painting/qcolormap_qpa.cpp new file mode 100644 index 0000000..f66607b --- /dev/null +++ b/src/gui/painting/qcolormap_qpa.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcolormap.h" +#include "qcolor.h" +#include "qpaintdevice.h" +#include "private/qapplication_p.h" +#include "private/qgraphicssystem_p.h" + +QT_BEGIN_NAMESPACE + +class QColormapPrivate +{ +public: + inline QColormapPrivate() + : ref(1), mode(QColormap::Direct), depth(0), numcolors(0) + { } + + QAtomicInt ref; + + QColormap::Mode mode; + int depth; + int numcolors; +}; + +static QColormapPrivate *screenMap = 0; + +void QColormap::initialize() +{ + screenMap = new QColormapPrivate; + + QPlatformIntegration *pi = QApplicationPrivate::platformIntegration(); + QList<QPlatformScreen*> screens = pi->screens(); + + screenMap->depth = screens.at(0)->depth(); + if (screenMap->depth < 8) { + screenMap->mode = QColormap::Indexed; + screenMap->numcolors = 256; + } else { + screenMap->mode = QColormap::Direct; + screenMap->numcolors = -1; + } +} + +void QColormap::cleanup() +{ + delete screenMap; + screenMap = 0; +} + +QColormap QColormap::instance(int /*screen*/) +{ + return QColormap(); +} + +QColormap::QColormap() + : d(screenMap) +{ d->ref.ref(); } + +QColormap::QColormap(const QColormap &colormap) + :d (colormap.d) +{ d->ref.ref(); } + +QColormap::~QColormap() +{ + if (!d->ref.deref()) + delete d; +} + +QColormap::Mode QColormap::mode() const +{ return d->mode; } + + +int QColormap::depth() const +{ return d->depth; } + + +int QColormap::size() const +{ + return d->numcolors; +} + +#ifndef QT_QWS_DEPTH16_RGB +#define QT_QWS_DEPTH16_RGB 565 +#endif +static const int qt_rbits = (QT_QWS_DEPTH16_RGB/100); +static const int qt_gbits = (QT_QWS_DEPTH16_RGB/10%10); +static const int qt_bbits = (QT_QWS_DEPTH16_RGB%10); +static const int qt_red_shift = qt_bbits+qt_gbits-(8-qt_rbits); +static const int qt_green_shift = qt_bbits-(8-qt_gbits); +static const int qt_neg_blue_shift = 8-qt_bbits; +static const int qt_blue_mask = (1<<qt_bbits)-1; +static const int qt_green_mask = (1<<(qt_gbits+qt_bbits))-(1<<qt_bbits); +static const int qt_red_mask = (1<<(qt_rbits+qt_gbits+qt_bbits))-(1<<(qt_gbits+qt_bbits)); + +static const int qt_red_rounding_shift = qt_red_shift + qt_rbits; +static const int qt_green_rounding_shift = qt_green_shift + qt_gbits; +static const int qt_blue_rounding_shift = qt_bbits - qt_neg_blue_shift; + +inline ushort qt_convRgbTo16(QRgb c) +{ + const int tr = qRed(c) << qt_red_shift; + const int tg = qGreen(c) << qt_green_shift; + const int tb = qBlue(c) >> qt_neg_blue_shift; + + return (tb & qt_blue_mask) | (tg & qt_green_mask) | (tr & qt_red_mask); +} + +inline QRgb qt_conv16ToRgb(ushort c) +{ + const int r=(c & qt_red_mask); + const int g=(c & qt_green_mask); + const int b=(c & qt_blue_mask); + const int tr = r >> qt_red_shift | r >> qt_red_rounding_shift; + const int tg = g >> qt_green_shift | g >> qt_green_rounding_shift; + const int tb = b << qt_neg_blue_shift | b >> qt_blue_rounding_shift; + + return qRgb(tr,tg,tb); +} + +uint QColormap::pixel(const QColor &color) const +{ + QRgb rgb = color.rgba(); + if (d->mode == QColormap::Direct) { + switch(d->depth) { + case 16: + return qt_convRgbTo16(rgb); + case 24: + case 32: + { + const int r = qRed(rgb); + const int g = qGreen(rgb); + const int b = qBlue(rgb); + const int red_shift = 16; + const int green_shift = 8; + const int red_mask = 0xff0000; + const int green_mask = 0x00ff00; + const int blue_mask = 0x0000ff; + const int tg = g << green_shift; +#ifdef QT_QWS_DEPTH_32_BGR + if (qt_screen->pixelType() == QScreen::BGRPixel) { + const int tb = b << red_shift; + return 0xff000000 | (r & blue_mask) | (tg & green_mask) | (tb & red_mask); + } +#endif + const int tr = r << red_shift; + return 0xff000000 | (b & blue_mask) | (tg & green_mask) | (tr & red_mask); + } + } + } + //XXX + //return qt_screen->alloc(qRed(rgb), qGreen(rgb), qBlue(rgb)); + return 0; +} + +const QColor QColormap::colorAt(uint pixel) const +{ + if (d->mode == Direct) { + if (d->depth == 16) { + pixel = qt_conv16ToRgb(pixel); + } + const int red_shift = 16; + const int green_shift = 8; + const int red_mask = 0xff0000; + const int green_mask = 0x00ff00; + const int blue_mask = 0x0000ff; +#ifdef QT_QWS_DEPTH_32_BGR + if (qt_screen->pixelType() == QScreen::BGRPixel) { + return QColor((pixel & blue_mask), + (pixel & green_mask) >> green_shift, + (pixel & red_mask) >> red_shift); + } +#endif + return QColor((pixel & red_mask) >> red_shift, + (pixel & green_mask) >> green_shift, + (pixel & blue_mask)); + } +#if 0 // XXX + Q_ASSERT_X(int(pixel) < qt_screen->numCols(), "QColormap::colorAt", "pixel out of bounds of palette"); + return QColor(qt_screen->clut()[pixel]); +#endif + return QColor(); +} + +const QVector<QColor> QColormap::colormap() const +{ + return QVector<QColor>(); +} + +QColormap &QColormap::operator=(const QColormap &colormap) +{ qAtomicAssign(d, colormap.d); return *this; } + +QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 5904296..360292c 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -75,43 +75,9 @@ enum { fixed_scale = 1 << 16, half_point = 1 << 15 }; -static const int buffer_size = 2048; - -struct LinearGradientValues -{ - qreal dx; - qreal dy; - qreal l; - qreal off; -}; - -struct RadialGradientValues -{ - qreal dx; - qreal dy; - qreal a; -}; - -struct Operator; -typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); -typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); -typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); - -struct Operator -{ - QPainter::CompositionMode mode; - DestFetchProc dest_fetch; - DestStoreProc dest_store; - SourceFetchProc src_fetch; - CompositionFunctionSolid funcSolid; - CompositionFunction func; - union { - LinearGradientValues linear; - RadialGradientValues radial; -// TextureValues texture; - }; -}; +// must be multiple of 4 for easier SIMD implementations +static const int buffer_size = 2048; /* Destination fetch. This is simple as we don't have to do bounds checks or @@ -570,8 +536,8 @@ const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const int image_width = data->texture.width; int image_height = data->texture.height; - const qreal cx = x + 0.5; - const qreal cy = y + 0.5; + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); const uint *end = buffer + length; uint *b = buffer; @@ -792,8 +758,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator * int image_x2 = data->texture.x2 - 1; int image_y2 = data->texture.y2 - 1; - const qreal cx = x + 0.5; - const qreal cy = y + 0.5; + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); uint *end = buffer + length; uint *b = buffer; @@ -1188,8 +1154,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator * while (b < end) { const qreal iw = fw == 0 ? 1 : 1 / fw; - const qreal px = fx * iw - 0.5; - const qreal py = fy * iw - 0.5; + const qreal px = fx * iw - qreal(0.5); + const qreal py = fy * iw - qreal(0.5); int x1 = int(px) - (px < 0); int x2; @@ -1346,64 +1312,13 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { }, }; - -static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) -{ - int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + 0.5); - - // calculate the actual offset. - if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { - if (data->spread == QGradient::RepeatSpread) { - ipos = ipos % GRADIENT_STOPTABLE_SIZE; - ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - - } else { - if (ipos < 0) ipos = 0; - else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1; - } - } - - Q_ASSERT(ipos >= 0); - Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); - - return data->colorTable[ipos]; -} - #define FIXPT_BITS 8 #define FIXPT_SIZE (1<<FIXPT_BITS) static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos) { int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; - - // calculate the actual offset. - if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { - if (data->spread == QGradient::RepeatSpread) { - ipos = ipos % GRADIENT_STOPTABLE_SIZE; - ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - - } else { - if (ipos < 0) ipos = 0; - else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1; - } - } - - Q_ASSERT(ipos >= 0); - Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); - - return data->colorTable[ipos]; + return data->colorTable[qt_gradient_clamp(data, ipos)]; } static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data) @@ -1419,8 +1334,8 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q } } -static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) { const uint *b = buffer; qreal t, inc; @@ -1430,8 +1345,8 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator if (op->linear.l == 0) { t = inc = 0; } else { - rx = data->m21 * (y + 0.5) + data->m11 * (x + 0.5) + data->dx; - ry = data->m22 * (y + 0.5) + data->m12 * (x + 0.5) + data->dy; + rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx; + ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy; t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off; inc = op->linear.dx * data->m11 + op->linear.dy * data->m12; affine = !data->m13 && !data->m23; @@ -1444,7 +1359,7 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator const uint *end = buffer + length; if (affine) { - if (inc > -1e-5 && inc < 1e-5) { + if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE))); } else { if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && @@ -1467,7 +1382,7 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator } } } else { // fall back to float math here as well - qreal rw = data->m23 * (y + 0.5) + data->m13 * (x + 0.5) + data->m33; + qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33; while (buffer < end) { qreal x = rx/rw; qreal y = ry/rw; @@ -1487,116 +1402,71 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator return b; } -static inline qreal determinant(qreal a, qreal b, qreal c) -{ - return (b * b) - (4 * a * c); -} - -// function to evaluate real roots -static inline qreal realRoots(qreal a, qreal b, qreal detSqrt) -{ - return (-b + detSqrt)/(2 * a); -} - -static inline qreal qSafeSqrt(qreal x) -{ - return x > 0 ? qSqrt(x) : 0; -} - static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y; - v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy; -} - -static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) -{ - const uint *b = buffer; - qreal rx = data->m21 * (y + 0.5) - + data->dx + data->m11 * (x + 0.5); - qreal ry = data->m22 * (y + 0.5) - + data->dy + data->m12 * (x + 0.5); - bool affine = !data->m13 && !data->m23; - //qreal r = data->gradient.radial.radius; - - const uint *end = buffer + length; - if (affine) { - rx -= data->gradient.radial.focal.x; - ry -= data->gradient.radial.focal.y; - - qreal inv_a = 1 / qreal(2 * op->radial.a); - - const qreal delta_rx = data->m11; - const qreal delta_ry = data->m12; - qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy); - qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); - const qreal b_delta_b = 2 * b * delta_b; - const qreal delta_b_delta_b = 2 * delta_b * delta_b; + v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius; + v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius; - const qreal bb = b * b; - const qreal delta_bb = delta_b * delta_b; + v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy; + v->inv2a = 1 / (2 * v->a); - b *= inv_a; - delta_b *= inv_a; - - const qreal rxrxryry = rx * rx + ry * ry; - const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; - const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); - const qreal delta_rx_plus_ry = 2 * delta_rxrxryry; - - inv_a *= inv_a; - - qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a; - qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; - const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; + v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; +} - while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b); +class RadialFetchPlain +{ +public: + static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) + { + if (op->radial.extended) { + while (buffer < end) { + quint32 result = 0; + if (det >= 0) { + qreal w = qSqrt(det) - b; + if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0) + result = qt_gradient_pixel(&data->gradient, w); + } - det += delta_det; - delta_det += delta_delta_det; - b += delta_b; + *buffer = result; - ++buffer; - } - } else { - qreal rw = data->m23 * (y + 0.5) - + data->m33 + data->m13 * (x + 0.5); - if (!rw) - rw = 1; - while (buffer < end) { - qreal gx = rx/rw - data->gradient.radial.focal.x; - qreal gy = ry/rw - data->gradient.radial.focal.y; - qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy); - qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy)); - qreal s = realRoots(op->radial.a, b, qSafeSqrt(det)); + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; - *buffer = qt_gradient_pixel(&data->gradient, s); + ++buffer; + } + } else { + while (buffer < end) { + *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b); - rx += data->m11; - ry += data->m12; - rw += data->m13; - if (!rw) { - rw += data->m13; + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; } - ++buffer; } } +}; - return b; +const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length); } -static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; + +static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { const uint *b = buffer; - qreal rx = data->m21 * (y + 0.5) - + data->dx + data->m11 * (x + 0.5); - qreal ry = data->m22 * (y + 0.5) - + data->dy + data->m12 * (x + 0.5); + qreal rx = data->m21 * (y + qreal(0.5)) + + data->dx + data->m11 * (x + qreal(0.5)); + qreal ry = data->m22 * (y + qreal(0.5)) + + data->dy + data->m12 * (x + qreal(0.5)); bool affine = !data->m13 && !data->m23; const uint *end = buffer + length; @@ -1613,8 +1483,8 @@ static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operato ++buffer; } } else { - qreal rw = data->m23 * (y + 0.5) - + data->m33 + data->m13 * (x + 0.5); + qreal rw = data->m23 * (y + qreal(0.5)) + + data->m33 + data->m13 * (x + qreal(0.5)); if (!rw) rw = 1; while (buffer < end) { @@ -2819,7 +2689,7 @@ static inline int soft_light_op(int dst, int src, int da, int sa) # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2 return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025; # else - return (dst * sa * 255 + da * (src2 - sa) * (int(sqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; + return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; # endif } } @@ -3347,16 +3217,16 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; getLinearGradientValues(&op.linear, data); - op.src_fetch = fetchLinearGradient; + op.src_fetch = qt_fetch_linear_gradient; break; case QSpanData::RadialGradient: solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); - op.src_fetch = fetchRadialGradient; + op.src_fetch = qt_fetch_radial_gradient; break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; - op.src_fetch = fetchConicalGradient; + op.src_fetch = qt_fetch_conical_gradient; break; case QSpanData::Texture: op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format]; @@ -5928,8 +5798,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); int x = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); @@ -5976,8 +5846,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); qreal x = data->m21 * cy + data->m11 * cx + data->dx; qreal y = data->m22 * cy + data->m12 * cx + data->dy; @@ -6328,8 +6198,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); int x = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); @@ -6380,8 +6250,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); qreal x = data->m21 * cy + data->m11 * cx + data->dx; qreal y = data->m22 * cy + data->m12 * cx + data->dy; @@ -7067,7 +6937,7 @@ static void qt_gradient_quint32(int count, const QSpan *spans, void *userData) */ const int gss = GRADIENT_STOPTABLE_SIZE - 1; int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); - int off = int((((linear.dy * (data->m22 * 0.5 + data->dy) + linear.off) * gss) * FIXPT_SIZE)); + int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); while (count--) { int y = spans->y; @@ -7115,7 +6985,7 @@ static void qt_gradient_quint16(int count, const QSpan *spans, void *userData) */ const int gss = GRADIENT_STOPTABLE_SIZE - 1; int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); - int off = int((((linear.dy * (data->m22 * 0.5 + data->dy) + linear.off) * gss) * FIXPT_SIZE)); + int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); uint oldColor = data->solid.color; while (count--) { @@ -7194,18 +7064,12 @@ void qt_build_pow_tables() { #ifdef Q_WS_MAC // decided by testing a few things on an iMac, should probably get this from the // system... - smoothing = 2.0; + smoothing = qreal(2.0); #endif #ifdef Q_WS_WIN - int winSmooth; - if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) - smoothing = winSmooth / 1000.0; - - // Safeguard ourselves against corrupt registry values... - if (smoothing > 5 || smoothing < 1) - smoothing = 1.4; - + extern qreal qt_fontsmoothing_gamma; // qapplication_win.cpp + smoothing = qt_fontsmoothing_gamma; #endif #ifdef Q_WS_X11 @@ -7226,7 +7090,7 @@ void qt_build_pow_tables() { for (int i=0; i<256; ++i) qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); for (int i=0; i<2048; ++i) - qt_pow_invgamma[i] = uchar(qRound(qPow(i / 2047.0, 1 / gray_gamma) * 255)); + qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255)); #endif } @@ -7888,6 +7752,11 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2; } #ifdef QT_HAVE_SSSE3 @@ -7983,6 +7852,11 @@ void qInitDrawhelperAsm() qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon; qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon; qt_memfill32 = qt_memfill32_neon; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; } #endif diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index debca37..e673dd9 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -955,6 +955,46 @@ void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h, } } +class QSimdNeon +{ +public: + typedef int32x4_t Int32x4; + typedef float32x4_t Float32x4; + + union Vect_buffer_i { Int32x4 v; int i[4]; }; + union Vect_buffer_f { Float32x4 v; float f[4]; }; + + static inline Float32x4 v_dup(float x) { return vdupq_n_f32(x); } + static inline Int32x4 v_dup(int x) { return vdupq_n_s32(x); } + static inline Int32x4 v_dup(uint x) { return vdupq_n_s32(x); } + + static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return vaddq_f32(a, b); } + static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return vaddq_s32(a, b); } + + static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return vmaxq_f32(a, b); } + static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return vminq_f32(a, b); } + static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return vminq_s32(a, b); } + + static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return vandq_s32(a, b); } + + static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return vsubq_f32(a, b); } + static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return vsubq_s32(a, b); } + + static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return vmulq_f32(a, b); } + + static inline Float32x4 v_sqrt(Float32x4 x) { Float32x4 y = vrsqrteq_f32(x); y = vmulq_f32(y, vrsqrtsq_f32(x, vmulq_f32(y, y))); return vmulq_f32(x, y); } + + static inline Int32x4 v_toInt(Float32x4 x) { return vcvtq_s32_f32(x); } + + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return vcge_f32(a, b); } +}; + +const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon> >(buffer, op, data, y, x, length); +} + QT_END_NAMESPACE #endif // QT_HAVE_NEON diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index d4e731b..fa6ad0b 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -63,6 +63,7 @@ #endif #include "private/qrasterdefs_p.h" #include <private/qsimd_p.h> +#include <private/qmath_p.h> #ifdef Q_WS_QWS #include "QtGui/qscreen_qws.h" @@ -178,6 +179,44 @@ void qBlendTextureCallback(int count, const QSpan *spans, void *userData); typedef void (QT_FASTCALL *CompositionFunction)(uint *dest, const uint *src, int length, uint const_alpha); typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha); +struct LinearGradientValues +{ + qreal dx; + qreal dy; + qreal l; + qreal off; +}; + +struct RadialGradientValues +{ + qreal dx; + qreal dy; + qreal dr; + qreal sqrfr; + qreal a; + qreal inv2a; + bool extended; +}; + +struct Operator; +typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); +typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); +typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); + +struct Operator +{ + QPainter::CompositionMode mode; + DestFetchProc dest_fetch; + DestStoreProc dest_store; + SourceFetchProc src_fetch; + CompositionFunctionSolid funcSolid; + CompositionFunction func; + union { + LinearGradientValues linear; + RadialGradientValues radial; + }; +}; + void qInitDrawhelperAsm(); class QRasterPaintEngine; @@ -204,12 +243,13 @@ struct QRadialGradientData struct { qreal x; qreal y; + qreal radius; } center; struct { qreal x; qreal y; + qreal radius; } focal; - qreal radius; }; struct QConicalGradientData @@ -233,8 +273,10 @@ struct QGradientData #ifdef Q_WS_QWS #define GRADIENT_STOPTABLE_SIZE 256 +#define GRADIENT_STOPTABLE_SIZE_SHIFT 8 #else #define GRADIENT_STOPTABLE_SIZE 1024 +#define GRADIENT_STOPTABLE_SIZE_SHIFT 10 #endif uint* colorTable; //[GRADIENT_STOPTABLE_SIZE]; @@ -308,6 +350,218 @@ struct QSpanData void adjustSpanMethods(); }; +static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) +{ + if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { + if (data->spread == QGradient::RepeatSpread) { + ipos = ipos % GRADIENT_STOPTABLE_SIZE; + ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; + } else if (data->spread == QGradient::ReflectSpread) { + const int limit = GRADIENT_STOPTABLE_SIZE * 2; + ipos = ipos % limit; + ipos = ipos < 0 ? limit + ipos : ipos; + ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos; + } else { + if (ipos < 0) + ipos = 0; + else if (ipos >= GRADIENT_STOPTABLE_SIZE) + ipos = GRADIENT_STOPTABLE_SIZE-1; + } + } + + Q_ASSERT(ipos >= 0); + Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); + + return ipos; +} + +static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) +{ + int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); + return data->colorTable[qt_gradient_clamp(data, ipos)]; +} + +static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) +{ + return (b * b) - (4 * a * c); +} + +template <class RadialFetchFunc> +const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + // avoid division by zero + if (qFuzzyIsNull(op->radial.a)) { + extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count); + qt_memfill32(buffer, 0, length); + return buffer; + } + + const uint *b = buffer; + qreal rx = data->m21 * (y + qreal(0.5)) + + data->dx + data->m11 * (x + qreal(0.5)); + qreal ry = data->m22 * (y + qreal(0.5)) + + data->dy + data->m12 * (x + qreal(0.5)); + bool affine = !data->m13 && !data->m23; + + uint *end = buffer + length; + if (affine) { + rx -= data->gradient.radial.focal.x; + ry -= data->gradient.radial.focal.y; + + qreal inv_a = 1 / qreal(2 * op->radial.a); + + const qreal delta_rx = data->m11; + const qreal delta_ry = data->m12; + + qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + rx * op->radial.dx + ry * op->radial.dy); + qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); + const qreal b_delta_b = 2 * b * delta_b; + const qreal delta_b_delta_b = 2 * delta_b * delta_b; + + const qreal bb = b * b; + const qreal delta_bb = delta_b * delta_b; + + b *= inv_a; + delta_b *= inv_a; + + const qreal rxrxryry = rx * rx + ry * ry; + const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; + const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); + const qreal delta_rx_plus_ry = 2 * delta_rxrxryry; + + inv_a *= inv_a; + + qreal det = (bb - 4 * op->radial.a * (op->radial.sqrfr - rxrxryry)) * inv_a; + qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; + const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; + + RadialFetchFunc::fetch(buffer, end, op, data, det, delta_det, delta_delta_det, b, delta_b); + } else { + qreal rw = data->m23 * (y + qreal(0.5)) + + data->m33 + data->m13 * (x + qreal(0.5)); + + while (buffer < end) { + if (rw == 0) { + *buffer = 0; + } else { + qreal invRw = 1 / rw; + qreal gx = rx * invRw - data->gradient.radial.focal.x; + qreal gy = ry * invRw - data->gradient.radial.focal.y; + qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy); + qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy)); + + quint32 result = 0; + if (det >= 0) { + qreal detSqrt = qSqrt(det); + + qreal s0 = (-b - detSqrt) * op->radial.inv2a; + qreal s1 = (-b + detSqrt) * op->radial.inv2a; + + qreal s = qMax(s0, s1); + + if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0) + result = qt_gradient_pixel(&data->gradient, s); + } + + *buffer = result; + } + + rx += data->m11; + ry += data->m12; + rw += data->m13; + + ++buffer; + } + } + + return b; +} + +template <class Simd> +class QRadialFetchSimd +{ +public: + static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) + { + typename Simd::Vect_buffer_f det_vec; + typename Simd::Vect_buffer_f delta_det4_vec; + typename Simd::Vect_buffer_f b_vec; + + for (int i = 0; i < 4; ++i) { + det_vec.f[i] = det; + delta_det4_vec.f[i] = 4 * delta_det; + b_vec.f[i] = b; + + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + } + + const typename Simd::Float32x4 v_delta_delta_det16 = Simd::v_dup(16 * delta_delta_det); + const typename Simd::Float32x4 v_delta_delta_det6 = Simd::v_dup(6 * delta_delta_det); + const typename Simd::Float32x4 v_delta_b4 = Simd::v_dup(4 * delta_b); + + const typename Simd::Float32x4 v_r0 = Simd::v_dup(data->gradient.radial.focal.radius); + const typename Simd::Float32x4 v_dr = Simd::v_dup(op->radial.dr); + + const typename Simd::Float32x4 v_min = Simd::v_dup(0.0f); + const typename Simd::Float32x4 v_max = Simd::v_dup(float(GRADIENT_STOPTABLE_SIZE-1)); + const typename Simd::Float32x4 v_half = Simd::v_dup(0.5f); + + const typename Simd::Int32x4 v_repeat_mask = Simd::v_dup(~(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT)); + const typename Simd::Int32x4 v_reflect_mask = Simd::v_dup(~(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1))); + + const typename Simd::Int32x4 v_reflect_limit = Simd::v_dup(2 * GRADIENT_STOPTABLE_SIZE - 1); + + const int extended_mask = op->radial.extended ? 0x0 : ~0x0; + +#define FETCH_RADIAL_LOOP_PROLOGUE \ + while (buffer < end) { \ + typename Simd::Vect_buffer_i v_buffer_mask; \ + v_buffer_mask.v = Simd::v_greaterOrEqual(det_vec.v, v_min); \ + const typename Simd::Float32x4 v_index_local = Simd::v_sub(Simd::v_sqrt(Simd::v_max(v_min, det_vec.v)), b_vec.v); \ + const typename Simd::Float32x4 v_index = Simd::v_add(Simd::v_mul(v_index_local, v_max), v_half); \ + v_buffer_mask.v = Simd::v_and(v_buffer_mask.v, Simd::v_greaterOrEqual(Simd::v_add(v_r0, Simd::v_mul(v_dr, v_index_local)), v_min)); \ + typename Simd::Vect_buffer_i index_vec; +#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \ + index_vec.v = Simd::v_and(v_repeat_mask, Simd::v_toInt(v_index)); +#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \ + const typename Simd::Int32x4 v_index_i = Simd::v_and(v_reflect_mask, Simd::v_toInt(v_index)); \ + const typename Simd::Int32x4 v_index_i_inv = Simd::v_sub(v_reflect_limit, v_index_i); \ + index_vec.v = Simd::v_min_16(v_index_i, v_index_i_inv); +#define FETCH_RADIAL_LOOP_CLAMP_PAD \ + index_vec.v = Simd::v_toInt(Simd::v_min(v_max, Simd::v_max(v_min, v_index))); +#define FETCH_RADIAL_LOOP_EPILOGUE \ + det_vec.v = Simd::v_add(Simd::v_add(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \ + delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \ + b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \ + for (int i = 0; i < 4; ++i) \ + *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \ + } + +#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \ + FETCH_RADIAL_LOOP_PROLOGUE \ + FETCH_RADIAL_LOOP_CLAMP \ + FETCH_RADIAL_LOOP_EPILOGUE + + switch (data->gradient.spread) { + case QGradient::RepeatSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REPEAT) + break; + case QGradient::ReflectSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REFLECT) + break; + case QGradient::PadSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD) + break; + default: + Q_ASSERT(false); + } + } +}; + #if defined(Q_CC_RVCT) # pragma push # pragma arm diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index aad6bc9..75bb619 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -112,8 +112,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, // First, align dest to 16 bytes: ALIGNMENT_PROLOGUE_16BYTES(dst, x, w) { - quint32 s = src[x]; - s = BYTE_MUL(s, const_alpha); dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); } @@ -127,8 +125,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, } } for (; x<w; ++x) { - quint32 s = src[x]; - s = BYTE_MUL(s, const_alpha); dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); } dst = (quint32 *)(((uchar *) dst) + dbpl); @@ -491,6 +487,58 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, } } +class QSimdSse2 +{ +public: + typedef __m128i Int32x4; + typedef __m128 Float32x4; + + union Vect_buffer_i { Int32x4 v; int i[4]; }; + union Vect_buffer_f { Float32x4 v; float f[4]; }; + + static inline Float32x4 v_dup(float x) { return _mm_set1_ps(x); } + static inline Float32x4 v_dup(double x) { return _mm_set1_ps(x); } + static inline Int32x4 v_dup(int x) { return _mm_set1_epi32(x); } + static inline Int32x4 v_dup(uint x) { return _mm_set1_epi32(x); } + + static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return _mm_add_ps(a, b); } + static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return _mm_add_epi32(a, b); } + + static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return _mm_max_ps(a, b); } + static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return _mm_min_ps(a, b); } + static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return _mm_min_epi16(a, b); } + + static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return _mm_and_si128(a, b); } + + static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return _mm_sub_ps(a, b); } + static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return _mm_sub_epi32(a, b); } + + static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return _mm_mul_ps(a, b); } + + static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); } + + static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } + + // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it +#if defined(Q_CC_MSVC) && _MSC_VER < 1500 + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) + { + union Convert { Int32x4 vi; Float32x4 vf; } convert; + convert.vf = _mm_cmpgt_ps(a, b); + return convert.vi; + } +#else + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); } +#endif +}; + +const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length); +} + + QT_END_NAMESPACE #endif // QT_HAVE_SSE2 diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 2d61cc5..d8793c3 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -78,7 +78,7 @@ QT_BEGIN_NAMESPACE pixelVectorAG = _mm_mullo_epi16(pixelVectorAG, alphaChannel); \ pixelVectorRB = _mm_mullo_epi16(pixelVectorRB, alphaChannel); \ \ - /* 3. devide by 255, that's the tricky part. \ + /* 3. divide by 255, that's the tricky part. \ we do it like for BYTE_MUL(), with bit shift: X/255 ~= (X + X/256 + rounding)/256 */ \ /** so first (X + X/256 + rounding) */\ pixelVectorRB = _mm_add_epi16(pixelVectorRB, _mm_srli_epi16(pixelVectorRB, 8)); \ @@ -86,7 +86,7 @@ QT_BEGIN_NAMESPACE pixelVectorAG = _mm_add_epi16(pixelVectorAG, _mm_srli_epi16(pixelVectorAG, 8)); \ pixelVectorAG = _mm_add_epi16(pixelVectorAG, half); \ \ - /** second devide by 256 */\ + /** second divide by 256 */\ pixelVectorRB = _mm_srli_epi16(pixelVectorRB, 8); \ /** for AG, we could >> 8 to divide followed by << 8 to put the \ bytes in the correct position. By masking instead, we execute \ diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp index 4b79600..d82fdc9 100644 --- a/src/gui/painting/qgraphicssystem.cpp +++ b/src/gui/painting/qgraphicssystem.cpp @@ -50,6 +50,9 @@ #ifdef Q_WS_MAC # include <private/qpixmap_mac_p.h> #endif +#ifdef Q_WS_QPA +# include <QtGui/private/qapplication_p.h> +#endif #ifdef Q_OS_SYMBIAN # include <private/qpixmap_s60_p.h> # include <private/qgraphicssystemex_symbian_p.h> @@ -74,8 +77,10 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); +#elif defined(Q_WS_QPA) + return QApplicationPrivate::platformIntegration()->createPixmapData(type); #elif defined(Q_OS_SYMBIAN) - return new QS60PixmapData(type); + return new QS60PixmapData(type); #elif !defined(Q_WS_QWS) #error QGraphicsSystem::createDefaultPixmapData() not implemented #endif diff --git a/src/gui/painting/qgraphicssystem_p.h b/src/gui/painting/qgraphicssystem_p.h index d5acaa4..275f9eb 100644 --- a/src/gui/painting/qgraphicssystem_p.h +++ b/src/gui/painting/qgraphicssystem_p.h @@ -55,10 +55,14 @@ #include "private/qpixmapdata_p.h" #include "private/qwindowsurface_p.h" +#include "private/qpaintengine_blitter_p.h" + +#include <qdebug.h> QT_BEGIN_NAMESPACE class QPixmapFilter; +class QBlittable; class QGraphicsSystemEx; class Q_GUI_EXPORT QGraphicsSystem @@ -68,7 +72,7 @@ public: virtual QPixmapData *createPixmapData(QPixmapData *origin); virtual QWindowSurface *createWindowSurface(QWidget *widget) const = 0; - virtual ~QGraphicsSystem() = 0; + virtual ~QGraphicsSystem(); //### Remove this & change qpixmap.cpp & qbitmap.cpp once every platform is gaurenteed // to have a graphics system. diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp index 33652ee..d1dd7ef 100644 --- a/src/gui/painting/qgraphicssystem_runtime.cpp +++ b/src/gui/painting/qgraphicssystem_runtime.cpp @@ -319,6 +319,11 @@ QPoint QRuntimeWindowSurface::offset(const QWidget *widget) const return m_windowSurface->offset(widget); } +QWindowSurface::WindowSurfaceFeatures QRuntimeWindowSurface::features() const +{ + return m_windowSurface->features(); +} + QRuntimeGraphicsSystem::QRuntimeGraphicsSystem() : m_windowSurfaceDestroyPolicy(DestroyImmediately), m_graphicsSystem(0) diff --git a/src/gui/painting/qgraphicssystem_runtime_p.h b/src/gui/painting/qgraphicssystem_runtime_p.h index 30b4e3e..26d3777 100644 --- a/src/gui/painting/qgraphicssystem_runtime_p.h +++ b/src/gui/painting/qgraphicssystem_runtime_p.h @@ -129,6 +129,8 @@ public: virtual QPoint offset(const QWidget *widget) const; + virtual WindowSurfaceFeatures features() const; + QScopedPointer<QWindowSurface> m_windowSurface; QScopedPointer<QWindowSurface> m_pendingWindowSurface; diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index 22e947c..62a60d7 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -45,6 +45,7 @@ #include "qmutex.h" #include "qapplication.h" +#include <private/qapplication_p.h> #include "qgraphicssystem_raster_p.h" #include "qgraphicssystem_runtime_p.h" #include "qdebug.h" @@ -73,12 +74,13 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) if (system.isEmpty()) { system = QLatin1String("runtime"); } -#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) +#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) || defined(Q_WS_X11) if (system.isEmpty()) { system = QLatin1String("raster"); } #endif + QApplicationPrivate::graphics_system_name = system; if (system == QLatin1String("raster")) return new QRasterGraphicsSystem; else if (system == QLatin1String("runtime")) diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c index 08a6ef8..e5e8ba4 100644 --- a/src/gui/painting/qgrayraster.c +++ b/src/gui/painting/qgrayraster.c @@ -408,25 +408,31 @@ /* */ /* Record the current cell in the table. */ /* */ - static PCell - gray_find_cell( RAS_ARG ) + static void + gray_record_cell( RAS_ARG ) { PCell *pcell, cell; int x = ras.ex; + if ( ras.invalid || !( ras.area | ras.cover ) ) + return; if ( x > ras.max_ex ) x = ras.max_ex; pcell = &ras.ycells[ras.ey]; + for (;;) { cell = *pcell; if ( cell == NULL || cell->x > x ) break; - if ( cell->x == x ) - goto Exit; + if ( cell->x == x ) { + cell->area += ras.area; + cell->cover += ras.cover; + return; + } pcell = &cell->next; } @@ -436,28 +442,11 @@ cell = ras.cells + ras.num_cells++; cell->x = x; - cell->area = 0; - cell->cover = 0; + cell->area = ras.area; + cell->cover = ras.cover; cell->next = *pcell; *pcell = cell; - - Exit: - return cell; - } - - - static void - gray_record_cell( RAS_ARG ) - { - if ( !ras.invalid && ( ras.area | ras.cover ) ) - { - PCell cell = gray_find_cell( RAS_VAR ); - - - cell->area += ras.area; - cell->cover += ras.cover; - } } diff --git a/src/gui/painting/qgrayraster_p.h b/src/gui/painting/qgrayraster_p.h index f2dd9d2..b9a4aed 100644 --- a/src/gui/painting/qgrayraster_p.h +++ b/src/gui/painting/qgrayraster_p.h @@ -91,7 +91,7 @@ /* Minimum buffer size for raster object, that accounts for TWorker and TCell sizes.*/ -#define MINIMUM_POOL_SIZE 4096 +#define MINIMUM_POOL_SIZE 8192 QT_FT_EXPORT_VAR( const QT_FT_Raster_Funcs ) qt_ft_grays_raster; diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp index 6e53c35..aac5083 100644 --- a/src/gui/painting/qoutlinemapper.cpp +++ b/src/gui/painting/qoutlinemapper.cpp @@ -47,8 +47,6 @@ QT_BEGIN_NAMESPACE -static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; - #define qreal_to_fixed_26_6(f) (int(f * 64)) @@ -216,13 +214,6 @@ void QOutlineMapper::endOutline() elements = m_elements_dev.data(); } - if (m_round_coords) { - // round coordinates to match outlines drawn with drawLine_midpoint_i - for (int i = 0; i < m_elements.size(); ++i) - elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta), - qFloor(elements[i].y() + aliasedCoordinateDelta)); - } - controlPointRect = boundingRect(elements, element_count); #ifdef QT_DEBUG_CONVERT diff --git a/src/gui/painting/qoutlinemapper_p.h b/src/gui/painting/qoutlinemapper_p.h index 0f2303c..4dd28ac 100644 --- a/src/gui/painting/qoutlinemapper_p.h +++ b/src/gui/painting/qoutlinemapper_p.h @@ -95,8 +95,7 @@ public: m_tags(0), m_contours(0), m_polygon_dev(0), - m_in_clip_elements(false), - m_round_coords(false) + m_in_clip_elements(false) { } @@ -202,8 +201,6 @@ public: QT_FT_Outline *convertPath(const QPainterPath &path); QT_FT_Outline *convertPath(const QVectorPath &path); - void setCoordinateRounding(bool coordinateRounding) { m_round_coords = coordinateRounding; } - inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? 0 : m_element_types.data(); } public: @@ -237,9 +234,6 @@ public: bool m_valid; bool m_in_clip_elements; - -private: - bool m_round_coords; }; QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 6ce21dc..51171c5 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -47,6 +47,7 @@ #include <private/qimage_p.h> #include <qstatictext.h> #include <private/qstatictext_p.h> +#include <private/qrawfont_p.h> #include <QDebug> @@ -54,8 +55,6 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); extern void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect, int tabstops, int* tabarray, int tabarraylen, @@ -130,7 +129,7 @@ QPaintBufferPrivate::~QPaintBufferPrivate() for (int i = 0; i < commands.size(); ++i) { const QPaintBufferCommand &cmd = commands.at(i); if (cmd.id == QPaintBufferPrivate::Cmd_DrawTextItem) - delete reinterpret_cast<QTextItemIntCopy *>(qVariantValue<void *>(variants.at(cmd.offset))); + delete reinterpret_cast<QTextItemIntCopy *>(qvariant_cast<void *>(variants.at(cmd.offset))); } } @@ -330,7 +329,7 @@ QString QPaintBuffer::commandDescription(int command) const break; } case QPaintBufferPrivate::Cmd_SetBrush: { - QBrush brush = qVariantValue<QBrush>(d_ptr->variants.at(cmd.offset)); + QBrush brush = qvariant_cast<QBrush>(d_ptr->variants.at(cmd.offset)); debug << "Cmd_SetBrush: " << brush; break; } @@ -354,27 +353,27 @@ QString QPaintBuffer::commandDescription(int command) const break; } case QPaintBufferPrivate::Cmd_StrokeVectorPath: { - QPen pen = qVariantValue<QPen>(d_ptr->variants.at(cmd.extra)); + QPen pen = qvariant_cast<QPen>(d_ptr->variants.at(cmd.extra)); debug << "ExCmd_StrokeVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2 << pen; break; } case QPaintBufferPrivate::Cmd_FillVectorPath: { - QBrush brush = qVariantValue<QBrush>(d_ptr->variants.at(cmd.extra)); + QBrush brush = qvariant_cast<QBrush>(d_ptr->variants.at(cmd.extra)); debug << "ExCmd_FillVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] << "pts/elms:" << cmd.offset << cmd.offset2 << brush; break; } case QPaintBufferPrivate::Cmd_FillRectBrush: { - QBrush brush = qVariantValue<QBrush>(d_ptr->variants.at(cmd.extra)); + QBrush brush = qvariant_cast<QBrush>(d_ptr->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset); debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; break; } case QPaintBufferPrivate::Cmd_FillRectColor: { - QColor color = qVariantValue<QColor>(d_ptr->variants.at(cmd.extra)); + QColor color = qvariant_cast<QColor>(d_ptr->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset); debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; break; } @@ -451,12 +450,12 @@ QString QPaintBuffer::commandDescription(int command) const break; } case QPaintBufferPrivate::Cmd_SetPen: { - QPen pen = qVariantValue<QPen>(d_ptr->variants.at(cmd.offset)); + QPen pen = qvariant_cast<QPen>(d_ptr->variants.at(cmd.offset)); debug << "Cmd_SetPen: " << pen; break; } case QPaintBufferPrivate::Cmd_SetTransform: { - QTransform xform = qVariantValue<QTransform>(d_ptr->variants.at(cmd.offset)); + QTransform xform = qvariant_cast<QTransform>(d_ptr->variants.at(cmd.offset)); debug << "Cmd_SetTransform, offset: " << cmd.offset << xform; break; } @@ -532,20 +531,10 @@ QString QPaintBuffer::commandDescription(int command) const case QPaintBufferPrivate::Cmd_DrawTextItem: { QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); - QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qVariantValue<void *>(d_ptr->variants.at(cmd.offset))); + QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qvariant_cast<void *>(d_ptr->variants.at(cmd.offset))); QTextItemInt &ti = (*tiCopy)(); QString text(ti.text()); - QFont font(ti.font()); - font.setUnderline(false); - font.setStrikeOut(false); - font.setOverline(false); - - const QTextItemInt &si = static_cast<const QTextItemInt &>(ti); - qreal justificationWidth = 0; - if (si.justified) - justificationWidth = si.width.toReal(); - debug << "Cmd_DrawTextItem:" << pos << " " << text; break; } case QPaintBufferPrivate::Cmd_SystemStateChanged: { @@ -1287,7 +1276,7 @@ void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) qDebug() << "QPaintBufferEngine: drawTextItem: pos:" << pos << ti.text(); #endif if (m_stream_raw_text_items) { - QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawTextItem, qVariantFromValue<void *>(new QTextItemIntCopy(ti))); + QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawTextItem, QVariant::fromValue<void *>(new QTextItemIntCopy(ti))); QFont font(ti.font()); font.setUnderline(false); @@ -1429,7 +1418,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_SetPen: { - QPen pen = qVariantValue<QPen>(d->variants.at(cmd.offset)); + QPen pen = qvariant_cast<QPen>(d->variants.at(cmd.offset)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetPen: " << pen; #endif @@ -1437,7 +1426,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_SetBrush: { - QBrush brush = qVariantValue<QBrush>(d->variants.at(cmd.offset)); + QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.offset)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetBrush: " << brush; #endif @@ -1452,7 +1441,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_SetTransform: { - QTransform xform = qVariantValue<QTransform>(d->variants.at(cmd.offset)); + QTransform xform = qvariant_cast<QTransform>(d->variants.at(cmd.offset)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_SetTransform, offset: " << cmd.offset << xform; #endif @@ -1520,7 +1509,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_StrokeVectorPath: { - QPen pen = qVariantValue<QPen>(d->variants.at(cmd.extra)); + QPen pen = qvariant_cast<QPen>(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_StrokeVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] @@ -1531,7 +1520,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_FillVectorPath: { - QBrush brush = qVariantValue<QBrush>(d->variants.at(cmd.extra)); + QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_FillVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] @@ -1705,7 +1694,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_FillRectBrush: { - QBrush brush = qVariantValue<QBrush>(d->variants.at(cmd.extra)); + QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; @@ -1714,7 +1703,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_FillRectColor: { - QColor color = qVariantValue<QColor>(d->variants.at(cmd.extra)); + QColor color = qvariant_cast<QColor>(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> Cmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; @@ -1756,26 +1745,38 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } +#if !defined(QT_NO_RAWFONT) case QPaintBufferPrivate::Cmd_DrawStaticText: { QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>()); QFont font = variants.at(0).value<QFont>(); - QVector<quint32> glyphs; + QVector<quint32> glyphIndexes; QVector<QPointF> positions; for (int i=0; i<(variants.size() - 1) / 2; ++i) { - glyphs.append(variants.at(i*2 + 1).toUInt()); + glyphIndexes.append(variants.at(i*2 + 1).toUInt()); positions.append(variants.at(i*2 + 2).toPointF()); } painter->setFont(font); - qt_draw_glyphs(painter, glyphs.constData(), positions.constData(), glyphs.size()); - - break; + QRawFont rawFont; + QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont); + QFontPrivate *fontD = QFontPrivate::get(font); + rawFontD->fontEngine = fontD->engineForScript(QUnicodeTables::Common); + rawFontD->fontEngine->ref.ref(); + + QGlyphs glyphs; + glyphs.setFont(rawFont); + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(positions); + + painter->drawGlyphs(QPointF(), glyphs); + break; } +#endif case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); @@ -1790,7 +1791,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) case QPaintBufferPrivate::Cmd_DrawTextItem: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); - QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qVariantValue<void *>(d->variants.at(cmd.offset))); + QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qvariant_cast<void *>(d->variants.at(cmd.offset))); QTextItemInt &ti = (*tiCopy)(); QString text(ti.text()); @@ -1885,7 +1886,7 @@ void QPaintEngineExReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_StrokeVectorPath: { - QPen pen = qVariantValue<QPen>(d->variants.at(cmd.extra)); + QPen pen = qvariant_cast<QPen>(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_StrokeVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] @@ -1896,7 +1897,7 @@ void QPaintEngineExReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_FillVectorPath: { - QBrush brush = qVariantValue<QBrush>(d->variants.at(cmd.extra)); + QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra)); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_FillVectorPath: size: " << cmd.size // << ", hints:" << d->ints[cmd.offset2+cmd.size] @@ -1907,7 +1908,7 @@ void QPaintEngineExReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_FillRectBrush: { - QBrush brush = qVariantValue<QBrush>(d->variants.at(cmd.extra)); + QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; @@ -1916,7 +1917,7 @@ void QPaintEngineExReplayer::process(const QPaintBufferCommand &cmd) break; } case QPaintBufferPrivate::Cmd_FillRectColor: { - QColor color = qVariantValue<QColor>(d->variants.at(cmd.extra)); + QColor color = qvariant_cast<QColor>(d->variants.at(cmd.extra)); QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset); #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << " -> ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; diff --git a/src/gui/painting/qpaintdevice.cpp b/src/gui/painting/qpaintdevice.cpp index 10463e0..f2ba7f0 100644 --- a/src/gui/painting/qpaintdevice.cpp +++ b/src/gui/painting/qpaintdevice.cpp @@ -59,11 +59,13 @@ QPaintDevice::~QPaintDevice() } +#ifndef Q_WS_QPA int QPaintDevice::metric(PaintDeviceMetric) const { qWarning("QPaintDevice::metrics: Device has no metric information"); return 0; } +#endif Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, QPaintDevice::PaintDeviceMetric metric) { diff --git a/src/gui/painting/qpaintdevice_qpa.cpp b/src/gui/painting/qpaintdevice_qpa.cpp new file mode 100644 index 0000000..0d1ca92 --- /dev/null +++ b/src/gui/painting/qpaintdevice_qpa.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintdevice.h" +#include "qpainter.h" +#include "qwidget.h" +#include "qbitmap.h" +#include "qapplication.h" + +QT_BEGIN_NAMESPACE + +extern void qt_painter_removePaintDevice(QPaintDevice *); //qpainter.cpp + +int QPaintDevice::metric(PaintDeviceMetric m) const +{ + qWarning("QPaintDevice::metrics: Device has no metric information"); + if (m == PdmDpiX) { + return 72; + } else if (m == PdmDpiY) { + return 72; + } else if (m == PdmNumColors) { + // FIXME: does this need to be a real value? + return 256; + } else { + qDebug("Unrecognised metric %d!",m); + return 0; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index f89a046..93aa63b 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -213,6 +213,7 @@ public: OpenVG, OpenGL2, PaintBuffer, + Blitter, User = 50, // first user type id MaxUser = 100 // last user type id @@ -270,6 +271,9 @@ private: friend class QtopiaPrintEnginePrivate; friend class QProxyFontEngine; #endif +#ifdef Q_WS_QPA + friend class QFontEngineQPA; +#endif friend class QPainter; friend class QPainterPrivate; friend class QWidget; diff --git a/src/gui/painting/qpaintengine_alpha.cpp b/src/gui/painting/qpaintengine_alpha.cpp index 339a002..171850d 100644 --- a/src/gui/painting/qpaintengine_alpha.cpp +++ b/src/gui/painting/qpaintengine_alpha.cpp @@ -46,6 +46,7 @@ #include "private/qpaintengine_alpha_p.h" #include "private/qpicture_p.h" +#include "private/qfont_p.h" #include "QtGui/qpicture.h" QT_BEGIN_NAMESPACE @@ -93,9 +94,6 @@ bool QAlphaPaintEngine::begin(QPaintDevice *pdev) return true; } -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); - bool QAlphaPaintEngine::end() { Q_D(QAlphaPaintEngine); diff --git a/src/gui/painting/qpaintengine_blitter.cpp b/src/gui/painting/qpaintengine_blitter.cpp new file mode 100644 index 0000000..500748e --- /dev/null +++ b/src/gui/painting/qpaintengine_blitter.cpp @@ -0,0 +1,663 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qpaintengine_blitter_p.h" + +#include "private/qblittable_p.h" +#include "private/qpaintengine_raster_p.h" +#include "private/qpainter_p.h" +#include "private/qapplication_p.h" +#include "private/qpixmap_blitter_p.h" + +#ifndef QT_NO_BLITTABLE +QT_BEGIN_NAMESPACE + +#define STATE_XFORM_SCALE 0x00000001 +#define STATE_XFORM_COMPLEX 0x00000002 + +#define STATE_BRUSH_PATTERN 0x00000010 +#define STATE_BRUSH_ALPHA 0x00000020 + +#define STATE_PEN_ENABLED 0x00000100 + +#define STATE_ANTIALIASING 0x00001000 +#define STATE_ALPHA 0x00002000 +#define STATE_BLENDING_COMPLEX 0x00004000 + +#define STATE_CLIPSYS_COMPLEX 0x00010000 +#define STATE_CLIP_COMPLEX 0x00020000 + + +static inline void updateStateBits(uint *state, uint mask, bool on) +{ + *state = on ? (*state | mask) : (*state & ~mask); +} + +static inline bool checkStateAgainstMask(uint state, uint mask) +{ + return !state || (state & mask && !(state & ~mask)); +} + +class CapabilitiesToStateMask +{ +public: + CapabilitiesToStateMask(QBlittable::Capabilities capabilities) + : m_capabilities(capabilities), + fillRectMask(0), + drawRectMask(0), + drawPixmapMask(0), + capabillitiesState(0) + { + if (capabilities & QBlittable::SolidRectCapability) { + setFillRectMask(); + } + if (capabilities & QBlittable::SourcePixmapCapability) { + setSourcePixmapMask(); + } + if (capabilities & QBlittable::SourceOverPixmapCapability) { + setSourceOverPixmapMask(); + } + if (capabilities & QBlittable::SourceOverScaledPixmapCapability) { + setSourceOverScaledPixmapMask(); + } + } + + inline bool canBlitterFillRect() const + { + return checkStateAgainstMask(capabillitiesState,fillRectMask); + } + + inline bool canBlitterDrawRectMask() const + { + return checkStateAgainstMask(capabillitiesState,drawRectMask); + } + + bool canBlitterDrawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) const + { + if (pm.pixmapData()->classId() != QPixmapData::BlitterClass) + return false; + if (checkStateAgainstMask(capabillitiesState,drawPixmapMask)) { + if (m_capabilities & (QBlittable::SourceOverPixmapCapability + | QBlittable::SourceOverScaledPixmapCapability)) { + if (r.size() != sr.size()) { + return m_capabilities & QBlittable::SourceOverScaledPixmapCapability; + } else { + return m_capabilities & QBlittable::SourceOverPixmapCapability; + } + } + if ((m_capabilities & QBlittable::SourcePixmapCapability) && r.size() == sr.size() && !pm.hasAlphaChannel()) { + return m_capabilities & QBlittable::SourcePixmapCapability; + } + } + return false; + } + + inline void updateState(uint mask, bool on) { + updateStateBits(&capabillitiesState,mask,on); + } + +public: + + void setFillRectMask() { + updateStateBits(&fillRectMask, STATE_XFORM_SCALE, false); + updateStateBits(&fillRectMask, STATE_XFORM_COMPLEX, false); + + updateStateBits(&fillRectMask, STATE_BRUSH_PATTERN, false); + updateStateBits(&fillRectMask, STATE_BRUSH_ALPHA, false); + + updateStateBits(&fillRectMask, STATE_PEN_ENABLED, true); + + //Sub-pixel aliasing should not be sent to the blitter + updateStateBits(&fillRectMask, STATE_ANTIALIASING, true); + updateStateBits(&fillRectMask, STATE_ALPHA, false); + updateStateBits(&fillRectMask, STATE_BLENDING_COMPLEX, false); + + updateStateBits(&fillRectMask, STATE_CLIPSYS_COMPLEX, false); + updateStateBits(&fillRectMask, STATE_CLIP_COMPLEX, false); + } + + void setSourcePixmapMask() { + updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, true); + updateStateBits(&drawPixmapMask, STATE_XFORM_COMPLEX, false); + + updateStateBits(&drawPixmapMask, STATE_BRUSH_PATTERN, true); + updateStateBits(&drawPixmapMask, STATE_BRUSH_ALPHA, false); + + updateStateBits(&drawPixmapMask, STATE_PEN_ENABLED, true); + + updateStateBits(&drawPixmapMask, STATE_ANTIALIASING, true); + updateStateBits(&drawPixmapMask, STATE_ALPHA, false); + updateStateBits(&drawPixmapMask, STATE_BLENDING_COMPLEX, false); + + updateStateBits(&drawPixmapMask, STATE_CLIPSYS_COMPLEX, false); + updateStateBits(&drawPixmapMask, STATE_CLIP_COMPLEX, false); + } + + void setSourceOverPixmapMask() { + setSourcePixmapMask(); + } + + void setSourceOverScaledPixmapMask() { + setSourceOverPixmapMask(); + updateStateBits(&drawRectMask, STATE_XFORM_SCALE, true); + } + + QBlittable::Capabilities m_capabilities; + uint fillRectMask; + uint drawRectMask; + uint drawPixmapMask; + uint capabillitiesState; +}; + +class QBlitterPaintEnginePrivate : public QPaintEngineExPrivate +{ + Q_DECLARE_PUBLIC(QBlitterPaintEngine); +public: + QBlitterPaintEnginePrivate(QBlittablePixmapData *p) + : QPaintEngineExPrivate(), + pmData(p), + isBlitterLocked(false), + hasXForm(false) + + { + raster = new QRasterPaintEngine(p->buffer()); + capabillities = new CapabilitiesToStateMask(pmData->blittable()->capabilities()); + } + + inline void lock() { + if (!isBlitterLocked) { + raster->d_func()->rasterBuffer->prepare(pmData->blittable()->lock()); + isBlitterLocked = true; + } + } + + inline void unlock() { + if (isBlitterLocked) { + pmData->blittable()->unlock(); + isBlitterLocked = false; + } + } + + void fillRect(const QRectF &rect, const QColor &color) { + Q_Q(QBlitterPaintEngine); + pmData->unmarkRasterOverlay(rect); + QRectF targetRect = rect; + if (hasXForm) { + targetRect = q->state()->matrix.mapRect(rect); + } + const QClipData *clipData = q->clip(); + if (clipData) { + if (clipData->hasRectClip) { + unlock(); + pmData->blittable()->fillRect(targetRect & clipData->clipRect, color); + } else if (clipData->hasRegionClip) { + QVector<QRect> rects = clipData->clipRegion.rects(); + for ( int i = 0; i < rects.size(); i++ ) { + QRect intersectRect = rects.at(i).intersected(targetRect.toRect()); + if (!intersectRect.isEmpty()) { + unlock(); + pmData->blittable()->fillRect(intersectRect,color); + } + } + } + } else { + if (targetRect.x() >= 0 && targetRect.y() >= 0 + && targetRect.width() <= raster->paintDevice()->width() + && targetRect.height() <= raster->paintDevice()->height()) { + unlock(); + pmData->blittable()->fillRect(targetRect,color); + } else { + QRectF deviceRect(0,0,raster->paintDevice()->width(), raster->paintDevice()->height()); + unlock(); + pmData->blittable()->fillRect(deviceRect&targetRect,color); + } + } + } + + void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr) { + QRectF intersectedRect = clip.intersected(target); + if (intersectedRect.isEmpty()) + return; + QRectF source = sr; + if(intersectedRect.size() != target.size()) { + qreal deltaTop = target.top() - intersectedRect.top(); + qreal deltaLeft = target.left() - intersectedRect.left(); + qreal deltaBottom = target.bottom() - intersectedRect.bottom(); + qreal deltaRight = target.right() - intersectedRect.right(); + source.adjust(-deltaLeft,-deltaTop,-deltaRight,-deltaBottom); + } + pmData->unmarkRasterOverlay(intersectedRect); + pmData->blittable()->drawPixmap(intersectedRect, pm, source); + } + + void updateClip() { + Q_Q(QBlitterPaintEngine); + const QClipData *clip = q->clip(); + bool complex = clip && !(clip->hasRectClip || clip->hasRegionClip); + capabillities->updateState(STATE_CLIP_COMPLEX, complex); + } + + void systemStateChanged() { + raster->d_func()->systemStateChanged(); + } + + QRasterPaintEngine *raster; + + QBlittablePixmapData *pmData; + bool isBlitterLocked; + + CapabilitiesToStateMask *capabillities; + + uint hasXForm; +}; + +QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePixmapData *p) + : QPaintEngineEx(*(new QBlitterPaintEnginePrivate(p))) +{ +} + +QBlitterPaintEngine::~QBlitterPaintEngine() +{ +} + +QPainterState *QBlitterPaintEngine::createState(QPainterState *orig) const +{ + Q_D(const QBlitterPaintEngine); + return d->raster->createState(orig); +} + +bool QBlitterPaintEngine::begin(QPaintDevice *pdev) +{ + Q_D(QBlitterPaintEngine); + + setActive(true); + bool ok = d->raster->begin(pdev); +#ifdef QT_BLITTER_RASTEROVERLAY + d->pmData->unmergeOverlay(); +#endif + return ok; +} + + +bool QBlitterPaintEngine::end() +{ + Q_D(QBlitterPaintEngine); + + setActive(false); +#ifdef QT_BLITTER_RASTEROVERLAY + d->pmData->mergeOverlay(); +#endif + return d->raster->end(); +} + + +void QBlitterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QBlitterPaintEngine); + if (path.shape() == QVectorPath::RectangleHint) { + QRectF rect(((QPointF *) path.points())[0], ((QPointF *) path.points())[2]); + fillRect(rect, brush); + } else { + d->lock(); + d->pmData->markRasterOverlay(path); + d->raster->fill(path, brush); + } +} + +void QBlitterPaintEngine::fillRect(const QRectF &rect, const QColor &color) +{ + Q_D(QBlitterPaintEngine); + if (d->capabillities->canBlitterFillRect() && color.alpha() == 0xff) { + d->fillRect(rect, color); + } else { + d->lock(); + d->pmData->markRasterOverlay(rect); + d->raster->fillRect(rect, color); + } +} + +void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) +{ + if(rect.size().isEmpty()) + return; + + Q_D(QBlitterPaintEngine); + + if (qbrush_style(brush) == Qt::SolidPattern + && qbrush_color(brush).alpha() == 0xff + && d->capabillities->canBlitterFillRect()) + { + d->fillRect(rect, qbrush_color(brush)); + }else if (brush.style() == Qt::TexturePattern + && d->capabillities->canBlitterDrawPixmap(rect,brush.texture(),rect)) + { + bool rectIsFilled = false; + QRectF transformedRect = state()->matrix.mapRect(rect); + qreal x = transformedRect.x(); + qreal y = transformedRect.y(); + QPixmap pm = brush.texture(); + d->unlock(); + int srcX = int(rect.x() - state()->brushOrigin.x()) % pm.width(); + if (srcX < 0) + srcX = pm.width() + srcX; + const int startX = srcX; + int srcY = int(rect.y() - state()->brushOrigin.y()) % pm.height(); + if (srcY < 0) + srcY = pm.height() + srcY; + while (!rectIsFilled) { + qreal blitWidth = (pm.width() ) - srcX; + qreal blitHeight = (pm.height() ) - srcY; + if (x + blitWidth > transformedRect.right()) + blitWidth = transformedRect.right() -x; + if (y + blitHeight > transformedRect.bottom()) + blitHeight = transformedRect.bottom() - y; + const QClipData *clipData = clip(); + if (clipData->hasRectClip) { + QRect targetRect = QRect(x,y,blitWidth,blitHeight).intersected(clipData->clipRect); + if (targetRect.isValid()) { + int tmpSrcX = srcX + (targetRect.x() - x); + int tmpSrcY = srcY + (targetRect.y() - y); + QRect srcRect(tmpSrcX,tmpSrcY,targetRect.width(),targetRect.height()); + d->pmData->blittable()->drawPixmap(targetRect,pm,srcRect); + } + } else if (clipData->hasRegionClip) { + QVector<QRect> clipRects = clipData->clipRegion.rects(); + QRect unclippedTargetRect(x,y,blitWidth,blitHeight); + QRegion intersectedRects = clipData->clipRegion.intersected(unclippedTargetRect); + + for ( int i = 0; i < intersectedRects.rects().size(); i++ ) { + QRect targetRect = intersectedRects.rects().at(i); + if (!targetRect.isValid() || targetRect.isEmpty()) + continue; + int tmpSrcX = srcX + (targetRect.x() - x); + int tmpSrcY = srcY + (targetRect.y() - y); + QRect srcRect(tmpSrcX,tmpSrcY,targetRect.width(),targetRect.height()); + d->pmData->blittable()->drawPixmap(targetRect,pm,srcRect); + } + } + x+=blitWidth; + if (x>=transformedRect.right()) { + x = transformedRect.x(); + srcX = startX; + srcY = 0; + y+=blitHeight; + if (y>=transformedRect.bottom()) + rectIsFilled = true; + } else + srcX = 0; + } + } else { + d->lock(); + d->pmData->markRasterOverlay(rect); + d->raster->fillRect(rect, brush); + } + +} + +void QBlitterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->pmData->markRasterOverlay(path); + d->raster->stroke(path, pen); +} + +void QBlitterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->clip(path, op); + d->updateClip(); +} +void QBlitterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op){ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->clip(rect,op); + d->updateClip(); +} +void QBlitterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->clip(region,op); + d->updateClip(); +} + +void QBlitterPaintEngine::clipEnabledChanged() +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->clipEnabledChanged(); +} + +void QBlitterPaintEngine::penChanged() +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->penChanged(); + d->capabillities->updateState(STATE_PEN_ENABLED,qpen_style(state()->pen) != Qt::NoPen); +} + +void QBlitterPaintEngine::brushChanged() +{ + Q_D(QBlitterPaintEngine); + d->raster->brushChanged(); + + bool solid = qbrush_style(state()->brush) == Qt::SolidPattern; + + d->capabillities->updateState(STATE_BRUSH_PATTERN, !solid); + d->capabillities->updateState(STATE_BRUSH_ALPHA, + qbrush_color(state()->brush).alpha() < 255); +} + +void QBlitterPaintEngine::brushOriginChanged() +{ + Q_D(QBlitterPaintEngine); + d->raster->brushOriginChanged(); +} + +void QBlitterPaintEngine::opacityChanged() +{ + Q_D(QBlitterPaintEngine); + d->raster->opacityChanged(); + + bool translucent = state()->opacity < 1; + d->capabillities->updateState(STATE_ALPHA,translucent); +} + +void QBlitterPaintEngine::compositionModeChanged() +{ + Q_D(QBlitterPaintEngine); + d->raster->compositionModeChanged(); + + bool nonTrivial = state()->composition_mode != QPainter::CompositionMode_SourceOver + && state()->composition_mode != QPainter::CompositionMode_Source; + + d->capabillities->updateState(STATE_BLENDING_COMPLEX,nonTrivial); +} + +void QBlitterPaintEngine::renderHintsChanged() +{ + Q_D(QBlitterPaintEngine); + d->raster->renderHintsChanged(); + + bool aa = state()->renderHints & QPainter::Antialiasing; + d->capabillities->updateState(STATE_ANTIALIASING, aa); + +} + +void QBlitterPaintEngine::transformChanged() +{ + Q_D(QBlitterPaintEngine); + d->raster->transformChanged(); + + QTransform::TransformationType type = state()->matrix.type(); + + d->capabillities->updateState(STATE_XFORM_COMPLEX, type > QTransform::TxScale); + d->capabillities->updateState(STATE_XFORM_SCALE, type > QTransform::TxTranslate); + + d->hasXForm = type >= QTransform::TxTranslate; + +} + +void QBlitterPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + Q_D(QBlitterPaintEngine); + if (d->capabillities->canBlitterDrawRectMask()) { + for (int i=0; i<rectCount; ++i) { + d->fillRect(rects[i], qbrush_color(state()->brush)); + } + } else { + d->pmData->markRasterOverlay(rects,rectCount); + QPaintEngineEx::drawRects(rects, rectCount); + } +} + +void QBlitterPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + Q_D(QBlitterPaintEngine); + if (d->capabillities->canBlitterDrawRectMask()) { + for (int i=0; i<rectCount; ++i) { + d->fillRect(rects[i], qbrush_color(state()->brush)); + } + } else { + d->pmData->markRasterOverlay(rects,rectCount); + QPaintEngineEx::drawRects(rects, rectCount); + } +} + +void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) +{ + Q_D(QBlitterPaintEngine); + if (d->capabillities->canBlitterDrawPixmap(r,pm,sr)) { + + d->unlock(); + QRectF targetRect = r; + if (d->hasXForm) { + targetRect = state()->matrix.mapRect(r); + } + const QClipData *clipData = clip(); + if (clipData) { + if (clipData->hasRectClip) { + d->clipAndDrawPixmap(clipData->clipRect,targetRect,pm,sr); + }else if (clipData->hasRegionClip) { + QVector<QRect>rects = clipData->clipRegion.rects(); + for (int i = 0; i<rects.size(); i++) { + d->clipAndDrawPixmap(rects.at(i),targetRect,pm,sr); + } + } + } else { + QRectF deviceRect(0,0,d->raster->paintDevice()->width(), d->raster->paintDevice()->height()); + d->clipAndDrawPixmap(deviceRect,targetRect,pm,sr); + } + }else { + d->lock(); + d->pmData->markRasterOverlay(r); + d->raster->drawPixmap(r, pm, sr); + } +} + +void QBlitterPaintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags flags) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->pmData->markRasterOverlay(r); + d->raster->drawImage(r, pm, sr, flags); +} + + +void QBlitterPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->drawTextItem(pos, ti); + d->pmData->markRasterOverlay(pos,ti); +} + +void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->raster->drawStaticTextItem(sti); + +//#### d->pmData->markRasterOverlay(sti); + qWarning("not implemented: markRasterOverlay for QStaticTextItem"); + +} + + +void QBlitterPaintEngine::drawEllipse(const QRectF &r) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + d->pmData->markRasterOverlay(r); + d->raster->drawEllipse(r); +} + +void QBlitterPaintEngine::setState(QPainterState *s) +{ + Q_D(QBlitterPaintEngine); + d->lock(); + QPaintEngineEx::setState(s); + d->raster->setState(s); + + clipEnabledChanged(); + penChanged(); + brushChanged(); + brushOriginChanged(); + opacityChanged(); + compositionModeChanged(); + renderHintsChanged(); + transformChanged(); + + d->updateClip(); +} + +inline QRasterPaintEngine *QBlitterPaintEngine::raster() const +{ + Q_D(const QBlitterPaintEngine); + return d->raster; +} + +QT_END_NAMESPACE +#endif //QT_NO_BLITTABLE + diff --git a/src/gui/painting/qpaintengine_blitter_p.h b/src/gui/painting/qpaintengine_blitter_p.h new file mode 100644 index 0000000..be8b2bc --- /dev/null +++ b/src/gui/painting/qpaintengine_blitter_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_BLITTER_P_H +#define QPAINTENGINE_BLITTER_P_H + +#include "private/qpaintengineex_p.h" +#include "private/qpaintengine_raster_p.h" + +#ifndef QT_NO_BLITTABLE +QT_BEGIN_NAMESPACE + +class QBlitterPaintEnginePrivate; +class QBlittablePixmapData; +class QBlittable; + +class Q_GUI_EXPORT QBlitterPaintEngine : public QPaintEngineEx +{ + Q_DECLARE_PRIVATE(QBlitterPaintEngine); +public: + QBlitterPaintEngine(QBlittablePixmapData *p); + ~QBlitterPaintEngine(); + + virtual QPainterState *createState(QPainterState *orig) const; + + virtual QPaintEngine::Type type() const { return Blitter; } + + virtual bool begin(QPaintDevice *pdev); + virtual bool end(); + + virtual void fill(const QVectorPath &path, const QBrush &brush); + virtual void stroke(const QVectorPath &path, const QPen &pen); + + virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + virtual void clip(const QRect &rect, Qt::ClipOperation op); + virtual void clip(const QRegion ®ion, Qt::ClipOperation op); + + virtual void clipEnabledChanged(); + virtual void penChanged(); + virtual void brushChanged(); + virtual void brushOriginChanged(); + virtual void opacityChanged(); + virtual void compositionModeChanged(); + virtual void renderHintsChanged(); + virtual void transformChanged(); + + virtual void fillRect(const QRectF &rect, const QBrush &brush); + virtual void fillRect(const QRectF &rect, const QColor &color); + + virtual void drawRects(const QRect *rects, int rectCount); + virtual void drawRects(const QRectF *rects, int rectCount); + + virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + + virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags); + + virtual void drawTextItem(const QPointF &pos, const QTextItem &ti); + virtual void drawStaticTextItem(QStaticTextItem *); + + virtual void drawEllipse(const QRectF &r); + + virtual void setState(QPainterState *s); + + inline QPainterState *state() { return raster()->state(); } + inline const QPainterState *state() const { const QPainterState *state = raster()->state(); return state;} + inline const QClipData *clip(){return raster()->d_func()->clip();} + +private: + QRasterPaintEngine *raster() const; +}; + +QT_END_NAMESPACE +#endif //QT_NO_BLITTABLE +#endif // QPAINTENGINE_BLITTER_P_H + diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index b07053e..cc75b86 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -57,6 +57,8 @@ #include <private/qfont_p.h> #include <private/qfontengine_p.h> +#include <private/qfontengine_coretext_p.h> +#include <private/qfontengine_mac_p.h> #include <private/qnumeric_p.h> #include <private/qpainter_p.h> #include <private/qpainterpath_p.h> @@ -131,8 +133,9 @@ QMacCGContext::QMacCGContext(QPainter *p) CGContextTranslateCTM(context, native.dx(), native.dy()); } + } else { + CGContextRetain(context); } - CGContextRetain(context); } @@ -1541,8 +1544,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset) QPointF center(radialGrad->center()); QPointF focal(radialGrad->focalPoint()); qreal radius = radialGrad->radius(); + qreal focalRadius = radialGrad->focalRadius(); shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()), - 0.0, CGPointMake(center.x(), center.y()), radius, fill_func, false, true); + focalRadius, CGPointMake(center.x(), center.y()), radius, fill_func, false, true); } CGFunctionRelease(fill_func); diff --git a/src/gui/painting/qpaintengine_mac_p.h b/src/gui/painting/qpaintengine_mac_p.h index 5c459ee..3e71d6c 100644 --- a/src/gui/painting/qpaintengine_mac_p.h +++ b/src/gui/painting/qpaintengine_mac_p.h @@ -57,15 +57,12 @@ #include "private/qt_mac_p.h" #include "private/qpaintengine_p.h" #include "private/qpolygonclipper_p.h" +#include "private/qfont_p.h" #include "QtCore/qhash.h" typedef struct CGColorSpace *CGColorSpaceRef; QT_BEGIN_NAMESPACE -extern int qt_defaultDpi(); -extern int qt_defaultDpiX(); -extern int qt_defaultDpiY(); - class QCoreGraphicsPaintEnginePrivate; class QCoreGraphicsPaintEngine : public QPaintEngine { diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index ba618ea..2119e30 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -96,6 +96,8 @@ # include <private/qabstractfontengine_p.h> #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) # include <private/qfontengine_s60_p.h> +#elif defined(Q_WS_QPA) +# include <private/qfontengine_ft_p.h> #endif #if defined(Q_WS_WIN64) @@ -124,9 +126,6 @@ void dumpClip(int width, int height, const QClipData *clip); // 4 pixels. #define int_dim(pos, dim) (int(pos+dim) - int(pos)) -// use the same rounding as in qrasterizer.cpp (6 bit fixed point) -static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; - #ifdef Q_WS_WIN extern bool qt_cleartype_enabled; #endif @@ -444,7 +443,7 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) if (device->devType() == QInternal::Pixmap) { QPixmap *pixmap = static_cast<QPixmap *>(device); QPixmapData *pd = pixmap->pixmapData(); - if (pd->classId() == QPixmapData::RasterClass) + if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass) d->device = pd->buffer(); } else { d->device = device; @@ -663,31 +662,23 @@ QRasterPaintEngineState::QRasterPaintEngineState() QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s) : QPainterState(s) + , lastPen(s.lastPen) + , penData(s.penData) + , stroker(s.stroker) + , strokeFlags(s.strokeFlags) + , lastBrush(s.lastBrush) + , brushData(s.brushData) + , fillFlags(s.fillFlags) + , pixmapFlags(s.pixmapFlags) + , intOpacity(s.intOpacity) + , txscale(s.txscale) + , clip(s.clip) + , dirty(s.dirty) + , flag_bits(s.flag_bits) { - stroker = s.stroker; - - lastBrush = s.lastBrush; - brushData = s.brushData; brushData.tempImage = 0; - - lastPen = s.lastPen; - penData = s.penData; penData.tempImage = 0; - - fillFlags = s.fillFlags; - strokeFlags = s.strokeFlags; - pixmapFlags = s.pixmapFlags; - - intOpacity = s.intOpacity; - - txscale = s.txscale; - - flag_bits = s.flag_bits; - - clip = s.clip; flags.has_clip_ownership = false; - - dirty = s.dirty; } /*! @@ -1769,10 +1760,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) static inline QRect toNormalizedFillRect(const QRectF &rect) { - int x1 = qRound(rect.x() + aliasedCoordinateDelta); - int y1 = qRound(rect.y() + aliasedCoordinateDelta); - int x2 = qRound(rect.right() + aliasedCoordinateDelta); - int y2 = qRound(rect.bottom() + aliasedCoordinateDelta); + int x1 = qRound(rect.x()); + int y1 = qRound(rect.y()); + int x2 = qRound(rect.right()); + int y2 = qRound(rect.bottom()); if (x2 < x1) qSwap(x1, x2); @@ -2041,7 +2032,6 @@ void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, Poly */ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) { - Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); #ifdef QT_DEBUG_DRAW @@ -2062,9 +2052,7 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly if (mode != PolylineMode) { // Do the fill... if (s->brushData.blend) { - d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque()); fillPolygon(points, pointCount, mode); - d->outlineMapper->setCoordinateRounding(false); } } @@ -2116,7 +2104,6 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg if (s->brushData.blend) { // Compose polygon fill.., ensureOutlineMapper(); - d->outlineMapper->setCoordinateRounding(s->penData.blend != 0); d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill); d->outlineMapper->moveTo(*points); const QPoint *p = points; @@ -2130,7 +2117,6 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect, &s->brushData); d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data()); - d->outlineMapper->setCoordinateRounding(false); } } @@ -2178,13 +2164,11 @@ void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointC : LineDrawNormal); int dashOffset = int(s->lastPen.dashOffset()); - const QPointF offs(aliasedCoordinateDelta, aliasedCoordinateDelta); - // Draw all the line segments. for (int i=1; i<pointCount; ++i) { - QPointF lp1 = points[i-1] * s->matrix + offs; - QPointF lp2 = points[i] * s->matrix + offs; + QPointF lp1 = points[i-1] * s->matrix; + QPointF lp2 = points[i] * s->matrix; const QRectF brect(lp1, lp2); ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); @@ -2206,8 +2190,8 @@ void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointC // Polygons are implicitly closed. if (needs_closing) { - QPointF lp1 = points[pointCount-1] * s->matrix + offs; - QPointF lp2 = points[0] * s->matrix + offs; + QPointF lp1 = points[pointCount-1] * s->matrix; + QPointF lp2 = points[0] * s->matrix; const QRectF brect(lp1, lp2); ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); @@ -2506,7 +2490,7 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img) const QClipData *clip = d->clip(); QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy()); - if (s->flags.fast_images) { + if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()]; if (func) { if (!clip) { @@ -2595,10 +2579,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe int sr_b = qCeil(sr.bottom()) - 1; if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) { - // as fillRect will apply the aliased coordinate delta we need to - // subtract it here as we don't use it for image drawing QTransform old = s->matrix; - s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta); // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied. QRgb color = img.pixel(sr_l, sr_t); @@ -2690,7 +2671,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe bool exceedsPrecision = targetBounds.width() > 0xffff || targetBounds.height() > 0xffff; - if (s->flags.fast_images && !exceedsPrecision) { + if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { if (s->matrix.type() > QTransform::TxScale) { SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()]; if (func && (!clip || clip->hasRectClip)) { @@ -2742,11 +2723,9 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe d->initializeRasterizer(&d->image_filler_xform); d->rasterizer->setAntialiased(s->flags.antialiased); - const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta); - const QRectF &rect = r.normalized(); - const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs; - const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs; + const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f); + const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f); if (s->flags.tx_noshear) d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width()); @@ -2755,18 +2734,16 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; } #endif - const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta; QPainterPath path; path.addRect(r); QTransform m = s->matrix; s->matrix = QTransform(m.m11(), m.m12(), m.m13(), m.m21(), m.m22(), m.m23(), - m.m31() - offs, m.m32() - offs, m.m33()); + m.m31(), m.m32(), m.m33()); fillPath(path, &d->image_filler_xform); s->matrix = m; } else { - - if (s->flags.fast_images) { + if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()]; if (func) { QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy()); @@ -3099,56 +3076,145 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx blend(current, spans, &s->penData); } -void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, +bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; +#if !defined(QT_NO_FREETYPE) + if (fontEngine->type() == QFontEngine::Freetype) { + QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine); + QFontEngineFT::GlyphFormat neededFormat = + painter()->device()->devType() == QInternal::Widget + ? fe->defaultGlyphFormat() + : QFontEngineFT::Format_A8; + + if (d_func()->mono_surface + || fe->isBitmapFont() // alphaPenBlt can handle mono, too + ) + neededFormat = QFontEngineFT::Format_Mono; + + if (neededFormat == QFontEngineFT::Format_None) + neededFormat = QFontEngineFT::Format_A8; + + QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs(); + if (s->matrix.type() >= QTransform::TxScale) { + if (s->matrix.isAffine()) + gset = fe->loadTransformedGlyphSet(s->matrix); + else + gset = 0; + } - QImageTextureGlyphCache *cache = - static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix)); - if (!cache) { - cache = new QImageTextureGlyphCache(glyphType, s->matrix); - fontEngine->setGlyphCache(0, cache); - } + if (!gset || gset->outline_drawing + || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat)) + return false; + + FT_Face lockedFace = 0; + + int depth; + switch (neededFormat) { + case QFontEngineFT::Format_Mono: + depth = 1; + break; + case QFontEngineFT::Format_A8: + depth = 8; + break; + case QFontEngineFT::Format_A32: + depth = 32; + break; + default: + Q_ASSERT(false); + depth = 0; + }; + + for (int i = 0; i < numGlyphs; i++) { + QFixed spp = fe->subPixelPositionForX(positions[i].x); + QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp); + + if (!glyph || glyph->format != neededFormat) { + if (!lockedFace) + lockedFace = fe->lockFace(); + glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat); + } - cache->populate(fontEngine, numGlyphs, glyphs, positions); + if (!glyph || !glyph->data) + continue; + + int pitch; + switch (neededFormat) { + case QFontEngineFT::Format_Mono: + pitch = ((glyph->width + 31) & ~31) >> 3; + break; + case QFontEngineFT::Format_A8: + pitch = (glyph->width + 3) & ~3; + break; + case QFontEngineFT::Format_A32: + pitch = glyph->width * 4; + break; + default: + Q_ASSERT(false); + pitch = 0; + }; + + alphaPenBlt(glyph->data, pitch, depth, + qFloor(positions[i].x) + glyph->x, + qFloor(positions[i].y) - glyph->y, + glyph->width, glyph->height); + } + if (lockedFace) + fe->unlockFace(); + } else +#endif + { + QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; - const QImage &image = cache->image(); - int bpl = image.bytesPerLine(); + QImageTextureGlyphCache *cache = + static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix)); + if (!cache) { + cache = new QImageTextureGlyphCache(glyphType, s->matrix); + fontEngine->setGlyphCache(0, cache); + } - int depth = image.depth(); - int rightShift = 0; - int leftShift = 0; - if (depth == 32) - leftShift = 2; // multiply by 4 - else if (depth == 1) - rightShift = 3; // divide by 8 + cache->populate(fontEngine, numGlyphs, glyphs, positions); + cache->fillInPendingGlyphs(); - int margin = cache->glyphMargin(); + const QImage &image = cache->image(); + int bpl = image.bytesPerLine(); - const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); + int depth = image.depth(); + int rightShift = 0; + int leftShift = 0; + if (depth == 32) + leftShift = 2; // multiply by 4 + else if (depth == 1) + rightShift = 3; // divide by 8 - const uchar *bits = image.bits(); - for (int i=0; i<numGlyphs; ++i) { - const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); - int x = qFloor(positions[i].x + offs) + c.baseLineX - margin; - int y = qFloor(positions[i].y + offs) - c.baseLineY - margin; + int margin = cache->glyphMargin(); + const uchar *bits = image.bits(); + for (int i=0; i<numGlyphs; ++i) { -// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n", -// c.x, c.y, -// c.w, c.h, -// c.baseLineX, c.baseLineY, -// glyphs[i], -// x, y, -// positions[i].x.toInt(), positions[i].y.toInt()); + QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x); + QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition); + const QTextureGlyphCache::Coord &c = cache->coords[glyph]; + if (c.isNull()) + continue; - alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h); - } + int x = qFloor(positions[i].x) + c.baseLineX - margin; + int y = qFloor(positions[i].y) - c.baseLineY - margin; - return; + // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n", + // c.x, c.y, + // c.w, c.h, + // c.baseLineX, c.baseLineY, + // glyphs[i], + // x, y, + // positions[i].x.toInt(), positions[i].y.toInt()); + + alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h); + } + } + return true; } #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) @@ -3173,15 +3239,13 @@ void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti) fe->setFontScale(matrix.m11()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta); - for (int i=0; i<glyphs.size(); ++i) { TOpenFontCharMetrics tmetrics; const TUint8 *glyphBitmapBytes; TSize glyphBitmapSize; fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize); - const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta); - const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta); + const int x = qFloor(positions[i].x + tmetrics.HorizBearingX()); + const int y = qFloor(positions[i].y - tmetrics.HorizBearingY()); alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight); } @@ -3394,7 +3458,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte #if defined(Q_WS_QWS) if (fontEngine->type() == QFontEngine::Box) { - fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti); + fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti); return; } @@ -3403,11 +3467,38 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte || (fontEngine->type() == QFontEngine::Proxy && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline())) )) { - fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti); + fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti); return; } #endif // Q_WS_QWS +#ifdef Q_WS_QPA + if (s->matrix.type() < QTransform::TxScale) { + + QVarLengthArray<QFixedPoint> positions; + QVarLengthArray<glyph_t> glyphs; + QTransform matrix = state()->transform(); + + qreal _x = qFloor(p.x()); + qreal _y = qFloor(p.y()); + matrix.translate(_x, _y); + + fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + if (glyphs.size() == 0) + return; + + for(int i = 0; i < glyphs.size(); i++) { + QImage img = fontEngine->alphaMapForGlyph(glyphs[i]); + glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]); + alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(), + qRound(positions[i].x + metrics.x), + qRound(positions[i].y + metrics.y), + img.width(), img.height()); + } + return; + } +#endif //Q_WS_QPA + #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2) @@ -3434,92 +3525,10 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte if (glyphs.size() == 0) return; - // only use subpixel antialiasing when drawing to widgets - QFontEngineFT::GlyphFormat neededFormat = - painter()->device()->devType() == QInternal::Widget - ? fe->defaultGlyphFormat() - : QFontEngineFT::Format_A8; - - if (d_func()->mono_surface - || fe->isBitmapFont() // alphaPenBlt can handle mono, too - ) - neededFormat = QFontEngineFT::Format_Mono; - - if (neededFormat == QFontEngineFT::Format_None) - neededFormat = QFontEngineFT::Format_A8; - - QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs(); - if (s->matrix.type() >= QTransform::TxScale) { - if (s->matrix.isAffine()) - gset = fe->loadTransformedGlyphSet(s->matrix); - else - gset = 0; - - } - - if (!gset || gset->outline_drawing - || !fe->loadGlyphs(gset, glyphs.data(), glyphs.size(), neededFormat)) - { + if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine)) QPaintEngine::drawTextItem(p, ti); - return; - } - - QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); - FT_Face lockedFace = 0; - - int depth; - switch (neededFormat) { - case QFontEngineFT::Format_Mono: - depth = 1; - break; - case QFontEngineFT::Format_A8: - depth = 8; - break; - case QFontEngineFT::Format_A32: - depth = 32; - break; - default: - Q_ASSERT(false); - depth = 0; - }; - - for(int i = 0; i < glyphs.size(); i++) { - QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i]); - - if (!glyph || glyph->format != neededFormat) { - if (!lockedFace) - lockedFace = fe->lockFace(); - glyph = fe->loadGlyph(gset, glyphs[i], neededFormat); - } - if (!glyph || !glyph->data) - continue; - - int pitch; - switch (neededFormat) { - case QFontEngineFT::Format_Mono: - pitch = ((glyph->width + 31) & ~31) >> 3; - break; - case QFontEngineFT::Format_A8: - pitch = (glyph->width + 3) & ~3; - break; - case QFontEngineFT::Format_A32: - pitch = glyph->width * 4; - break; - default: - Q_ASSERT(false); - pitch = 0; - }; - - alphaPenBlt(glyph->data, pitch, depth, - qFloor(positions[i].x + offs) + glyph->x, - qFloor(positions[i].y + offs) - glyph->y, - glyph->width, glyph->height); - } - if (lockedFace) - fe->unlockFace(); return; - #endif #endif @@ -3650,8 +3659,8 @@ void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount) int m11 = int(s->matrix.m11()); int m22 = int(s->matrix.m22()); - int dx = qFloor(s->matrix.dx() + aliasedCoordinateDelta); - int dy = qFloor(s->matrix.dy() + aliasedCoordinateDelta); + int dx = qFloor(s->matrix.dx()); + int dy = qFloor(s->matrix.dy()); for (int i=0; i<lineCount; ++i) { int dashOffset = int(s->lastPen.dashOffset()); if (s->flags.int_xform) { @@ -3762,7 +3771,7 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) for (int i=0; i<lineCount; ++i) { int dashOffset = int(s->lastPen.dashOffset()); - QLineF line = (lines[i] * s->matrix).translated(aliasedCoordinateDelta, aliasedCoordinateDelta); + QLineF line = lines[i] * s->matrix; const QRectF brect(QPointF(line.x1(), line.y1()), QPointF(line.x2(), line.y2())); ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); @@ -4296,11 +4305,19 @@ void QRasterPaintEnginePrivate::recalculateFastImages() QRasterPaintEngineState *s = q->state(); s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform) - && rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && s->matrix.type() <= QTransform::TxShear; } +bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const +{ + Q_Q(const QRasterPaintEngine); + const QRasterPaintEngineState *s = q->state(); + return s->flags.fast_images + && (mode == QPainter::CompositionMode_SourceOver + || (mode == QPainter::CompositionMode_Source + && !image.hasAlphaChannel())); +} QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color) { @@ -4627,38 +4644,40 @@ void QClipData::fixup() return; } -// qDebug("QClipData::fixup: count=%d",count); int y = -1; ymin = m_spans[0].y; ymax = m_spans[count-1].y + 1; xmin = INT_MAX; xmax = 0; + const int firstLeft = m_spans[0].x; + const int firstRight = m_spans[0].x + m_spans[0].len; bool isRect = true; - int left = m_spans[0].x; - int right = m_spans[0].x + m_spans[0].len; for (int i = 0; i < count; ++i) { - if (m_spans[i].y != y) { - if (m_spans[i].y != y + 1 && y != -1) { + QT_FT_Span_& span = m_spans[i]; + + if (span.y != y) { + if (span.y != y + 1 && y != -1) isRect = false; - } - y = m_spans[i].y; - m_clipLines[y].spans = m_spans+i; - m_clipLines[y].count = 0; -// qDebug() << " new line: y=" << y; - } - ++m_clipLines[y].count; - int sl = (int) m_spans[i].x; - int sr = sl + m_spans[i].len; + y = span.y; + m_clipLines[y].spans = &span; + m_clipLines[y].count = 1; + } else + ++m_clipLines[y].count; + + const int spanLeft = span.x; + const int spanRight = spanLeft + span.len; - xmin = qMin(xmin, (int)m_spans[i].x); - xmax = qMax(xmax, (int)m_spans[i].x + m_spans[i].len); + if (spanLeft < xmin) + xmin = spanLeft; - if (sl != left || sr != right) + if (spanRight > xmax) + xmax = spanRight; + + if (spanLeft != firstLeft || spanRight != firstRight) isRect = false; } -// qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d %s", xmin, xmax, ymin, ymax, isRect ? "rectangular" : ""); if (isRect) { hasRectClip = true; @@ -4994,8 +5013,8 @@ protected: int size, int opacity) const; uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) { if (cache.size() == maxCacheSize()) { - int elem_to_remove = qrand() % maxCacheSize(); - cache.remove(cache.keys()[elem_to_remove]); // may remove more than 1, but OK + // may remove more than 1, but OK + cache.erase(cache.begin() + (qrand() % maxCacheSize())); } CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode()); generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity); @@ -5014,6 +5033,84 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); + if (stopCount == 2) { + uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); + uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity); + + qreal first_stop = stops[0].first; + qreal second_stop = stops[1].first; + + if (second_stop < first_stop) { + qSwap(first_color, second_color); + qSwap(first_stop, second_stop); + } + + if (colorInterpolation) { + first_color = PREMUL(first_color); + second_color = PREMUL(second_color); + } + + int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1)); + int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1)); + + uint red_first = qRed(first_color) << 16; + uint green_first = qGreen(first_color) << 16; + uint blue_first = qBlue(first_color) << 16; + uint alpha_first = qAlpha(first_color) << 16; + + uint red_second = qRed(second_color) << 16; + uint green_second = qGreen(second_color) << 16; + uint blue_second = qBlue(second_color) << 16; + uint alpha_second = qAlpha(second_color) << 16; + + int i = 0; + for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) { + if (colorInterpolation) + colorTable[i] = first_color; + else + colorTable[i] = PREMUL(first_color); + } + + if (i < second_index) { + qreal reciprocal = qreal(1) / (second_index - first_index); + + int red_delta = qRound(int(red_second - red_first) * reciprocal); + int green_delta = qRound(int(green_second - green_first) * reciprocal); + int blue_delta = qRound(int(blue_second - blue_first) * reciprocal); + int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal); + + // rounding + red_first += 1 << 15; + green_first += 1 << 15; + blue_first += 1 << 15; + alpha_first += 1 << 15; + + for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) { + red_first += red_delta; + green_first += green_delta; + blue_first += blue_delta; + alpha_first += alpha_delta; + + const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000) + | ((green_first >> 8) & 0xff00) | (blue_first >> 16); + + if (colorInterpolation) + colorTable[i] = color; + else + colorTable[i] = PREMUL(color); + } + } + + for (; i < GRADIENT_STOPTABLE_SIZE; ++i) { + if (colorInterpolation) + colorTable[i] = second_color; + else + colorTable[i] = PREMUL(second_color); + } + + return; + } + uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); if (stopCount == 1) { current_color = PREMUL(current_color); @@ -5146,7 +5243,8 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode case Qt::SolidPattern: { type = Solid; QColor c = qbrush_color(brush); - solid.color = PREMUL(ARGB_COMBINE_ALPHA(c.rgba(), alpha)); + QRgb rgba = c.rgba(); + solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha)); if ((solid.color & 0xff000000) == 0 && compositionMode == QPainter::CompositionMode_SourceOver) { type = None; @@ -5184,10 +5282,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode QPointF center = g->center(); radialData.center.x = center.x(); radialData.center.y = center.y(); + radialData.center.radius = g->centerRadius(); QPointF focal = g->focalPoint(); radialData.focal.x = focal.x(); radialData.focal.y = focal.y(); - radialData.radius = g->radius(); + radialData.focal.radius = g->focalRadius(); } break; diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 6c2d28d..52f51fa 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -254,12 +254,14 @@ protected: QRasterPaintEngine(QRasterPaintEnginePrivate &d, QPaintDevice *); private: friend struct QSpanData; + friend class QBlitterPaintEngine; + friend class QBlitterPaintEnginePrivate; void init(); void fillRect(const QRectF &rect, QSpanData *data); void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); - void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, + bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine); #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) @@ -340,6 +342,7 @@ public: void initializeRasterizer(QSpanData *data); void recalculateFastImages(); + bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const; QPaintDevice *device; QScopedPointer<QOutlineMapper> outlineMapper; diff --git a/src/gui/painting/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp index 8b71b83..6ba9a99 100644 --- a/src/gui/painting/qpaintengine_x11.cpp +++ b/src/gui/painting/qpaintengine_x11.cpp @@ -1611,8 +1611,6 @@ void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int p && (fill.style() != Qt::NoBrush) && ((has_fill_texture && fill.texture().hasAlpha()) || antialias || !solid_fill || has_alpha_pen != has_alpha_brush)) { - QRect br = tessellator->tessellate((QPointF *)clippedPoints, clippedCount, - mode == QPaintEngine::WindingMode); if (tessellator->size > 0) { XRenderPictureAttributes attrs; attrs.poly_edge = antialias ? PolyEdgeSmooth : PolyEdgeSharp; @@ -1771,7 +1769,6 @@ void QX11PaintEngine::drawPath(const QPainterPath &path) Q_D(QX11PaintEngine); if (path.isEmpty()) return; - QTransform old_matrix = d->matrix; if (d->has_brush) d->fillPath(path, QX11PaintEnginePrivate::BrushGC, true); @@ -2385,7 +2382,7 @@ void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &ti) set = ft->loadTransformedGlyphSet(d->matrix); if (!set || set->outline_drawing - || !ft->loadGlyphs(set, glyphs.data(), glyphs.size(), QFontEngineFT::Format_Render)) + || !ft->loadGlyphs(set, glyphs.constData(), glyphs.size(), positions.constData(), QFontEngineFT::Format_Render)) { QPaintEngine::drawTextItem(p, ti); return; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 509fb77..7f601eb 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1012,4 +1012,50 @@ void QPaintEngineEx::updateState(const QPaintEngineState &) // do nothing... } +Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path) +{ + const qreal *points = path.points(); + const QPainterPath::ElementType *types = path.elements(); + + QPainterPath p; + if (types) { + int id = 0; + for (int i=0; i<path.elementCount(); ++i) { + switch(types[i]) { + case QPainterPath::MoveToElement: + p.moveTo(QPointF(points[id], points[id+1])); + id+=2; + break; + case QPainterPath::LineToElement: + p.lineTo(QPointF(points[id], points[id+1])); + id+=2; + break; + case QPainterPath::CurveToElement: { + QPointF p1(points[id], points[id+1]); + QPointF p2(points[id+2], points[id+3]); + QPointF p3(points[id+4], points[id+5]); + p.cubicTo(p1, p2, p3); + id+=6; + break; + } + case QPainterPath::CurveToDataElement: + ; + break; + } + } + } else { + p.moveTo(QPointF(points[0], points[1])); + int id = 2; + for (int i=1; i<path.elementCount(); ++i) { + p.lineTo(QPointF(points[id], points[id+1])); + id+=2; + } + } + if (path.hints() & QVectorPath::WindingFill) + p.setFillRule(Qt::WindingFill); + + return p; +} + + QT_END_NAMESPACE diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 3735e7c..9e28102 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -61,6 +61,8 @@ #include "qstyle.h" #include "qthread.h" #include "qvarlengtharray.h" +#include "qstatictext.h" +#include "qglyphs.h" #include <private/qfontengine_p.h> #include <private/qpaintengine_p.h> @@ -70,9 +72,10 @@ #include <private/qwidget_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qmath_p.h> -#include <qstatictext.h> #include <private/qstatictext_p.h> +#include <private/qglyphs_p.h> #include <private/qstylehelper_p.h> +#include <private/qrawfont_p.h> QT_BEGIN_NAMESPACE @@ -92,7 +95,7 @@ void qt_format_text(const QFont &font, QPainter *painter); static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextCharFormat::UnderlineStyle underlineStyle, - const QTextItem::RenderFlags flags, qreal width, + QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat); // Helper function to calculate left most position, width and flags for decoration drawing Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, @@ -149,6 +152,14 @@ static inline uint line_emulation(uint emulation) | QPaintEngine_OpaqueBackground); } +static bool qt_paintengine_supports_transformations(QPaintEngine::Type type) +{ + return type == QPaintEngine::OpenGL2 + || type == QPaintEngine::OpenVG + || type == QPaintEngine::OpenGL + || type == QPaintEngine::CoreGraphics; +} + #ifndef QT_NO_DEBUG static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false) { @@ -162,6 +173,10 @@ static bool qt_painter_thread_test(int devType, const char *what, bool extraCond #endif break; default: +#ifdef Q_WS_X11 + if (QApplication::testAttribute(Qt::AA_X11InitThreads)) + return true; +#endif if (!extraCondition && QThread::currentThread() != qApp->thread()) { qWarning("QPainter: It is not safe to use %s outside the GUI thread", what); return false; @@ -489,8 +504,12 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio q->save(); state->matrix = QTransform(); - state->dirtyFlags |= QPaintEngine::DirtyTransform; - updateState(state); + if (extended) { + extended->transformChanged(); + } else { + state->dirtyFlags |= QPaintEngine::DirtyTransform; + updateState(state); + } engine->drawImage(absPathRect, image, QRectF(0, 0, absPathRect.width(), absPathRect.height()), @@ -673,11 +692,14 @@ void QPainterPrivate::updateInvMatrix() invMatrix = state->matrix.inverted(); } +extern bool qt_isExtendedRadialGradient(const QBrush &brush); + void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) { bool alpha = false; bool linearGradient = false; bool radialGradient = false; + bool extendedRadialGradient = false; bool conicalGradient = false; bool patternBrush = false; bool xform = false; @@ -709,6 +731,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) (brushStyle == Qt::LinearGradientPattern)); radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) || (brushStyle == Qt::RadialGradientPattern)); + extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush)); conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) || (brushStyle == Qt::ConicalGradientPattern)); patternBrush = (((penBrushStyle > Qt::SolidPattern @@ -792,7 +815,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill; // Radial gradient emulation - if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)) + if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))) s->emulationSpecifier |= QPaintEngine::RadialGradientFill; else s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill; @@ -2701,6 +2724,63 @@ QPainterPath QPainter::clipPath() const } /*! + Returns the bounding rectangle of the current clip if there is a clip; + otherwise returns an empty rectangle. Note that the clip region is + given in logical coordinates. + + The bounding rectangle is not guaranteed to be tight. + + \sa setClipRect(), setClipPath(), setClipRegion() + + \since 4.8 + */ + +QRectF QPainter::clipBoundingRect() const +{ + Q_D(const QPainter); + + if (!d->engine) { + qWarning("QPainter::clipBoundingRect: Painter not active"); + return QRectF(); + } + + // Accumulate the bounding box in device space. This is not 100% + // precise, but it fits within the guarantee and it is resonably + // fast. + QRectF bounds; + for (int i=0; i<d->state->clipInfo.size(); ++i) { + QRectF r; + const QPainterClipInfo &info = d->state->clipInfo.at(i); + + if (info.clipType == QPainterClipInfo::RectClip) + r = info.rect; + else if (info.clipType == QPainterClipInfo::RectFClip) + r = info.rectf; + else if (info.clipType == QPainterClipInfo::RegionClip) + r = info.region.boundingRect(); + else + r = info.path.boundingRect(); + + r = info.matrix.mapRect(r); + + if (i == 0) + bounds = r; + else if (info.operation == Qt::IntersectClip) + bounds &= r; + else if (info.operation == Qt::UniteClip) + bounds |= r; + } + + + // Map the rectangle back into logical space using the inverse + // matrix. + if (!d->txinv) + const_cast<QPainter *>(this)->d_ptr->updateInvMatrix(); + + return d->invMatrix.mapRect(bounds); +} + +/*! \fn void QPainter::setClipRect(const QRectF &rectangle, Qt::ClipOperation operation) Enables clipping, and sets the clip region to the given \a @@ -5256,7 +5336,7 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawPixmap()", true); #endif if (d->extended) { @@ -5326,7 +5406,7 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) if (!d->engine || pm.isNull()) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawPixmap()", true); #endif qreal x = r.x(); @@ -5711,37 +5791,77 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags); } +/*! + Draws the glyphs represented by \a glyphs at \a position. The \a position gives the + edge of the baseline for the string of glyphs. The glyphs will be retrieved from the font + selected on \a glyphs and at offsets given by the positions in \a glyphs. + + \since 4.8 -void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray, - int glyphCount) + \sa QGlyphs::setFont(), QGlyphs::setPositions(), QGlyphs::setGlyphIndexes() +*/ +#if !defined(QT_NO_RAWFONT) +void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) { - QPainterPrivate *painter_d = QPainterPrivate::get(painter); - painter_d->drawGlyphs(glyphArray, positionArray, glyphCount); + Q_D(QPainter); + + QRawFont font = glyphs.font(); + if (!font.isValid()) + return; + + QVector<quint32> glyphIndexes = glyphs.glyphIndexes(); + QVector<QPointF> glyphPositions = glyphs.positions(); + + int count = qMin(glyphIndexes.size(), glyphPositions.size()); + QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count); + + bool paintEngineSupportsTransformations = + d->extended != 0 + ? qt_paintengine_supports_transformations(d->extended->type()) + : qt_paintengine_supports_transformations(d->engine->type()); + for (int i=0; i<count; ++i) { + QPointF processedPosition = position + glyphPositions.at(i); + if (!paintEngineSupportsTransformations) + processedPosition = d->state->transform().map(processedPosition); + fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition); + } + + d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphs.overline(), + glyphs.underline(), glyphs.strikeOut()); } -void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *positionArray, - int glyphCount) +void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount, + const QRawFont &font, bool overline, bool underline, + bool strikeOut) { + Q_Q(QPainter); + updateState(state); - QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common); + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + QFontEngine *fontEngine = fontD->fontEngine; - while (fontEngine->type() == QFontEngine::Multi) { - // Pick engine based on first glyph in array if we are using a multi engine. - // (all glyphs must be for same font) - int engineIdx = 0; - if (glyphCount > 0) - engineIdx = glyphArray[0] >> 24; + QFixed leftMost; + QFixed rightMost; + QFixed baseLine; + for (int i=0; i<glyphCount; ++i) { + glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]); + if (i == 0 || leftMost > positions[i].x) + leftMost = positions[i].x; - fontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); - } + // We don't support glyphs that do not share a common baseline. If this turns out to + // be a relevant use case, then we need to find clusters of glyphs that share a baseline + // and do a drawTextItemDecorations call per cluster. + if (i == 0 || baseLine < positions[i].y) + baseLine = positions[i].y; - QVarLengthArray<QFixedPoint, 128> positions; - for (int i=0; i<glyphCount; ++i) { - QFixedPoint fp = QFixedPoint::fromPointF(positionArray[i]); - positions.append(fp); + // We use the advance rather than the actual bounds to match the algorithm in drawText() + if (i == 0 || rightMost < positions[i].x + gm.xoff) + rightMost = positions[i].x + gm.xoff; } + QFixed width = rightMost - leftMost; + if (extended != 0) { QStaticTextItem staticTextItem; staticTextItem.color = state->pen.color(); @@ -5749,12 +5869,11 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *posit staticTextItem.setFontEngine(fontEngine); staticTextItem.numGlyphs = glyphCount; staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray)); - staticTextItem.glyphPositions = positions.data(); + staticTextItem.glyphPositions = positions; extended->drawStaticTextItem(&staticTextItem); } else { QTextItemInt textItem; - textItem.f = &state->font; textItem.fontEngine = fontEngine; QVarLengthArray<QFixed, 128> advances(glyphCount); @@ -5766,7 +5885,7 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *posit textItem.glyphs.numGlyphs = glyphCount; textItem.glyphs.glyphs = reinterpret_cast<HB_Glyph *>(const_cast<quint32 *>(glyphArray)); - textItem.glyphs.offsets = positions.data(); + textItem.glyphs.offsets = positions; textItem.glyphs.advances_x = advances.data(); textItem.glyphs.advances_y = advances.data(); textItem.glyphs.justifications = glyphJustifications.data(); @@ -5774,7 +5893,23 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *posit engine->drawTextItem(QPointF(0, 0), textItem); } + + QTextItemInt::RenderFlags flags; + if (underline) + flags |= QTextItemInt::Underline; + if (overline) + flags |= QTextItemInt::Overline; + if (strikeOut) + flags |= QTextItemInt::StrikeOut; + + drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()), + fontEngine, + (underline + ? QTextCharFormat::SingleUnderline + : QTextCharFormat::NoUnderline), + flags, width.toReal(), QTextCharFormat()); } +#endif // QT_NO_RAWFONT /*! @@ -5862,10 +5997,7 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText return; } - bool paintEngineSupportsTransformations = d->extended->type() == QPaintEngine::OpenGL2 - || d->extended->type() == QPaintEngine::OpenVG - || d->extended->type() == QPaintEngine::OpenGL; - + bool paintEngineSupportsTransformations = qt_paintengine_supports_transformations(d->extended->type()); if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) { staticText_d->untransformedCoordinates = true; staticText_d->needsRelayout = true; @@ -6309,7 +6441,7 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextCharFormat::UnderlineStyle underlineStyle, - const QTextItem::RenderFlags flags, qreal width, + QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat) { if (underlineStyle == QTextCharFormat::NoUnderline @@ -6324,12 +6456,13 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const pen.setWidthF(fe->lineThickness().toReal()); pen.setCapStyle(Qt::FlatCap); - QLineF line(pos.x(), pos.y(), pos.x() + width, pos.y()); + QLineF line(pos.x(), pos.y(), pos.x() + qFloor(width), pos.y()); const qreal underlineOffset = fe->underlinePosition().toReal(); // deliberately ceil the offset to avoid the underline coming too close to // the text above it. - const qreal underlinePos = pos.y() + qCeil(underlineOffset); + const qreal aliasedCoordinateDelta = 0.5 - 0.015625; + const qreal underlinePos = pos.y() + qCeil(underlineOffset) - aliasedCoordinateDelta; if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle)); @@ -6697,7 +6830,7 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()"); + qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()", true); #endif qreal sw = pixmap.width(); @@ -7877,7 +8010,7 @@ void qt_format_text(const QFont &fnt, const QRectF &_r, } void qt_format_text(const QFont &fnt, const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect, - int tabstops, int *, int tabarraylen, + int tabstops, int *ta, int tabarraylen, QPainter *painter) { @@ -7997,6 +8130,16 @@ start_lengthVariant: engine.option = *option; } + if (engine.option.tabStop() < 0 && tabstops > 0) + engine.option.setTabStop(tabstops); + + if (engine.option.tabs().isEmpty() && ta) { + QList<qreal> tabs; + for (int i = 0; i < tabarraylen; i++) + tabs.append(qreal(ta[i])); + engine.option.setTabArray(tabs); + } + engine.option.setTextDirection(layout_direction); if (tf & Qt::AlignJustify) engine.option.setAlignment(Qt::AlignJustify); diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 0d7829e..1a432e6 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -79,6 +79,7 @@ class QTextItem; class QMatrix; class QTransform; class QStaticText; +class QGlyphs; class QPainterPrivateDeleter; @@ -221,6 +222,8 @@ public: void setClipping(bool enable); bool hasClipping() const; + QRectF clipBoundingRect() const; + void save(); void restore(); @@ -396,6 +399,10 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; +#if !defined(QT_NO_RAWFONT) + void drawGlyphs(const QPointF &position, const QGlyphs &glyphs); +#endif + void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText); inline void drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText); inline void drawStaticText(int left, int top, const QStaticText &staticText); @@ -546,6 +553,7 @@ private: friend class QPaintEngine; friend class QPaintEngineExPrivate; friend class QOpenGLPaintEngine; + friend class QVGPaintEngine; friend class QX11PaintEngine; friend class QX11PaintEnginePrivate; friend class QWin32PaintEngine; diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 0e0c11f..205c10a 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -70,6 +70,7 @@ QT_BEGIN_NAMESPACE class QPaintEngine; class QEmulationPaintEngine; class QPaintEngineEx; +struct QFixedPoint; struct QTLWExtra; @@ -183,6 +184,7 @@ struct QPainterDummyState QTransform transform; }; +class QRawFont; class QPainterPrivate { Q_DECLARE_PUBLIC(QPainter) @@ -228,7 +230,12 @@ public: void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw); void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); - void drawGlyphs(const quint32 *glyphArray, const QPointF *positionArray, int glyphCount); + +#if !defined(QT_NO_RAWFONT) + void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, + const QRawFont &font, bool overline = false, bool underline = false, + bool strikeOut = false); +#endif void updateMatrix(); void updateInvMatrix(); @@ -258,8 +265,6 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); -Q_GUI_EXPORT void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, - const QPointF *positionArray, int glyphCount); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 4744cb5..9fbac13 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -576,6 +576,14 @@ QPainterPath &QPainterPath::operator=(const QPainterPath &other) } /*! + \fn void QPainterPath::swap(QPainterPath &other) + \since 4.8 + + Swaps painter path \a other with this painter path. This operation is very + fast and never fails. +*/ + +/*! Destroys this QPainterPath object. */ QPainterPath::~QPainterPath() @@ -866,7 +874,7 @@ void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength); #endif - if (!qt_is_finite(rect.x()) && !qt_is_finite(rect.y()) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height()) + if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height()) || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) { #ifndef QT_NO_DEBUG qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call"); @@ -1118,6 +1126,7 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString & QTextEngine *eng = layout.engine(); layout.beginLayout(); QTextLine line = layout.createLine(); + Q_UNUSED(line); layout.endLayout(); const QScriptLine &sl = eng->lines[0]; if (!sl.length || !eng->layoutData) @@ -1896,7 +1905,7 @@ static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, if (y >= bounds.top() && y < bounds.bottom() && bounds.right() >= x1 && bounds.left() < x2) { const qreal lower_bound = qreal(.01); - if (depth == 32 || bounds.width() < lower_bound && bounds.height() < lower_bound) + if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) return true; QBezier first_half, second_half; @@ -1915,7 +1924,7 @@ static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qr if (x >= bounds.left() && x < bounds.right() && bounds.bottom() >= y1 && bounds.top() < y2) { const qreal lower_bound = qreal(.01); - if (depth == 32 || bounds.width() < lower_bound && bounds.height() < lower_bound) + if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) return true; QBezier first_half, second_half; @@ -2915,9 +2924,12 @@ QPointF QPainterPath::pointAtPercent(qreal t) const return QPointF(); } - if (isEmpty()) + if (!d_ptr || d_ptr->elements.size() == 0) return QPointF(); + if (d_ptr->elements.size() == 1) + return d_ptr->elements.at(0); + qreal totalLength = length(); qreal curLen = 0; qreal bezierLen = 0; diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index 4d166af..3c23282 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -95,7 +95,12 @@ public: explicit QPainterPath(const QPointF &startPoint); QPainterPath(const QPainterPath &other); QPainterPath &operator=(const QPainterPath &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QPainterPath &operator=(QPainterPath &&other) + { qSwap(d_ptr, other.d_ptr); return *this; } +#endif ~QPainterPath(); + inline void swap(QPainterPath &other) { d_ptr.swap(other.d_ptr); } void closeSubpath(); diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 4e8408b..0271a39 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -47,6 +47,7 @@ #include "private/qcups_p.h" #include "qprinterinfo.h" #include <qnumeric.h> +#include "private/qfont_p.h" #ifdef Q_OS_UNIX #include "private/qcore_unix_p.h" // overrides QT_OPEN @@ -54,8 +55,6 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT extern int qt_defaultDpi(); - #ifndef QT_NO_PRINTER extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size); @@ -915,7 +914,6 @@ const char *QPdf::paperSizeToString(QPrinter::PaperSize paperSize) return psToStr[paperSize]; } - // -------------------------- base engine, shared code between PS and PDF ----------------------- QPdfBaseEngine::QPdfBaseEngine(QPdfBaseEnginePrivate &dd, PaintEngineFeatures f) @@ -1157,6 +1155,8 @@ void QPdfBaseEngine::updateState(const QPaintEngineState &state) } if (flags & DirtyBrush) { d->brush = state.brush(); + if (d->brush.color().alpha() == 0 && d->brush.style() == Qt::SolidPattern) + d->brush.setStyle(Qt::NoBrush); d->hasBrush = d->brush.style() != Qt::NoBrush; } if (flags & DirtyBrushOrigin) { diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index 08f9504..b69458d 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -383,6 +383,14 @@ QPen &QPen::operator=(const QPen &p) } /*! + \fn void QPen::swap(QPen &other) + \since 4.8 + + Swaps pen \a other with this pen. This operation is very + fast and never fails. +*/ + +/*! Returns the pen as a QVariant. */ QPen::operator QVariant() const diff --git a/src/gui/painting/qpen.h b/src/gui/painting/qpen.h index 4298f81..001cd44 100644 --- a/src/gui/painting/qpen.h +++ b/src/gui/painting/qpen.h @@ -74,6 +74,11 @@ public: ~QPen(); QPen &operator=(const QPen &pen); +#ifdef Q_COMPILER_RVALUE_REFS + inline QPen &operator=(QPen &&other) + { qSwap(d, other.d); return *this; } +#endif + inline void swap(QPen &other) { qSwap(d, other.d); } Qt::PenStyle style() const; void setStyle(Qt::PenStyle); diff --git a/src/gui/painting/qpolygon.cpp b/src/gui/painting/qpolygon.cpp index 0cf2ef5..41b686a 100644 --- a/src/gui/painting/qpolygon.cpp +++ b/src/gui/painting/qpolygon.cpp @@ -700,6 +700,22 @@ QPolygon QPolygonF::toPolygon() const } /*! + \fn void QPolygon::swap(QPolygon &other) + \since 4.8 + + Swaps polygon \a other with this polygon. This operation is very + fast and never fails. +*/ + +/*! + \fn void QPolygonF::swap(QPolygonF &other) + \since 4.8 + + Swaps polygon \a other with this polygon. This operation is very + fast and never fails. +*/ + +/*! Returns the polygon as a QVariant */ QPolygon::operator QVariant() const diff --git a/src/gui/painting/qpolygon.h b/src/gui/painting/qpolygon.h index b89b2a5..0f4a8b3 100644 --- a/src/gui/painting/qpolygon.h +++ b/src/gui/painting/qpolygon.h @@ -67,6 +67,8 @@ public: inline QPolygon(const QVector<QPoint> &v) : QVector<QPoint>(v) {} QPolygon(const QRect &r, bool closed=false); QPolygon(int nPoints, const int *points); + inline void swap(QPolygon &other) { QVector<QPoint>::swap(other); } // prevent QVector<QPoint><->QPolygon swaps + operator QVariant() const; void translate(int dx, int dy); @@ -139,6 +141,7 @@ public: inline QPolygonF(const QVector<QPointF> &v) : QVector<QPointF>(v) {} QPolygonF(const QRectF &r); QPolygonF(const QPolygon &a); + inline void swap(QPolygonF &other) { QVector<QPointF>::swap(other); } // prevent QVector<QPointF><->QPolygonF swaps inline void translate(qreal dx, qreal dy); void translate(const QPointF &offset); diff --git a/src/gui/painting/qprintengine_mac.mm b/src/gui/painting/qprintengine_mac.mm index ec842a9..1dce303 100644 --- a/src/gui/painting/qprintengine_mac.mm +++ b/src/gui/painting/qprintengine_mac.mm @@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size); -extern int qt_defaultDpi(); QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode) : QPaintEngine(*(new QMacPrintEnginePrivate)) { diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp index f262144..353869f 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -534,7 +534,10 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n QImage image = img; QImage::Format format = image.format(); - if (image.depth() == 1 && *bitmap && img.colorTable().size() == 0) { + if (image.depth() == 1 && *bitmap && img.colorTable().size() == 2 + && img.colorTable().at(0) == QColor(Qt::black).rgba() + && img.colorTable().at(1) == QColor(Qt::white).rgba()) + { if (format == QImage::Format_MonoLSB) image = image.convertToFormat(QImage::Format_Mono); format = QImage::Format_Mono; @@ -936,7 +939,7 @@ void QPdfEnginePrivate::writeInfo() xprintf("\n/Creator "); printString(creator); xprintf("\n/Producer "); - printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2010 Nokia Corporation and/or its subsidiary(-ies)")); + printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2011 Nokia Corporation and/or its subsidiary(-ies)")); QDateTime now = QDateTime::currentDateTime().toUTC(); QTime t = now.time(); QDate d = now.date(); diff --git a/src/gui/painting/qprinterinfo.qdoc b/src/gui/painting/qprinterinfo.cpp index c3c0f83..f680ce1 100644 --- a/src/gui/painting/qprinterinfo.qdoc +++ b/src/gui/painting/qprinterinfo.cpp @@ -25,6 +25,16 @@ ** ****************************************************************************/ +#include "qprinterinfo.h" +#include "qprinterinfo_p.h" + +#ifndef QT_NO_PRINTER + +QT_BEGIN_NAMESPACE + +QPrinterInfoPrivate QPrinterInfoPrivate::shared_null; + + /*! \class QPrinterInfo @@ -59,60 +69,94 @@ */ /*! - \fn QPrinterInfo::QPrinterInfo() - Constructs an empty QPrinterInfo object. \sa isNull() */ +QPrinterInfo::QPrinterInfo() + : d_ptr(&QPrinterInfoPrivate::shared_null) +{ +} /*! - \fn QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) - - Constructs a copy of \a src. + Constructs a copy of \a other. */ +QPrinterInfo::QPrinterInfo(const QPrinterInfo &other) + : d_ptr(new QPrinterInfoPrivate(*other.d_ptr)) +{ +} /*! - \fn QPrinterInfo::QPrinterInfo(const QPrinter& printer) - Constructs a QPrinterInfo object from \a printer. */ +QPrinterInfo::QPrinterInfo(const QPrinter &printer) + : d_ptr(&QPrinterInfoPrivate::shared_null) +{ + foreach (const QPrinterInfo &printerInfo, availablePrinters()) { + if (printerInfo.printerName() == printer.printerName()) { + d_ptr.reset(new QPrinterInfoPrivate(*printerInfo.d_ptr)); + break; + } + } +} /*! - \fn QPrinterInfo::~QPrinterInfo() + \internal +*/ +QPrinterInfo::QPrinterInfo(const QString &name) + : d_ptr(new QPrinterInfoPrivate(name)) +{ +} +/*! Destroys the QPrinterInfo object. References to the values in the object become invalid. */ +QPrinterInfo::~QPrinterInfo() +{ +} /*! - \fn QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) - - Sets the QPrinterInfo object to be equal to \a src. + Sets the QPrinterInfo object to be equal to \a other. */ +QPrinterInfo &QPrinterInfo::operator=(const QPrinterInfo &other) +{ + Q_ASSERT(d_ptr); + d_ptr.reset(new QPrinterInfoPrivate(*other.d_ptr)); + return *this; +} /*! - \fn QString QPrinterInfo::printerName() const - Returns the name of the printer. \sa QPrinter::setPrinterName() */ +QString QPrinterInfo::printerName() const +{ + const Q_D(QPrinterInfo); + return d->name; +} /*! - \fn bool QPrinterInfo::isNull() const - Returns whether this QPrinterInfo object holds a printer definition. An empty QPrinterInfo object could result for example from calling defaultPrinter() when there are no printers on the system. */ +bool QPrinterInfo::isNull() const +{ + const Q_D(QPrinterInfo); + return d == &QPrinterInfoPrivate::shared_null; +} /*! - \fn bool QPrinterInfo::isDefault() const - Returns whether this printer is the default printer. */ +bool QPrinterInfo::isDefault() const +{ + const Q_D(QPrinterInfo); + return d->isDefault; +} /*! \fn QList< QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const @@ -123,3 +167,7 @@ Not all printer drivers support this query, so the list may be empty. On Mac OS X 10.3, this function always returns an empty list. */ + +QT_END_NAMESPACE + +#endif // QT_NO_PRINTER diff --git a/src/gui/painting/qprinterinfo.h b/src/gui/painting/qprinterinfo.h index 2ac07a8..3437961 100644 --- a/src/gui/painting/qprinterinfo.h +++ b/src/gui/painting/qprinterinfo.h @@ -42,9 +42,10 @@ #ifndef QPRINTERINFO_H #define QPRINTERINFO_H -#include <QtGui/QPrinter> #include <QtCore/QList> +#include <QtGui/QPrinter> + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -56,15 +57,13 @@ class QPrinterInfoPrivate; class QPrinterInfoPrivateDeleter; class Q_GUI_EXPORT QPrinterInfo { -Q_DECLARE_PRIVATE(QPrinterInfo) - public: QPrinterInfo(); - QPrinterInfo(const QPrinterInfo& src); - QPrinterInfo(const QPrinter& printer); + QPrinterInfo(const QPrinterInfo &other); + QPrinterInfo(const QPrinter &printer); ~QPrinterInfo(); - QPrinterInfo& operator=(const QPrinterInfo& src); + QPrinterInfo &operator=(const QPrinterInfo &other); QString printerName() const; bool isNull() const; @@ -75,8 +74,10 @@ public: static QPrinterInfo defaultPrinter(); private: - QPrinterInfo(const QString& name); + QPrinterInfo(const QString &name); +private: + Q_DECLARE_PRIVATE(QPrinterInfo) QScopedPointer<QPrinterInfoPrivate, QPrinterInfoPrivateDeleter> d_ptr; }; diff --git a/src/gui/painting/qprinterinfo_mac.cpp b/src/gui/painting/qprinterinfo_mac.cpp index bafe2b2..b24ab70 100644 --- a/src/gui/painting/qprinterinfo_mac.cpp +++ b/src/gui/painting/qprinterinfo_mac.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qprinterinfo.h" +#include "qprinterinfo_p.h" #include "private/qt_mac_p.h" @@ -47,189 +48,71 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_PRINTER -class QPrinterInfoPrivate -{ -Q_DECLARE_PUBLIC(QPrinterInfo) -public: - ~QPrinterInfoPrivate(); - QPrinterInfoPrivate(); - QPrinterInfoPrivate(const QString& name); - -private: - QPrinterInfo* q_ptr; - - QString m_name; - bool m_default; - bool m_isNull; -}; - -static QPrinterInfoPrivate nullQPrinterInfoPrivate; - -class QPrinterInfoPrivateDeleter -{ -public: - static inline void cleanup(QPrinterInfoPrivate *d) - { - if (d != &nullQPrinterInfoPrivate) - delete d; - } -}; - -extern QPrinter::PaperSize qSizeFTopaperSize(const QSizeF& size); - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// +extern QPrinter::PaperSize qSizeFTopaperSize(const QSizeF &size); QList<QPrinterInfo> QPrinterInfo::availablePrinters() { QList<QPrinterInfo> printers; - OSStatus status = noErr; - QCFType<CFArrayRef> printerList; - status = PMServerCreatePrinterList(kPMServerLocal, &printerList); - if (status == noErr) { - CFIndex count = CFArrayGetCount(printerList); - for (CFIndex i=0; i<count; ++i) { - PMPrinter printer = static_cast<PMPrinter>(const_cast<void *>(CFArrayGetValueAtIndex(printerList, i))); - QString name = QCFString::toQString(PMPrinterGetName(printer)); - printers.append(QPrinterInfo(name)); - if (PMPrinterIsDefault(printer)) { - printers[i].d_ptr->m_default = true; - } + QCFType<CFArrayRef> array; + if (PMServerCreatePrinterList(kPMServerLocal, &array) == noErr) { + CFIndex count = CFArrayGetCount(array); + for (int i = 0; i < count; ++i) { + PMPrinter printer = static_cast<PMPrinter>(const_cast<void *>(CFArrayGetValueAtIndex(array, i))); + QString printerName = QCFString::toQString(PMPrinterGetName(printer)); + + QPrinterInfo printerInfo(printerName); + if (PMPrinterIsDefault(printer)) + printerInfo.d_ptr->isDefault = true; + printers.append(printerInfo); } } return printers; } -QPrinterInfo QPrinterInfo::defaultPrinter(){ - QList<QPrinterInfo> printers = availablePrinters(); - for (int c = 0; c < printers.size(); ++c) { - if (printers[c].isDefault()) { - return printers[c]; - } - } - return QPrinterInfo(); -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -QPrinterInfo::QPrinterInfo(const QPrinter& prn) - : d_ptr(&nullQPrinterInfoPrivate) +QPrinterInfo QPrinterInfo::defaultPrinter() { - QList<QPrinterInfo> list = availablePrinters(); - for (int c = 0; c < list.size(); ++c) { - if (prn.printerName() == list[c].printerName()) { - *this = list[c]; - return; - } + QList<QPrinterInfo> printers = availablePrinters(); + foreach (const QPrinterInfo &printerInfo, printers) { + if (printerInfo.isDefault()) + return printerInfo; } -} - -QPrinterInfo::~QPrinterInfo() -{ -} - -QPrinterInfo::QPrinterInfo() - : d_ptr(&nullQPrinterInfoPrivate) -{ -} - -QPrinterInfo::QPrinterInfo(const QString& name) - : d_ptr(new QPrinterInfoPrivate(name)) -{ - d_ptr->q_ptr = this; -} - -QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) - : d_ptr(&nullQPrinterInfoPrivate) -{ - *this = src; -} - -QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) -{ - Q_ASSERT(d_ptr); - d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr)); - d_ptr->q_ptr = this; - return *this; -} - -QString QPrinterInfo::printerName() const -{ - const Q_D(QPrinterInfo); - return d->m_name; -} -bool QPrinterInfo::isNull() const -{ - const Q_D(QPrinterInfo); - return d->m_isNull; -} - -bool QPrinterInfo::isDefault() const -{ - const Q_D(QPrinterInfo); - return d->m_default; + return printers.value(0); } QList<QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const { const Q_D(QPrinterInfo); - PMPrinter cfPrn = PMPrinterCreateFromPrinterID(QCFString::toCFStringRef(d->m_name)); + QList<QPrinter::PaperSize> paperSizes; + if (isNull()) + return paperSizes; - if (!cfPrn) return QList<QPrinter::PaperSize>(); + PMPrinter cfPrn = PMPrinterCreateFromPrinterID(QCFString::toCFStringRef(d->name)); + if (!cfPrn) + return paperSizes; CFArrayRef array; - OSStatus status = PMPrinterGetPaperList(cfPrn, &array); - - if (status != 0) { + if (PMPrinterGetPaperList(cfPrn, &array) != noErr) { PMRelease(cfPrn); - return QList<QPrinter::PaperSize>(); + return paperSizes; } - QList<QPrinter::PaperSize> paperList; int count = CFArrayGetCount(array); - for (int c = 0; c < count; c++) { - PMPaper paper = static_cast<PMPaper>( - const_cast<void*>( - CFArrayGetValueAtIndex(array, c))); + for (int i = 0; i < count; ++i) { + PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(array, i))); double width, height; - status = PMPaperGetWidth(paper, &width); - status |= PMPaperGetHeight(paper, &height); - if (status != 0) continue; - - QSizeF size(width * 0.3527, height * 0.3527); - paperList.append(qSizeFTopaperSize(size)); + if (PMPaperGetWidth(paper, &width) == noErr && PMPaperGetHeight(paper, &height) == noErr) { + QSizeF size(width * 0.3527, height * 0.3527); + paperSizes.append(qSizeFTopaperSize(size)); + } } PMRelease(cfPrn); - return paperList; -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -QPrinterInfoPrivate::QPrinterInfoPrivate() : - q_ptr(NULL), - m_default(false), - m_isNull(true) -{ -} - -QPrinterInfoPrivate::QPrinterInfoPrivate(const QString& name) : - q_ptr(NULL), - m_name(name), - m_default(false), - m_isNull(false) -{ -} - -QPrinterInfoPrivate::~QPrinterInfoPrivate() -{ + return paperSizes; } #endif // QT_NO_PRINTER diff --git a/src/gui/painting/qprinterinfo_p.h b/src/gui/painting/qprinterinfo_p.h new file mode 100644 index 0000000..fcc1acb --- /dev/null +++ b/src/gui/painting/qprinterinfo_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPRINTERINFO_P_H +#define QPRINTERINFO_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qglobal.h" + +#ifndef QT_NO_PRINTER + +#include "QtCore/qlist.h" + +QT_BEGIN_NAMESPACE + +class QPrinterInfoPrivate +{ +public: + QPrinterInfoPrivate(const QString& name = QString()) : + name(name), isDefault(false) +#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)) || defined(Q_WS_QPA) +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + , cupsPrinterIndex(0), hasPaperSizes(false) +#endif +#endif + {} + ~QPrinterInfoPrivate() + {} + + static QPrinterInfoPrivate shared_null; + + QString name; + bool isDefault; + +#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)) || defined(Q_WS_QPA) +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + int cupsPrinterIndex; + mutable bool hasPaperSizes; + mutable QList<QPrinter::PaperSize> paperSizes; +#endif +#endif +}; + + +class QPrinterInfoPrivateDeleter +{ +public: + static inline void cleanup(QPrinterInfoPrivate *d) + { + if (d != &QPrinterInfoPrivate::shared_null) + delete d; + } +}; + +QT_END_NAMESPACE + +#endif // QT_NO_PRINTER + +#endif // QPRINTERINFO_P_H diff --git a/src/gui/painting/qprinterinfo_unix.cpp b/src/gui/painting/qprinterinfo_unix.cpp index ed8ce80..38e9590 100644 --- a/src/gui/painting/qprinterinfo_unix.cpp +++ b/src/gui/painting/qprinterinfo_unix.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qprinterinfo.h" +#include "qprinterinfo_p.h" #include <qfile.h> #include <qfileinfo.h> @@ -60,42 +61,66 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_PRINTER -class QPrinterInfoPrivate -{ -Q_DECLARE_PUBLIC(QPrinterInfo) -public: - QPrinterInfoPrivate(); - QPrinterInfoPrivate(const QString& name); - ~QPrinterInfoPrivate(); - - static QPrinter::PaperSize string2PaperSize(const QString& str); - static QString pageSize2String(QPrinter::PaperSize size); - -private: - QString m_name; - bool m_isNull; - bool m_default; - mutable bool m_mustGetPaperSizes; - mutable QList<QPrinter::PaperSize> m_paperSizes; - int m_cupsPrinterIndex; - - QPrinterInfo* q_ptr; +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) +// preserver names in ascending order for the binary search +static const struct NamedPaperSize { + const char *const name; + QPrinter::PaperSize size; +} named_sizes_map[QPrinter::NPageSize] = { + { "A0", QPrinter::A0 }, + { "A1", QPrinter::A1 }, + { "A2", QPrinter::A2 }, + { "A3", QPrinter::A3 }, + { "A4", QPrinter::A4 }, + { "A5", QPrinter::A5 }, + { "A6", QPrinter::A6 }, + { "A7", QPrinter::A7 }, + { "A8", QPrinter::A8 }, + { "A9", QPrinter::A9 }, + { "B0", QPrinter::B0 }, + { "B1", QPrinter::B1 }, + { "B10", QPrinter::B10 }, + { "B2", QPrinter::B2 }, + { "B4", QPrinter::B4 }, + { "B5", QPrinter::B5 }, + { "B6", QPrinter::B6 }, + { "B7", QPrinter::B7 }, + { "B8", QPrinter::B8 }, + { "B9", QPrinter::B9 }, + { "C5E", QPrinter::C5E }, + { "Comm10E", QPrinter::Comm10E }, + { "Custom", QPrinter::Custom }, + { "DLE", QPrinter::DLE }, + { "Executive", QPrinter::Executive }, + { "Folio", QPrinter::Folio }, + { "Ledger", QPrinter::Ledger }, + { "Legal", QPrinter::Legal }, + { "Letter", QPrinter::Letter }, + { "Tabloid", QPrinter::Tabloid } }; -static QPrinterInfoPrivate nullQPrinterInfoPrivate; +inline bool operator<(const char *name, const NamedPaperSize &data) +{ return qstrcmp(name, data.name) < 0; } +inline bool operator<(const NamedPaperSize &data, const char *name) +{ return qstrcmp(data.name, name) < 0; } -class QPrinterInfoPrivateDeleter +static inline QPrinter::PaperSize string2PaperSize(const char *name) { -public: - static inline void cleanup(QPrinterInfoPrivate *d) - { - if (d != &nullQPrinterInfoPrivate) - delete d; - } -}; + const NamedPaperSize *r = qBinaryFind(named_sizes_map, named_sizes_map + QPrinter::NPageSize, name); + if (r - named_sizes_map != QPrinter::NPageSize) + return r->size; + return QPrinter::Custom; +} -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// +static inline const char *paperSize2String(QPrinter::PaperSize size) +{ + for (int i = 0; i < QPrinter::NPageSize; ++i) { + if (size == named_sizes_map[i].size) + return named_sizes_map[i].name; + } + return 0; +} +#endif void qt_perhapsAddPrinter(QList<QPrinterDescription> *printers, const QString &name, QString host, QString comment, @@ -784,12 +809,12 @@ int qt_getLprPrinters(QList<QPrinterDescription>& printers) #endif } + QRegExp ps(QLatin1String("[^a-z]ps(?:[^a-z]|$)")); + QRegExp lp(QLatin1String("[^a-z]lp(?:[^a-z]|$)")); + int quality = 0; int best = 0; for (int i = 0; i < printers.size(); ++i) { - QRegExp ps(QLatin1String("[^a-z]ps(?:[^a-z]|$)")); - QRegExp lp(QLatin1String("[^a-z]lp(?:[^a-z]|$)")); - QString name = printers.at(i).name; QString comment = printers.at(i).comment; if (quality < 5 && name == dollarPrinter) { @@ -824,331 +849,77 @@ int qt_getLprPrinters(QList<QPrinterDescription>& printers) QList<QPrinterInfo> QPrinterInfo::availablePrinters() { - QList<QPrinterInfo> list; + QList<QPrinterInfo> printers; #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) - QCUPSSupport cups; if (QCUPSSupport::isAvailable()) { - //const ppd_file_t* cupsPPD = cups.currentPPD(); + QCUPSSupport cups; int cupsPrinterCount = cups.availablePrintersCount(); const cups_dest_t* cupsPrinters = cups.availablePrinters(); - for (int i = 0; i < cupsPrinterCount; ++i) { QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name)); if (cupsPrinters[i].instance) printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance); - list.append(QPrinterInfo(printerName)); + + QPrinterInfo printerInfo(printerName); if (cupsPrinters[i].is_default) - list[i].d_ptr->m_default = true; - list[i].d_ptr->m_cupsPrinterIndex = i; + printerInfo.d_ptr->isDefault = true; + printerInfo.d_ptr->cupsPrinterIndex = i; + printers.append(printerInfo); } - } else { + } else #endif + { QList<QPrinterDescription> lprPrinters; int defprn = qt_getLprPrinters(lprPrinters); // populating printer combo - QList<QPrinterDescription>::const_iterator i = lprPrinters.constBegin(); - for(; i != lprPrinters.constEnd(); ++i) { - list.append(QPrinterInfo((*i).name)); - } - if (defprn >= 0 && defprn < lprPrinters.size()) { - list[defprn].d_ptr->m_default = true; - } -#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + foreach (const QPrinterDescription &description, lprPrinters) + printers.append(QPrinterInfo(description.name)); + if (defprn >= 0 && defprn < printers.size()) + printers[defprn].d_ptr->isDefault = true; } -#endif - return list; + return printers; } QPrinterInfo QPrinterInfo::defaultPrinter() { - QList<QPrinterInfo> prnList = availablePrinters(); - for (int i = 0; i < prnList.size(); ++i) { - if (prnList[i].isDefault()) - return prnList[i]; + QList<QPrinterInfo> printers = availablePrinters(); + foreach (const QPrinterInfo &printerInfo, printers) { + if (printerInfo.isDefault()) + return printerInfo; } - return (prnList.size() > 0) ? prnList[0] : QPrinterInfo(); -} - -QPrinterInfo::QPrinterInfo() - : d_ptr(&nullQPrinterInfoPrivate) -{ -} -QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) - : d_ptr(&nullQPrinterInfoPrivate) -{ - *this = src; + return printers.value(0); } -QPrinterInfo::QPrinterInfo(const QPrinter& printer) - : d_ptr(new QPrinterInfoPrivate(printer.printerName())) +QList<QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const { - - Q_D(QPrinterInfo); - d->q_ptr = this; - #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) - QCUPSSupport cups; - if (QCUPSSupport::isAvailable()) { - int cupsPrinterCount = cups.availablePrintersCount(); - const cups_dest_t* cupsPrinters = cups.availablePrinters(); - - for (int i = 0; i < cupsPrinterCount; ++i) { - QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name)); - if (cupsPrinters[i].instance) - printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance); - if (printerName == printer.printerName()) { - if (cupsPrinters[i].is_default) - d->m_default = true; - d->m_cupsPrinterIndex = i; - return; - } - } - } else { -#endif - QList<QPrinterDescription> lprPrinters; - int defprn = qt_getLprPrinters(lprPrinters); - // populating printer combo - QList<QPrinterDescription>::const_iterator i = lprPrinters.constBegin(); - int c; - for(c = 0; i != lprPrinters.constEnd(); ++i, ++c) { - if (i->name == printer.printerName()) { - if (defprn == c) - d->m_default = true; - return; - } - } -#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) - } -#endif - - // Printer not found. - d_ptr.reset(&nullQPrinterInfoPrivate); -} - -QPrinterInfo::QPrinterInfo(const QString& name) - : d_ptr(new QPrinterInfoPrivate(name)) -{ - d_ptr->q_ptr = this; -} - -QPrinterInfo::~QPrinterInfo() -{ -} - -QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) -{ - Q_ASSERT(d_ptr); - d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr)); - d_ptr->q_ptr = this; - return *this; -} - -QString QPrinterInfo::printerName() const -{ const Q_D(QPrinterInfo); - return d->m_name; -} - -bool QPrinterInfo::isNull() const -{ - const Q_D(QPrinterInfo); - return d->m_isNull; -} -bool QPrinterInfo::isDefault() const -{ - const Q_D(QPrinterInfo); - return d->m_default; -} + if (isNull()) + return d->paperSizes; -QList< QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const -{ - const Q_D(QPrinterInfo); - if (d->m_mustGetPaperSizes) { - d->m_mustGetPaperSizes = false; + if (!d->hasPaperSizes) { + d->hasPaperSizes = true; -#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) - QCUPSSupport cups; if (QCUPSSupport::isAvailable()) { // Find paper sizes from CUPS. - cups.setCurrentPrinter(d->m_cupsPrinterIndex); + QCUPSSupport cups; + cups.setCurrentPrinter(d->cupsPrinterIndex); const ppd_option_t* sizes = cups.pageSizes(); if (sizes) { - for (int j = 0; j < sizes->num_choices; ++j) { - d->m_paperSizes.append( - QPrinterInfoPrivate::string2PaperSize( - QLatin1String(sizes->choices[j].choice))); - } + for (int j = 0; j < sizes->num_choices; ++j) + d->paperSizes.append(string2PaperSize(sizes->choices[j].choice)); } } -#endif - } - return d->m_paperSizes; -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -QPrinterInfoPrivate::QPrinterInfoPrivate() -{ - m_isNull = true; - m_default = false; - m_mustGetPaperSizes = true; - m_cupsPrinterIndex = 0; - q_ptr = 0; -} - -QPrinterInfoPrivate::QPrinterInfoPrivate(const QString& name) -{ - m_name = name; - m_isNull = false; - m_default = false; - m_mustGetPaperSizes = true; - m_cupsPrinterIndex = 0; - q_ptr = 0; -} -QPrinterInfoPrivate::~QPrinterInfoPrivate() -{ -} - -QPrinter::PaperSize QPrinterInfoPrivate::string2PaperSize(const QString& str) -{ - if (str == QLatin1String("A4")) { - return QPrinter::A4; - } else if (str == QLatin1String("B5")) { - return QPrinter::B5; - } else if (str == QLatin1String("Letter")) { - return QPrinter::Letter; - } else if (str == QLatin1String("Legal")) { - return QPrinter::Legal; - } else if (str == QLatin1String("Executive")) { - return QPrinter::Executive; - } else if (str == QLatin1String("A0")) { - return QPrinter::A0; - } else if (str == QLatin1String("A1")) { - return QPrinter::A1; - } else if (str == QLatin1String("A2")) { - return QPrinter::A2; - } else if (str == QLatin1String("A3")) { - return QPrinter::A3; - } else if (str == QLatin1String("A5")) { - return QPrinter::A5; - } else if (str == QLatin1String("A6")) { - return QPrinter::A6; - } else if (str == QLatin1String("A7")) { - return QPrinter::A7; - } else if (str == QLatin1String("A8")) { - return QPrinter::A8; - } else if (str == QLatin1String("A9")) { - return QPrinter::A9; - } else if (str == QLatin1String("B0")) { - return QPrinter::B0; - } else if (str == QLatin1String("B1")) { - return QPrinter::B1; - } else if (str == QLatin1String("B10")) { - return QPrinter::B10; - } else if (str == QLatin1String("B2")) { - return QPrinter::B2; - } else if (str == QLatin1String("B3")) { - return QPrinter::B3; - } else if (str == QLatin1String("B4")) { - return QPrinter::B4; - } else if (str == QLatin1String("B6")) { - return QPrinter::B6; - } else if (str == QLatin1String("B7")) { - return QPrinter::B7; - } else if (str == QLatin1String("B8")) { - return QPrinter::B8; - } else if (str == QLatin1String("B9")) { - return QPrinter::B9; - } else if (str == QLatin1String("C5E")) { - return QPrinter::C5E; - } else if (str == QLatin1String("Comm10E")) { - return QPrinter::Comm10E; - } else if (str == QLatin1String("DLE")) { - return QPrinter::DLE; - } else if (str == QLatin1String("Folio")) { - return QPrinter::Folio; - } else if (str == QLatin1String("Ledger")) { - return QPrinter::Ledger; - } else if (str == QLatin1String("Tabloid")) { - return QPrinter::Tabloid; - } else { - return QPrinter::Custom; - } -} - -QString QPrinterInfoPrivate::pageSize2String(QPrinter::PaperSize size) -{ - switch (size) { - case QPrinter::A4: - return QLatin1String("A4"); - case QPrinter::B5: - return QLatin1String("B5"); - case QPrinter::Letter: - return QLatin1String("Letter"); - case QPrinter::Legal: - return QLatin1String("Legal"); - case QPrinter::Executive: - return QLatin1String("Executive"); - case QPrinter::A0: - return QLatin1String("A0"); - case QPrinter::A1: - return QLatin1String("A1"); - case QPrinter::A2: - return QLatin1String("A2"); - case QPrinter::A3: - return QLatin1String("A3"); - case QPrinter::A5: - return QLatin1String("A5"); - case QPrinter::A6: - return QLatin1String("A6"); - case QPrinter::A7: - return QLatin1String("A7"); - case QPrinter::A8: - return QLatin1String("A8"); - case QPrinter::A9: - return QLatin1String("A9"); - case QPrinter::B0: - return QLatin1String("B0"); - case QPrinter::B1: - return QLatin1String("B1"); - case QPrinter::B10: - return QLatin1String("B10"); - case QPrinter::B2: - return QLatin1String("B2"); - case QPrinter::B3: - return QLatin1String("B3"); - case QPrinter::B4: - return QLatin1String("B4"); - case QPrinter::B6: - return QLatin1String("B6"); - case QPrinter::B7: - return QLatin1String("B7"); - case QPrinter::B8: - return QLatin1String("B8"); - case QPrinter::B9: - return QLatin1String("B9"); - case QPrinter::C5E: - return QLatin1String("C5E"); - case QPrinter::Comm10E: - return QLatin1String("Comm10E"); - case QPrinter::DLE: - return QLatin1String("DLE"); - case QPrinter::Folio: - return QLatin1String("Folio"); - case QPrinter::Ledger: - return QLatin1String("Ledger"); - case QPrinter::Tabloid: - return QLatin1String("Tabloid"); - default: - return QLatin1String("Custom"); - } + return d->paperSizes; +#else + return QList<QPrinter::PaperSize>(); +#endif } #endif // QT_NO_PRINTER diff --git a/src/gui/painting/qprinterinfo_win.cpp b/src/gui/painting/qprinterinfo_win.cpp index 144b715..2c4014d 100644 --- a/src/gui/painting/qprinterinfo_win.cpp +++ b/src/gui/painting/qprinterinfo_win.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qprinterinfo.h" +#include "qprinterinfo_p.h" #include <qstringlist.h> @@ -51,59 +52,25 @@ QT_BEGIN_NAMESPACE extern QPrinter::PaperSize mapDevmodePaperSize(int s); -class QPrinterInfoPrivate -{ -Q_DECLARE_PUBLIC(QPrinterInfo) -public: - ~QPrinterInfoPrivate(); - QPrinterInfoPrivate(); - QPrinterInfoPrivate(const QString& name); - -private: - QString m_name; - bool m_default; - bool m_isNull; - - QPrinterInfo* q_ptr; -}; - -static QPrinterInfoPrivate nullQPrinterInfoPrivate; - -class QPrinterInfoPrivateDeleter -{ -public: - static inline void cleanup(QPrinterInfoPrivate *d) - { - if (d != &nullQPrinterInfoPrivate) - delete d; - } -}; - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - QList<QPrinterInfo> QPrinterInfo::availablePrinters() { QList<QPrinterInfo> printers; - LPBYTE buffer; + DWORD needed = 0; DWORD returned = 0; - - if ( !EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, 0, 0, &needed, &returned)) - { - buffer = new BYTE[needed]; - if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS , NULL, - 4, buffer, needed, &needed, &returned)) - { - delete [] buffer; - return printers; - } - PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer); - QPrinterInfo defPrn = defaultPrinter(); - for (uint i = 0; i < returned; ++i) { - printers.append(QPrinterInfo(QString::fromWCharArray(infoList[i].pPrinterName))); - if (printers.at(i).printerName() == defPrn.printerName()) - printers[i].d_ptr->m_default = true; + if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, 0, 0, &needed, &returned)) { + LPBYTE buffer = new BYTE[needed]; + if (EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, buffer, needed, &needed, &returned)) { + PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer); + QPrinterInfo defPrn = defaultPrinter(); + for (uint i = 0; i < returned; ++i) { + QString printerName(QString::fromWCharArray(infoList[i].pPrinterName)); + + QPrinterInfo printerInfo(printerName); + if (printerInfo.printerName() == defPrn.printerName()) + printerInfo.d_ptr->isDefault = true; + printers.append(printerInfo); + } } delete [] buffer; } @@ -117,127 +84,37 @@ QPrinterInfo QPrinterInfo::defaultPrinter() wchar_t buffer[256]; GetProfileString(L"windows", L"device", (wchar_t*)noPrinters.utf16(), buffer, 256); QString output = QString::fromWCharArray(buffer); - - // Filter out the name of the printer, which should be everything - // before a comma. - bool noConfiguredPrinters = (output == noPrinters); - QStringList info = output.split(QLatin1Char(',')); - QString printerName = noConfiguredPrinters ? QString() : info.at(0); - - QPrinterInfo prn(printerName); - prn.d_ptr->m_default = true; - if (noConfiguredPrinters) - prn.d_ptr->m_isNull = true; - return prn; -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -QPrinterInfo::QPrinterInfo() - : d_ptr(&nullQPrinterInfoPrivate) -{ -} - -QPrinterInfo::QPrinterInfo(const QString& name) - : d_ptr(new QPrinterInfoPrivate(name)) -{ - d_ptr->q_ptr = this; -} - -QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) - : d_ptr(&nullQPrinterInfoPrivate) -{ - *this = src; -} - -QPrinterInfo::QPrinterInfo(const QPrinter& prn) - : d_ptr(&nullQPrinterInfoPrivate) -{ - QList<QPrinterInfo> list = availablePrinters(); - for (int c = 0; c < list.size(); ++c) { - if (prn.printerName() == list[c].printerName()) { - *this = list[c]; - return; - } + if (output != noPrinters) { + // Filter out the name of the printer, which should be everything before a comma. + QString printerName = output.split(QLatin1Char(',')).value(0); + QPrinterInfo printerInfo(printerName); + printerInfo.d_ptr->isDefault = true; + return printerInfo; } - *this = QPrinterInfo(); -} - -QPrinterInfo::~QPrinterInfo() -{ -} - -QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) -{ - Q_ASSERT(d_ptr); - d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr)); - d_ptr->q_ptr = this; - return *this; -} - -QString QPrinterInfo::printerName() const -{ - const Q_D(QPrinterInfo); - return d->m_name; -} - -bool QPrinterInfo::isNull() const -{ - const Q_D(QPrinterInfo); - return d->m_isNull; -} - -bool QPrinterInfo::isDefault() const -{ - const Q_D(QPrinterInfo); - return d->m_default; + return QPrinterInfo(); } QList<QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const { const Q_D(QPrinterInfo); - QList<QPrinter::PaperSize> paperList; - DWORD size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->m_name.utf16()), - NULL, DC_PAPERS, NULL, NULL); - if ((int)size == -1) - return paperList; - - wchar_t *papers = new wchar_t[size]; - size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->m_name.utf16()), - NULL, DC_PAPERS, papers, NULL); + QList<QPrinter::PaperSize> paperSizes; + if (isNull()) + return paperSizes; - for (int c = 0; c < (int)size; ++c) { - paperList.append(mapDevmodePaperSize(papers[c])); + DWORD size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()), + NULL, DC_PAPERS, NULL, NULL); + if ((int)size != -1) { + wchar_t *papers = new wchar_t[size]; + size = DeviceCapabilities(reinterpret_cast<const wchar_t*>(d->name.utf16()), + NULL, DC_PAPERS, papers, NULL); + for (int c = 0; c < (int)size; ++c) + paperSizes.append(mapDevmodePaperSize(papers[c])); + delete [] papers; } - delete [] papers; - - return paperList; -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////// - -QPrinterInfoPrivate::QPrinterInfoPrivate() : - m_default(false), - m_isNull(true), - q_ptr(NULL) -{ -} - -QPrinterInfoPrivate::QPrinterInfoPrivate(const QString& name) : - m_name(name), - m_default(false), - m_isNull(false), - q_ptr(NULL) -{ -} - -QPrinterInfoPrivate::~QPrinterInfoPrivate() -{ + return paperSizes; } #endif // QT_NO_PRINTER diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index bd38286..75116c2 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -62,8 +62,8 @@ typedef int Q16Dot16; #define SPAN_BUFFER_SIZE 256 -#define COORD_ROUNDING 1 // 0: round up, 1: round down -#define COORD_OFFSET 32 // 26.6, 32 is half a pixel +#define COORD_ROUNDING 0 // 0: round up, 1: round down +#define COORD_OFFSET 0 // 26.6, 32 is half a pixel static inline QT_FT_Vector PointToVector(const QPointF &p) { diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 478a00b..d713346 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -391,6 +391,14 @@ void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byt */ /*! + \fn void QRegion::swap(QRegion &other) + \since 4.8 + + Swaps region \a other with this region. This operation is very + fast and never fails. +*/ + +/*! \relates QRegion Writes the region \a r to the stream \a s and returns a reference @@ -1620,7 +1628,7 @@ QT_END_INCLUDE_NAMESPACE QT_BEGIN_INCLUDE_NAMESPACE # include "qregion_win.cpp" QT_END_INCLUDE_NAMESPACE -#elif defined(Q_WS_QWS) +#elif defined(Q_WS_QWS) || defined(Q_WS_QPA) static QRegionPrivate qrp; QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp}; #endif @@ -4231,7 +4239,7 @@ QRect QRegion::boundingRect() const Returns true if \a rect is guaranteed to be fully contained in \a region. A false return value does not guarantee the opposite. */ -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) Q_GUI_EXPORT #endif bool qt_region_strictContains(const QRegion ®ion, const QRect &rect) diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index f78ece8..1cd38d4 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -59,7 +59,7 @@ QT_MODULE(Gui) template <class T> class QVector; class QVariant; -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) struct QRegionPrivate; #endif @@ -81,7 +81,11 @@ public: QRegion(const QBitmap &bitmap); ~QRegion(); QRegion &operator=(const QRegion &); - +#ifdef Q_COMPILER_RVALUE_REFS + inline QRegion &operator=(QRegion &&other) + { qSwap(d, other.d); return *this; } +#endif + inline void swap(QRegion &other) { qSwap(d, other.d); } #ifdef QT3_SUPPORT inline QT3_SUPPORT bool isNull() const { return isEmpty(); } #endif @@ -163,7 +167,7 @@ public: #endif HIMutableShapeRef toHIMutableShape() const; static QRegion fromHIShapeRef(HIShapeRef shape); -#elif defined(Q_WS_QWS) +#elif defined(Q_WS_QWS) || defined(Q_WS_QPA) inline void *handle() const { return d->qt_rgn; } #endif #endif @@ -203,7 +207,7 @@ private: #elif defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) mutable RgnHandle unused; // Here for binary compatibility reasons. ### Qt 5 remove. #endif -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) QRegionPrivate *qt_rgn; #endif }; diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 80353bc..dd723ed 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -552,6 +552,7 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine // // line to the beginning of the arc segment, (should not be needed). // emitLineTo(qt_real_to_fixed(curve_start.x()), qt_real_to_fixed(curve_start.y())); + Q_UNUSED(curve_start); for (int i=0; i<point_count; i+=3) { emitCubicTo(qt_real_to_fixed(curves[i].x()), @@ -668,26 +669,28 @@ template <class Iterator> bool qt_stroke_side(Iterator *it, #endif QLineF line(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y), qt_fixed_to_real(e.x), qt_fixed_to_real(e.y)); - QLineF normal = line.normalVector(); - normal.setLength(offset); - line.translate(normal.dx(), normal.dy()); - - // If we are starting a new subpath, move to correct starting point. - if (first) { - if (capFirst) - stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode()); - else - stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1())); - *startTangent = line; - first = false; - } else { - stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode()); - } + if (line.p1() != line.p2()) { + QLineF normal = line.normalVector(); + normal.setLength(offset); + line.translate(normal.dx(), normal.dy()); + + // If we are starting a new subpath, move to correct starting point. + if (first) { + if (capFirst) + stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode()); + else + stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1())); + *startTangent = line; + first = false; + } else { + stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode()); + } - // Add the stroke for this line. - stroker->emitLineTo(qt_real_to_fixed(line.x2()), - qt_real_to_fixed(line.y2())); - prev = e; + // Add the stroke for this line. + stroker->emitLineTo(qt_real_to_fixed(line.x2()), + qt_real_to_fixed(line.y2())); + prev = e; + } // CurveToElement } else if (e.isCurveTo()) { diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 3918ffc..e9e56a2 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -65,8 +65,60 @@ static inline int qt_next_power_of_two(int v) return v; } +int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const +{ + // Test 12 different subpixel positions since it factors into 3*4 so it gives + // the coverage we need. + + QList<QImage> images; + for (int i=0; i<12; ++i) { + QImage img = textureMapForGlyph(glyph, QFixed::fromReal(i / 12.0)); + + if (images.isEmpty()) { + QPainterPath path; + QFixedPoint point; + m_current_fontengine->addGlyphsToPath(&glyph, &point, 1, &path, QTextItem::RenderFlags()); + + // Glyph is space, return 0 to indicate that we need to keep trying + if (path.isEmpty()) + break; + + images.append(img); + } else { + bool found = false; + for (int j=0; j<images.size(); ++j) { + if (images.at(j) == img) { + found = true; + break; + } + } + if (!found) + images.append(img); + } + } + + return images.size(); +} + +QFixed QTextureGlyphCache::subPixelPositionForX(QFixed x) const +{ + if (m_subPixelPositionCount <= 1) + return QFixed(); + + QFixed subPixelPosition; + if (x != 0) { + subPixelPosition = x - x.floor(); + QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor(); + + // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over + // the lower boundary for the selected rasterization by adding 1/64. + subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625); + } + return subPixelPosition; +} + bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, - const QFixedPoint *) + const QFixedPoint *positions) { #ifdef CACHE_DEBUG printf("Populating with %d glyphs\n", numGlyphs); @@ -77,17 +129,46 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const const int margin = glyphMargin(); const int paddingDoubled = glyphPadding() * 2; - QHash<glyph_t, Coord> listItemCoordinates; + bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions(); + if (m_subPixelPositionCount == 0) { + if (!supportsSubPixelPositions) { + m_subPixelPositionCount = 1; + } else { +#if !defined(Q_WS_X11) + int i = 0; + while (m_subPixelPositionCount == 0 && i < numGlyphs) + m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]); +#else + m_subPixelPositionCount = 4; +#endif + } + } + + QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates; int rowHeight = 0; + QFontEngine::GlyphFormat format; + switch (m_type) { + case Raster_A8: format = QFontEngine::Format_A8; break; + case Raster_RGBMask: format = QFontEngine::Format_A32; break; + default: format = QFontEngine::Format_Mono; break; + } + // check each glyph for its metrics and get the required rowHeight. for (int i=0; i < numGlyphs; ++i) { const glyph_t glyph = glyphs[i]; - if (coords.contains(glyph)) + + QFixed subPixelPosition; + if (supportsSubPixelPositions) { + QFixed x = positions != 0 ? positions[i].x : QFixed(); + subPixelPosition = subPixelPositionForX(x); + } + + if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition))) continue; - if (listItemCoordinates.contains(glyph)) + if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition))) continue; - glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform); + glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, format); #ifdef CACHE_DEBUG printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n", @@ -98,11 +179,16 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const metrics.yoff.toReal(), metrics.x.toReal(), metrics.y.toReal()); -#endif +#endif + GlyphAndSubPixelPosition key(glyph, subPixelPosition); int glyph_width = metrics.width.ceil().toInt(); int glyph_height = metrics.height.ceil().toInt(); - if (glyph_height == 0 || glyph_width == 0) + if (glyph_height == 0 || glyph_width == 0) { + // Avoid multiple calls to boundingBox() for non-printable characters + Coord c = { 0, 0, 0, 0, 0, 0 }; + coords.insert(key, c); continue; + } glyph_width += margin * 2 + 4; glyph_height += margin * 2 + 4; // align to 8-bit boundary @@ -115,30 +201,35 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const metrics.x.round().truncate(), -metrics.y.truncate() }; // baseline for horizontal scripts - listItemCoordinates.insert(glyph, c); + listItemCoordinates.insert(key, c); rowHeight = qMax(rowHeight, glyph_height); } if (listItemCoordinates.isEmpty()) return true; rowHeight += margin * 2 + paddingDoubled; - if (isNull()) - createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight)); + + if (m_w == 0) { + if (fontEngine->maxCharWidth() <= QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH) + m_w = QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; + else + m_w = qt_next_power_of_two(fontEngine->maxCharWidth()); + } // now actually use the coords and paint the wanted glyps into cache. - QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin(); + QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin(); + int requiredWidth = m_w; while (iter != listItemCoordinates.end()) { Coord c = iter.value(); m_currentRowHeight = qMax(m_currentRowHeight, c.h + margin * 2); - if (m_cx + c.w > m_w) { - int new_width = m_w*2; + if (m_cx + c.w > requiredWidth) { + int new_width = requiredWidth*2; while (new_width < m_cx + c.w) new_width *= 2; if (new_width <= maxTextureWidth()) { - resizeTextureData(new_width, m_h); - m_w = new_width; + requiredWidth = new_width; } else { // no room on the current line, start new glyph strip m_cx = 0; @@ -146,36 +237,63 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const m_currentRowHeight = c.h + margin * 2; // New row } } - if (m_cy + c.h > m_h) { - int new_height = m_h*2; - while (new_height < m_cy + c.h) - new_height *= 2; - - if (maxTextureHeight() > 0 && new_height > maxTextureHeight()) { - // We can't make a new texture of the required size, so - // bail out - return false; - } - // if no room in the current texture - realloc a larger texture - resizeTextureData(m_w, new_height); - m_h = new_height; + if (maxTextureHeight() > 0 && m_cy + c.h > maxTextureHeight()) { + // We can't make a cache of the required size, so we bail out + return false; } c.x = m_cx; c.y = m_cy; - fillTexture(c, iter.key()); coords.insert(iter.key(), c); + m_pendingGlyphs.insert(iter.key(), c); m_cx += c.w + paddingDoubled; ++iter; } - return true; + +} + +void QTextureGlyphCache::fillInPendingGlyphs() +{ + if (m_pendingGlyphs.isEmpty()) + return; + + int requiredHeight = m_h; + int requiredWidth = m_w; // Use a minimum size to avoid a lot of initial reallocations + { + QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin(); + while (iter != m_pendingGlyphs.end()) { + Coord c = iter.value(); + requiredHeight = qMax(requiredHeight, c.y + c.h); + requiredWidth = qMax(requiredWidth, c.x + c.w); + ++iter; + } + } + + if (isNull() || requiredHeight > m_h || requiredWidth > m_w) { + if (isNull()) + createCache(qt_next_power_of_two(requiredWidth), qt_next_power_of_two(requiredHeight)); + else + resizeCache(qt_next_power_of_two(requiredWidth), qt_next_power_of_two(requiredHeight)); + } + + { + QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin(); + while (iter != m_pendingGlyphs.end()) { + GlyphAndSubPixelPosition key = iter.key(); + fillTexture(iter.value(), key.glyph, key.subPixelPosition); + + ++iter; + } + } + + m_pendingGlyphs.clear(); } -QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const +QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const { #if defined(Q_WS_X11) if (m_transform.type() > QTransform::TxTranslate && m_current_fontengine->type() == QFontEngine::Freetype) { @@ -198,9 +316,11 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine); QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform); + QFixedPoint positions[1]; + positions[0].x = subPixelPosition; - if (gset && ft->loadGlyphs(gset, &g, 1, format)) { - QFontEngineFT::Glyph *glyph = gset->getGlyph(g); + if (gset && ft->loadGlyphs(gset, &g, 1, positions, format)) { + QFontEngineFT::Glyph *glyph = gset->getGlyph(g, subPixelPosition); const int bytesPerLine = (format == QFontEngineFT::Format_Mono ? ((glyph->width + 31) & ~31) >> 3 : (glyph->width + 3) & ~3); return QImage(glyph->data, glyph->width, glyph->height, bytesPerLine, imageFormat); @@ -208,9 +328,9 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const } else #endif if (m_type == QFontEngineGlyphCache::Raster_RGBMask) - return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform); + return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, glyphMargin(), m_transform); else - return m_current_fontengine->alphaMapForGlyph(g, m_transform); + return m_current_fontengine->alphaMapForGlyph(g, subPixelPosition, m_transform); return QImage(); } @@ -247,16 +367,16 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) int QImageTextureGlyphCache::glyphMargin() const { -#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) +#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) || defined(Q_WS_X11) return 0; #else return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; #endif } -void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g) +void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subPixelPosition) { - QImage mask = textureMapForGlyph(g); + QImage mask = textureMapForGlyph(g, subPixelPosition); #ifdef CACHE_DEBUG printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height()); @@ -341,7 +461,7 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g) QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1); if (m_image.rect().contains(base)) m_image.setPixel(base, 255); - m_image.save(QString::fromLatin1("cache-%1.png").arg(int(this))); + m_image.save(QString::fromLatin1("cache-%1.png").arg(qint64(this))); #endif } diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 17f0d89..922e290 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -81,11 +81,24 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache public: QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) : QFontEngineGlyphCache(matrix, type), m_current_fontengine(0), - m_w(0), m_h(0), m_cx(0), m_cy(0), m_currentRowHeight(0) + m_w(0), m_h(0), m_cx(0), m_cy(0), m_currentRowHeight(0), m_subPixelPositionCount(0) { } virtual ~QTextureGlyphCache() { } + struct GlyphAndSubPixelPosition + { + GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {} + + bool operator==(const GlyphAndSubPixelPosition &other) const + { + return glyph == other.glyph && subPixelPosition == other.subPixelPosition; + } + + glyph_t glyph; + QFixed subPixelPosition; + }; + struct Coord { int x; int y; @@ -94,17 +107,23 @@ public: int baseLineX; int baseLineY; + + bool isNull() const + { + return w == 0 || h == 0; + } }; bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions); + void fillInPendingGlyphs(); virtual void createTextureData(int width, int height) = 0; virtual void resizeTextureData(int width, int height) = 0; virtual int glyphMargin() const { return 0; } virtual int glyphPadding() const { return 0; } - virtual void fillTexture(const Coord &coord, glyph_t glyph) = 0; + virtual void fillTexture(const Coord &coord, glyph_t glyph, QFixed subPixelPosition) = 0; inline void createCache(int width, int height) { m_w = width; @@ -112,24 +131,42 @@ public: createTextureData(width, height); } - inline bool isNull() const { return m_w <= 0 || m_h <= 0; } + inline void resizeCache(int width, int height) + { + resizeTextureData(width, height); + m_w = width; + m_h = height; + } - QHash<glyph_t, Coord> coords; + inline bool isNull() const { return m_h == 0; } - QImage textureMapForGlyph(glyph_t g) const; + QHash<GlyphAndSubPixelPosition, Coord> coords; virtual int maxTextureWidth() const { return QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; } virtual int maxTextureHeight() const { return -1; } + QImage textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const; + + QFixed subPixelPositionForX(QFixed x) const; + protected: + int calculateSubPixelPositionCount(glyph_t) const; + QFontEngine *m_current_fontengine; + QHash<GlyphAndSubPixelPosition, Coord> m_pendingGlyphs; int m_w; // image width int m_h; // image height int m_cx; // current x int m_cy; // current y int m_currentRowHeight; // Height of last row + int m_subPixelPositionCount; // Number of positions within a single pixel for this cache }; +inline uint qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g) +{ + return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt(); +} + class Q_GUI_EXPORT QImageTextureGlyphCache : public QTextureGlyphCache { @@ -139,7 +176,7 @@ public: virtual int glyphMargin() const; virtual void createTextureData(int width, int height); virtual void resizeTextureData(int width, int height); - virtual void fillTexture(const Coord &c, glyph_t glyph); + virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition); inline const QImage &image() const { return m_image; } diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 4441b30..7d11e2f 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1085,8 +1085,11 @@ QDebug operator<<(QDebug dbg, const QTransform &m) "TxNone", "TxTranslate", "TxScale", + 0, "TxRotate", + 0, 0, 0, "TxShear", + 0, 0, 0, 0, 0, 0, 0, "TxProject" }; diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp new file mode 100644 index 0000000..2fda6b9 --- /dev/null +++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qunifiedtoolbarsurface_mac_p.h" +#include <private/qt_cocoa_helpers_mac_p.h> +#include <private/qbackingstore_p.h> +#include <private/qmainwindowlayout_p.h> + +#include <QDebug> + +#ifdef QT_MAC_USE_COCOA + +QT_BEGIN_NAMESPACE + +QUnifiedToolbarSurface::QUnifiedToolbarSurface(QWidget *widget) + : QRasterWindowSurface(widget, false), d_ptr(new QUnifiedToolbarSurfacePrivate) +{ + d_ptr->image = 0; + d_ptr->inSetGeometry = false; + + setGeometry(QRect(QPoint(0, 0), QSize(widget->width(), 100))); // FIXME: Fix height. +} + +QUnifiedToolbarSurface::~QUnifiedToolbarSurface() +{ + if (d_ptr->image) + delete d_ptr->image; +} + +QPaintDevice *QUnifiedToolbarSurface::paintDevice() +{ + return &d_ptr->image->image; +} + +void QUnifiedToolbarSurface::recursiveRedirect(QObject *object, QWidget *parent_toolbar, const QPoint &offset) +{ + if (object != 0) { + if (object->isWidgetType()) { + QWidget *widget = qobject_cast<QWidget *>(object); + + // We redirect the painting only if the widget is in the same window + // and is not a window in itself. + if (!(widget->windowType() & Qt::Window)) { + widget->d_func()->unifiedSurface = this; + widget->d_func()->isInUnifiedToolbar = true; + widget->d_func()->toolbar_offset = offset; + widget->d_func()->toolbar_ancestor = parent_toolbar; + + for (int i = 0; i < object->children().size(); ++i) { + recursiveRedirect(object->children().at(i), parent_toolbar, offset); + } + } + } + } +} + +void QUnifiedToolbarSurface::insertToolbar(QWidget *toolbar, const QPoint &offset) +{ + setGeometry(QRect(QPoint(0, 0), QSize(offset.x() + toolbar->width(), 100))); // FIXME + recursiveRedirect(toolbar, toolbar, offset); +} + +// We basically undo what we set in recursiveRedirect(). +void QUnifiedToolbarSurface::recursiveRemoval(QObject *object) +{ + if (object != 0) { + if (object->isWidgetType()) { + QWidget *widget = qobject_cast<QWidget *>(object); + + // If it's a pop-up or something similar, we don't redirect it. + if (widget->windowType() & Qt::Window) + return; + + widget->d_func()->unifiedSurface = 0; + widget->d_func()->isInUnifiedToolbar = false; + widget->d_func()->toolbar_offset = QPoint(); + widget->d_func()->toolbar_ancestor = 0; + } + + for (int i = 0; i < object->children().size(); ++i) { + recursiveRemoval(object->children().at(i)); + } + } +} + +void QUnifiedToolbarSurface::removeToolbar(QToolBar *toolbar) +{ + recursiveRemoval(toolbar); +} + +void QUnifiedToolbarSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); + Q_D(QUnifiedToolbarSurface); + d->inSetGeometry = true; + if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) + prepareBuffer(QImage::Format_ARGB32_Premultiplied, window()); + d->inSetGeometry = false; + + // FIXME: set unified toolbar height. +} + +void QUnifiedToolbarSurface::beginPaint(const QRegion &rgn) +{ + QPainter p(&d_ptr->image->image); + p.setCompositionMode(QPainter::CompositionMode_Source); + const QVector<QRect> rects = rgn.rects(); + const QColor blank = Qt::transparent; + for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { + p.fillRect(*it, blank); + } +} + +void QUnifiedToolbarSurface::updateToolbarOffset(QWidget *widget) +{ + QMainWindowLayout *mlayout = qobject_cast<QMainWindowLayout*> (widget->window()->layout()); + if (mlayout) + mlayout->updateUnifiedToolbarOffset(); +} + +void QUnifiedToolbarSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + + this->flush(widget); +} + +void QUnifiedToolbarSurface::flush(QWidget *widget) +{ + Q_D(QUnifiedToolbarSurface); + + if (!d->image) + return; + + if (widget->d_func()->flushRequested) { + // We call display: directly to avoid flickering in the toolbar. + qt_mac_display(widget); + } +} + +void QUnifiedToolbarSurface::prepareBuffer(QImage::Format format, QWidget *widget) +{ + Q_D(QUnifiedToolbarSurface); + + int width = geometry().width(); + int height = 100; // FIXME + if (d->image) { + width = qMax(d->image->width(), width); + height = qMax(d->image->height(), height); + } + + if (width == 0 || height == 0) { + delete d->image; + d->image = 0; + return; + } + + QNativeImage *oldImage = d->image; + + d->image = new QNativeImage(width, height, format, false, widget); + + if (oldImage && d->inSetGeometry && hasStaticContents()) { + // Make sure we use the const version of bits() (no detach). + const uchar *src = const_cast<const QImage &>(oldImage->image).bits(); + uchar *dst = d->image->image.bits(); + + const int srcBytesPerLine = oldImage->image.bytesPerLine(); + const int dstBytesPerLine = d->image->image.bytesPerLine(); + const int bytesPerPixel = oldImage->image.depth() >> 3; + + QRegion staticRegion(staticContents()); + // Make sure we're inside the boundaries of the old image. + staticRegion &= QRect(0, 0, oldImage->image.width(), oldImage->image.height()); + const QVector<QRect> &rects = staticRegion.rects(); + const QRect *srcRect = rects.constData(); + + // Copy the static content of the old image into the new one. + int numRectsLeft = rects.size(); + do { + const int bytesOffset = srcRect->x() * bytesPerPixel; + const int dy = srcRect->y(); + + // Adjust src and dst to point to the right offset. + const uchar *s = src + dy * srcBytesPerLine + bytesOffset; + uchar *d = dst + dy * dstBytesPerLine + bytesOffset; + const int numBytes = srcRect->width() * bytesPerPixel; + + int numScanLinesLeft = srcRect->height(); + do { + ::memcpy(d, s, numBytes); + d += dstBytesPerLine; + s += srcBytesPerLine; + } while (--numScanLinesLeft); + + ++srcRect; + } while (--numRectsLeft); + } + + delete oldImage; +} + +CGContextRef QUnifiedToolbarSurface::imageContext() +{ + Q_D(QUnifiedToolbarSurface); + return d->image->cg; +} + +void QUnifiedToolbarSurface::renderToolbar(QWidget *widget, bool forceFlush) +{ + QWidget *toolbar = widget->d_func()->toolbar_ancestor; + + updateToolbarOffset(toolbar); + QRect beginPaintRect(toolbar->d_func()->toolbar_offset.x(), toolbar->d_func()->toolbar_offset.y(), toolbar->geometry().width(), toolbar->geometry().height()); + QRegion beginPaintRegion(beginPaintRect); + + beginPaint(beginPaintRegion); + toolbar->render(paintDevice(), toolbar->d_func()->toolbar_offset, QRegion(toolbar->geometry()), QWidget::DrawChildren); + toolbar->d_func()->flushRequested = true; + + if (forceFlush) + flush(toolbar); +} + +QT_END_NAMESPACE + +#endif // QT_MAC_USE_COCOA diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac_p.h b/src/gui/painting/qunifiedtoolbarsurface_mac_p.h new file mode 100644 index 0000000..0a7ebf1 --- /dev/null +++ b/src/gui/painting/qunifiedtoolbarsurface_mac_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUNIFIEDTOOLBARSURFACE_MAC_P_H +#define QUNIFIEDTOOLBARSURFACE_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qwindowsurface_raster_p.h> +#include <QWidget> +#include <QToolBar> +#include <private/qwidget_p.h> +#include <private/qnativeimage_p.h> + +#ifdef QT_MAC_USE_COCOA + +QT_BEGIN_NAMESPACE + +class QNativeImage; + + +class QUnifiedToolbarSurfacePrivate +{ +public: + QNativeImage *image; + uint inSetGeometry : 1; +}; + +class Q_GUI_EXPORT QUnifiedToolbarSurface : public QRasterWindowSurface +{ +public: + QUnifiedToolbarSurface(QWidget *widget); + ~QUnifiedToolbarSurface(); + + void flush(QWidget *widget); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + void beginPaint(const QRegion &rgn); + void insertToolbar(QWidget *toolbar, const QPoint &offset); + void removeToolbar(QToolBar *toolbar); + void updateToolbarOffset(QWidget *widget); + void renderToolbar(QWidget *widget, bool forceFlush = false); + void recursiveRedirect(QObject *widget, QWidget *parent_toolbar, const QPoint &offset); + + QPaintDevice *paintDevice(); + CGContextRef imageContext(); + +private: + void prepareBuffer(QImage::Format format, QWidget *widget); + void recursiveRemoval(QObject *object); + + Q_DECLARE_PRIVATE(QUnifiedToolbarSurface) + QScopedPointer<QUnifiedToolbarSurfacePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QT_MAC_USE_COCOA + +#endif // QUNIFIEDTOOLBARSURFACE_MAC_P_H diff --git a/src/gui/painting/qwindowsurface.cpp b/src/gui/painting/qwindowsurface.cpp index b84f26e..0fb9bf7 100644 --- a/src/gui/painting/qwindowsurface.cpp +++ b/src/gui/painting/qwindowsurface.cpp @@ -52,17 +52,17 @@ class QWindowSurfacePrivate public: QWindowSurfacePrivate(QWidget *w) : window(w) - , staticContentsSupport(0) - , partialUpdateSupport(1) { } QWidget *window; +#if !defined(Q_WS_QPA) QRect geometry; +#else + QSize size; +#endif //Q_WS_QPA QRegion staticContents; QList<QImage*> bufferImages; - uint staticContentsSupport : 1; - uint partialUpdateSupport : 1; }; /*! @@ -70,7 +70,7 @@ public: \since 4.3 \internal \preliminary - \ingroup qws + \ingroup qws qpa \brief The QWindowSurface class provides the drawing area for top-level windows. @@ -114,11 +114,11 @@ public: /*! Constructs an empty surface for the given top-level \a window. */ -QWindowSurface::QWindowSurface(QWidget *window) +QWindowSurface::QWindowSurface(QWidget *window, bool setDefaultSurface) : d_ptr(new QWindowSurfacePrivate(window)) { if (!QApplicationPrivate::runtime_graphics_system) { - if(window) + if(setDefaultSurface && window) window->setWindowSurface(this); } } @@ -153,6 +153,7 @@ void QWindowSurface::endPaint(const QRegion &) d_ptr->bufferImages.clear(); } +#if !defined(Q_WS_QPA) /*! Sets the currently allocated area to be the given \a rect. @@ -173,6 +174,26 @@ QRect QWindowSurface::geometry() const { return d_ptr->geometry; } +#else + +/*! + Sets the size of the windowsurface to be \a size. + + \sa size() +*/ +void QWindowSurface::resize(const QSize &size) +{ + d_ptr->size = size; +} + +/*! + Returns the current size of the windowsurface. +*/ +QSize QWindowSurface::size() const +{ + return d_ptr->size; +} +#endif //Q_WS_QPA /*! Scrolls the given \a area \a dx pixels to the right and \a dy @@ -286,20 +307,6 @@ QPoint QWindowSurface::offset(const QWidget *widget) const window surface. */ -bool QWindowSurface::hasStaticContentsSupport() const -{ - return d_ptr->staticContentsSupport; -} - -void QWindowSurface::setStaticContentsSupport(bool enable) -{ - if (enable && !d_ptr->partialUpdateSupport) { - qWarning("QWindowSurface::setStaticContentsSupport: static contents support requires partial update support"); - return; - } - d_ptr->staticContentsSupport = enable; -} - void QWindowSurface::setStaticContents(const QRegion ®ion) { d_ptr->staticContents = region; @@ -312,24 +319,21 @@ QRegion QWindowSurface::staticContents() const bool QWindowSurface::hasStaticContents() const { - return d_ptr->staticContentsSupport && !d_ptr->staticContents.isEmpty(); + return hasFeature(QWindowSurface::StaticContents) && !d_ptr->staticContents.isEmpty(); } -bool QWindowSurface::hasPartialUpdateSupport() const +QWindowSurface::WindowSurfaceFeatures QWindowSurface::features() const { - return d_ptr->partialUpdateSupport; + return PartialUpdates | PreservedContents; } -void QWindowSurface::setPartialUpdateSupport(bool enable) -{ - if (!enable && d_ptr->staticContentsSupport) { - qWarning("QWindowSurface::setPartialUpdateSupport: static contents support requires partial update support"); - return; - } - d_ptr->partialUpdateSupport = enable; -} +#ifdef Q_WS_QPA +#define Q_EXPORT_SCROLLRECT Q_GUI_EXPORT +#else +#define Q_EXPORT_SCROLLRECT +#endif -void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) +void Q_EXPORT_SCROLLRECT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset) { // make sure we don't detach uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits()); diff --git a/src/gui/painting/qwindowsurface_mac.cpp b/src/gui/painting/qwindowsurface_mac.cpp index 88d41ba..620a50f 100644 --- a/src/gui/painting/qwindowsurface_mac.cpp +++ b/src/gui/painting/qwindowsurface_mac.cpp @@ -82,6 +82,7 @@ void QMacWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint extern CGContextRef qt_mac_graphicsContextFor(QWidget *); CGContextRef context = qt_mac_graphicsContextFor(widget); #endif + CGContextRetain(context); CGContextSaveGState(context); // Flip context. @@ -109,6 +110,7 @@ void QMacWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint #else CGContextFlush(context); #endif + CGContextRelease(context); } void QMacWindowSurface::setGeometry(const QRect &rect) diff --git a/src/gui/painting/qwindowsurface_p.h b/src/gui/painting/qwindowsurface_p.h index 6275ec0..a3fea67 100644 --- a/src/gui/painting/qwindowsurface_p.h +++ b/src/gui/painting/qwindowsurface_p.h @@ -63,11 +63,20 @@ class QRect; class QPoint; class QImage; class QWindowSurfacePrivate; +class QPlatformWindow; class Q_GUI_EXPORT QWindowSurface { public: - QWindowSurface(QWidget *window); + enum WindowSurfaceFeature { + PartialUpdates = 0x00000001, // Supports doing partial updates. + PreservedContents = 0x00000002, // Supports doing flush without first doing a repaint. + StaticContents = 0x00000004, // Supports having static content regions when being resized. + AllFeatures = 0xffffffff // For convenience + }; + Q_DECLARE_FLAGS(WindowSurfaceFeatures, WindowSurfaceFeature) + + QWindowSurface(QWidget *window, bool setDefaultSurface = true); virtual ~QWindowSurface(); QWidget *window() const; @@ -79,8 +88,14 @@ public: // can be larger than just the offset from the top-level widget as there may also be window // decorations which are painted into the window surface. virtual void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) = 0; +#if !defined(Q_WS_QPA) virtual void setGeometry(const QRect &rect); QRect geometry() const; +#else + virtual void resize(const QSize &size); + QSize size() const; + inline QRect geometry() const { return QRect(QPoint(), size()); } //### cleanup before Qt 5 +#endif virtual bool scroll(const QRegion &area, int dx, int dy); @@ -93,26 +108,31 @@ public: virtual QPoint offset(const QWidget *widget) const; inline QRect rect(const QWidget *widget) const; - bool hasStaticContentsSupport() const; - bool hasPartialUpdateSupport() const; + bool hasFeature(WindowSurfaceFeature feature) const; + virtual WindowSurfaceFeatures features() const; void setStaticContents(const QRegion ®ion); QRegion staticContents() const; protected: bool hasStaticContents() const; - void setStaticContentsSupport(bool enable); - void setPartialUpdateSupport(bool enable); private: QWindowSurfacePrivate *d_ptr; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowSurface::WindowSurfaceFeatures) + inline QRect QWindowSurface::rect(const QWidget *widget) const { return widget->rect().translated(offset(widget)); } +inline bool QWindowSurface::hasFeature(WindowSurfaceFeature feature) const +{ + return (features() & feature) != 0; +} + QT_END_NAMESPACE #endif // QWINDOWSURFACE_P_H diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp index ccb10ff..9860841 100644 --- a/src/gui/painting/qwindowsurface_raster.cpp +++ b/src/gui/painting/qwindowsurface_raster.cpp @@ -64,6 +64,9 @@ #ifdef Q_WS_MAC #include <private/qt_cocoa_helpers_mac_p.h> +#include <QMainWindow> +#include <private/qmainwindowlayout_p.h> +#include <QToolBar> #endif QT_BEGIN_NAMESPACE @@ -75,6 +78,9 @@ public: #ifdef Q_WS_X11 GC gc; +#ifndef QT_NO_MITSHM + uint needsSync : 1; +#endif #ifndef QT_NO_XRENDER uint translucentBackground : 1; #endif @@ -82,8 +88,8 @@ public: uint inSetGeometry : 1; }; -QRasterWindowSurface::QRasterWindowSurface(QWidget *window) - : QWindowSurface(window), d_ptr(new QRasterWindowSurfacePrivate) +QRasterWindowSurface::QRasterWindowSurface(QWidget *window, bool setDefaultSurface) + : QWindowSurface(window, setDefaultSurface), d_ptr(new QRasterWindowSurfacePrivate) { #ifdef Q_WS_X11 d_ptr->gc = XCreateGC(X11->display, window->handle(), 0, 0); @@ -91,10 +97,17 @@ QRasterWindowSurface::QRasterWindowSurface(QWidget *window) d_ptr->translucentBackground = X11->use_xrender && window->x11Info().depth() == 32; #endif +#ifndef QT_NO_MITHSM + d_ptr->needsSync = false; +#endif #endif d_ptr->image = 0; d_ptr->inSetGeometry = false; - setStaticContentsSupport(true); + +#ifdef QT_MAC_USE_COCOA + needsFlush = false; + regionToFlush = QRegion(); +#endif // QT_MAC_USE_COCOA } @@ -113,8 +126,23 @@ QPaintDevice *QRasterWindowSurface::paintDevice() return &d_ptr->image->image; } +#if defined(Q_WS_X11) && !defined(QT_NO_MITSHM) +void QRasterWindowSurface::syncX() +{ + // delay writing to the backbuffer until we know for sure X is done reading from it + if (d_ptr->needsSync) { + XSync(X11->display, false); + d_ptr->needsSync = false; + } +} +#endif + void QRasterWindowSurface::beginPaint(const QRegion &rgn) { +#if defined(Q_WS_X11) && !defined(QT_NO_MITSHM) + syncX(); +#endif + #if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_WS_WINCE)) if (!qt_widget_private(window())->isOpaque && window()->testAttribute(Qt::WA_TranslucentBackground)) { #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) @@ -214,13 +242,13 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi if (d_ptr->image->xshmpm) { XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc, br.x(), br.y(), br.width(), br.height(), wbr.x(), wbr.y()); - XSync(X11->display, False); + d_ptr->needsSync = true; } else if (d_ptr->image->xshmimg) { const QImage &src = d->image->image; br = br.intersected(src.rect()); XShmPutImage(X11->display, widget->handle(), d_ptr->gc, d_ptr->image->xshmimg, br.x(), br.y(), wbr.x(), wbr.y(), br.width(), br.height(), False); - XSync(X11->display, False); + d_ptr->needsSync = true; } else #endif { @@ -248,20 +276,27 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi #ifdef Q_WS_MAC -// qDebug() << "Flushing" << widget << rgn << offset; + Q_UNUSED(offset); -// d->image->image.save("flush.png"); + // This is mainly done for native components like native "open file" dialog. + if (widget->testAttribute(Qt::WA_DontShowOnScreen)) { + return; + } - Q_UNUSED(offset); +#ifdef QT_MAC_USE_COCOA + + this->needsFlush = true; + this->regionToFlush += rgn; + + // The actual flushing will be processed in [view drawRect:rect] + qt_mac_setNeedsDisplay(widget); + +#else // Get a context for the widget. -#ifndef QT_MAC_USE_COCOA CGContextRef context; CGrafPtr port = GetWindowPort(qt_mac_window_for(widget)); QDBeginCGContext(port, &context); -#else - extern CGContextRef qt_mac_graphicsContextFor(QWidget *); - CGContextRef context = qt_mac_graphicsContextFor(widget); -#endif + CGContextRetain(context); CGContextSaveGState(context); // Flip context. @@ -282,20 +317,17 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi CGImageRef subImage = CGImageCreateWithImageInRect(image, area); qt_mac_drawCGImage(context, &area, subImage); + CGImageRelease(subImage); CGImageRelease(image); -// CGSize size = { d->image->image.width(), d->image->image.height() }; -// CGLayerRef layer = CGLayerCreateWithContext(d->image->cg, size, 0); -// CGPoint pt = { 0, 0 }; -// CGContextDrawLayerAtPoint(context, pt, layer); -// CGLayerRelease(layer); + QDEndCGContext(port, &context); // Restore context. CGContextRestoreGState(context); -#ifndef QT_MAC_USE_COCOA - QDEndCGContext(port, &context); -#endif + CGContextRelease(context); +#endif // QT_MAC_USE_COCOA + #endif // Q_WS_MAC #ifdef Q_OS_SYMBIAN @@ -323,6 +355,25 @@ void QRasterWindowSurface::setGeometry(const QRect &rect) prepareBuffer(QNativeImage::systemFormat(), window()); } d->inSetGeometry = false; + +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + QMainWindow* mWindow = qobject_cast<QMainWindow*>(window()); + if (mWindow) { + QMainWindowLayout *mLayout = qobject_cast<QMainWindowLayout*>(mWindow->layout()); + QList<QToolBar *> toolbarList = mLayout->qtoolbarsInUnifiedToolbarList; + + for (int i = 0; i < toolbarList.size(); ++i) { + QToolBar* toolbar = toolbarList.at(i); + if (mLayout->toolBarArea(toolbar) == Qt::TopToolBarArea) { + QWidget* tbWidget = (QWidget*) toolbar; + if (tbWidget->d_func()->unifiedSurface) { + tbWidget->d_func()->unifiedSurface->setGeometry(rect); + } + } + } + } +#endif // Q_WS_MAC && QT_MAC_USE_COCOA + } // from qwindowsurface.cpp @@ -347,6 +398,10 @@ bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy) if (!d->image || d->image->image.isNull()) return false; +#if defined(Q_WS_X11) && !defined(QT_NO_MITSHM) + syncX(); +#endif + const QVector<QRect> rects = area.rects(); for (int i = 0; i < rects.size(); ++i) qt_scrollRectInImage(d->image->image, rects.at(i), QPoint(dx, dy)); @@ -355,6 +410,10 @@ bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy) #endif } +QWindowSurface::WindowSurfaceFeatures QRasterWindowSurface::features() const +{ + return QWindowSurface::AllFeatures; +} void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget) { @@ -417,4 +476,12 @@ void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget) delete oldImage; } +#ifdef QT_MAC_USE_COCOA +CGContextRef QRasterWindowSurface::imageContext() +{ + Q_D(QRasterWindowSurface); + return d->image->cg; +} +#endif // QT_MAC_USE_COCOA + QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_raster_p.h b/src/gui/painting/qwindowsurface_raster_p.h index 42f4bb5..06abcd3 100644 --- a/src/gui/painting/qwindowsurface_raster_p.h +++ b/src/gui/painting/qwindowsurface_raster_p.h @@ -56,6 +56,10 @@ #include <qglobal.h> #include "private/qwindowsurface_p.h" +#ifdef QT_MAC_USE_COCOA +# include <private/qt_cocoa_helpers_mac_p.h> +#endif // QT_MAC_USE_COCOA + QT_BEGIN_NAMESPACE #ifdef Q_WS_WIN @@ -97,7 +101,7 @@ class QNativeImage; class Q_GUI_EXPORT QRasterWindowSurface : public QWindowSurface { public: - QRasterWindowSurface(QWidget *widget); + QRasterWindowSurface(QWidget *widget, bool setDefaultSurface = true); ~QRasterWindowSurface(); QPaintDevice *paintDevice(); @@ -105,8 +109,19 @@ public: void beginPaint(const QRegion &rgn); void setGeometry(const QRect &rect); bool scroll(const QRegion &area, int dx, int dy); + WindowSurfaceFeatures features() const; + +#ifdef QT_MAC_USE_COCOA + CGContextRef imageContext(); + + bool needsFlush; + QRegion regionToFlush; +#endif // QT_MAC_USE_COCOA private: +#if defined(Q_WS_X11) && !defined(QT_NO_MITSHM) + void syncX(); +#endif void prepareBuffer(QImage::Format format, QWidget *widget); Q_DECLARE_PRIVATE(QRasterWindowSurface) QScopedPointer<QRasterWindowSurfacePrivate> d_ptr; diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index cb53ea0..9fa01ed 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -88,7 +88,8 @@ QS60WindowSurface::QS60WindowSurface(QWidget* widget) const bool opaque = widgetPrivate->isOpaque && !blitWriteAlpha(widgetPrivate); TDisplayMode mode = displayMode(opaque); // We create empty CFbsBitmap here -> it will be resized in setGeometry - CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new + CFbsBitmap *bitmap = new CFbsBitmap; // CBase derived object needs check on new + Q_CHECK_PTR(bitmap); qt_symbian_throwIfError( bitmap->Create( TSize(0, 0), mode ) ); QS60PixmapData *data = new QS60PixmapData(QPixmapData::PixmapType); @@ -96,8 +97,6 @@ QS60WindowSurface::QS60WindowSurface(QWidget* widget) data->fromSymbianBitmap(bitmap, true); d_ptr->device = QPixmap(data); } - - setStaticContentsSupport(true); } QS60WindowSurface::~QS60WindowSurface() @@ -240,6 +239,11 @@ void QS60WindowSurface::setGeometry(const QRect& rect) QWindowSurface::setGeometry(rect); } +QWindowSurface::WindowSurfaceFeatures QS60WindowSurface::features() const +{ + return QWindowSurface::AllFeatures; +} + CFbsBitmap* QS60WindowSurface::symbianBitmap() const { QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); diff --git a/src/gui/painting/qwindowsurface_s60_p.h b/src/gui/painting/qwindowsurface_s60_p.h index d0d4925..25018d8 100644 --- a/src/gui/painting/qwindowsurface_s60_p.h +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -79,6 +79,8 @@ public: void setGeometry(const QRect &rect); + WindowSurfaceFeatures features() const; + CFbsBitmap *symbianBitmap() const; private: diff --git a/src/gui/painting/qwindowsurface_x11.cpp b/src/gui/painting/qwindowsurface_x11.cpp index 8c2c68a..deb83b4 100644 --- a/src/gui/painting/qwindowsurface_x11.cpp +++ b/src/gui/painting/qwindowsurface_x11.cpp @@ -70,9 +70,6 @@ QX11WindowSurface::QX11WindowSurface(QWidget *widget) #ifndef QT_NO_XRENDER d_ptr->translucentBackground = X11->use_xrender && widget->x11Info().depth() == 32; - setStaticContentsSupport(!d_ptr->translucentBackground); -#else - setStaticContentsSupport(true); #endif } @@ -149,6 +146,8 @@ void QX11WindowSurface::setGeometry(const QRect &rect) return; #ifndef QT_NO_XRENDER if (d_ptr->translucentBackground) { + QPixmap::x11SetDefaultScreen(d_ptr->widget->x11Info().screen()); + QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType); data->xinfo = d_ptr->widget->x11Info(); data->resize(size.width(), size.height()); @@ -251,4 +250,16 @@ QPixmap QX11WindowSurface::grabWidget(const QWidget *widget, return px; } +QWindowSurface::WindowSurfaceFeatures QX11WindowSurface::features() const +{ + WindowSurfaceFeatures features = QWindowSurface::PartialUpdates | QWindowSurface::PreservedContents; +#ifndef QT_NO_XRENDER + if (!d_ptr->translucentBackground) + features |= QWindowSurface::StaticContents; +#else + features |= QWindowSurface::StaticContents; +#endif + return features; +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_x11_p.h b/src/gui/painting/qwindowsurface_x11_p.h index 88753ea..df76f98 100644 --- a/src/gui/painting/qwindowsurface_x11_p.h +++ b/src/gui/painting/qwindowsurface_x11_p.h @@ -80,6 +80,8 @@ public: bool scroll(const QRegion &area, int dx, int dy); QPixmap grabWidget(const QWidget *widget, const QRect& rectangle = QRect()) const; + WindowSurfaceFeatures features() const; + private: QX11WindowSurfacePrivate *d_ptr; GC gc; |