Basic high-dpi "retina" support for Qt 5.

Bring Qt 5 on par with Qt 4, prepare for more comprehensive
support later on.

Introduce device independent pixels (dips), device pixels,
and devicePixelRatio. Add high-dpi support to QPainter,
QGLWidget, the cocoa platform plugin, mac and fusion styles.

Dips are similar to CSS pixels, Apple points and
Android density-independent pixels. Device pixels
are pixels in the backing store/physical pixels on screen.
devicePixelRatio is the ratio between them, which is
1.0 on standard displays and 2.0 on "retina" displays.

New API:
QImage::devicePixelRatio() and setDevicePixelRatio()
QPixmap::devicePixelRatio() and setDevicePixelRatio()
QWindow::devicePixelRatio()
QScreen::devicePixelRatio()
QGuiApplicaiton::devicePixelRatio()

Change-Id: If98c3ca9bfdf0e1bdbcf7574cd5b912c9ff63856
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
This commit is contained in:
Morten Johan Sørvig 2012-11-20 11:34:52 +01:00 committed by The Qt Project
parent c8dc41bacd
commit 5e61bbe586
50 changed files with 934 additions and 119 deletions

View File

@ -95,10 +95,12 @@ static QImage rotated270(const QImage &src);
QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1); QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
QImageData::QImageData() QImageData::QImageData()
: ref(0), width(0), height(0), depth(0), nbytes(0), data(0), : ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(0),
format(QImage::Format_ARGB32), bytes_per_line(0), format(QImage::Format_ARGB32), bytes_per_line(0),
ser_no(qimage_serial_number.fetchAndAddRelaxed(1)), ser_no(qimage_serial_number.fetchAndAddRelaxed(1)),
detach_no(0), detach_no(0),
ldpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
ldpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
dpmx(qt_defaultDpiX() * 100 / qreal(2.54)), dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
dpmy(qt_defaultDpiY() * 100 / qreal(2.54)), dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false), offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
@ -1216,6 +1218,7 @@ QImage QImage::copy(const QRect& r) const
image.d->dpmx = dotsPerMeterX(); image.d->dpmx = dotsPerMeterX();
image.d->dpmy = dotsPerMeterY(); image.d->dpmy = dotsPerMeterY();
image.d->devicePixelRatio = devicePixelRatio();
image.d->offset = offset(); image.d->offset = offset();
image.d->has_alpha_clut = d->has_alpha_clut; image.d->has_alpha_clut = d->has_alpha_clut;
image.d->text = d->text; image.d->text = d->text;
@ -1369,6 +1372,52 @@ QVector<QRgb> QImage::colorTable() const
return d ? d->colortable : QVector<QRgb>(); return d ? d->colortable : QVector<QRgb>();
} }
/*!
Returns the device pixel ratio for the image. This is the
ratio between image pixels and device-independent pixels.
Use this function when calculating layout geometry based on
the image size: QSize layoutSize = image.size() / image.devicePixelRatio()
The default value is 1.0.
\sa setDevicePixelRatio()
*/
qreal QImage::devicePixelRatio() const
{
if (!d)
return 1.0;
return d->devicePixelRatio;
}
/*!
Sets the the device pixel ratio for the image. This is the
ratio between image pixels and device-independent pixels.
The default value is 1.0. Setting it to something else has
two effects:
QPainters that are opened on the image will be scaled. For
example, painting on a 200x200 image if with a ratio of 2.0
will result in effective (device-independent) painting bounds
of 100x100.
Code paths in Qt that calculate layout geometry based on the
image size will take the ratio into account:
QSize layoutSize = image.size() / image.devicePixelRatio()
The net effect of this is that the image is displayed as
high-dpi image rather than a large image.
\sa devicePixelRatio()
*/
void QImage::setDevicePixelRatio(qreal scaleFactor)
{
if (!d)
return;
detach();
d->devicePixelRatio = scaleFactor;
}
/*! /*!
\since 4.6 \since 4.6
Returns the number of bytes occupied by the image data. Returns the number of bytes occupied by the image data.
@ -3359,6 +3408,7 @@ QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) co
image.setDotsPerMeterY(dotsPerMeterY()); image.setDotsPerMeterY(dotsPerMeterY());
image.setDotsPerMeterX(dotsPerMeterX()); image.setDotsPerMeterX(dotsPerMeterX());
image.setDevicePixelRatio(devicePixelRatio());
image.d->text = d->text; image.d->text = d->text;
@ -3479,6 +3529,7 @@ QImage QImage::convertToFormat(Format format, const QVector<QRgb> &colorTable, Q
QImage image(d->width, d->height, format); QImage image(d->width, d->height, format);
QIMAGE_SANITYCHECK_MEMORY(image); QIMAGE_SANITYCHECK_MEMORY(image);
image.setDevicePixelRatio(devicePixelRatio());
image.d->text = d->text; image.d->text = d->text;
@ -4932,17 +4983,20 @@ int QImage::metric(PaintDeviceMetric metric) const
return d->depth; return d->depth;
case PdmDpiX: case PdmDpiX:
return qRound(d->dpmx * 0.0254); return qRound(d->ldpmx * 0.0254);
break;
case PdmDpiY: case PdmDpiY:
return qRound(d->dpmy * 0.0254); return qRound(d->ldpmy * 0.0254);
break;
case PdmPhysicalDpiX: case PdmPhysicalDpiX:
return qRound(d->dpmx * 0.0254); return qRound(d->dpmx * 0.0254 * d->devicePixelRatio);
break;
case PdmPhysicalDpiY: case PdmPhysicalDpiY:
return qRound(d->dpmy * 0.0254); return qRound(d->dpmy * 0.0254 * d->devicePixelRatio);
break;
default: default:
qWarning("QImage::metric(): Unhandled metric type %d", metric); qWarning("QImage::metric(): Unhandled metric type %d", metric);
break; break;
@ -5641,6 +5695,7 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode
dImage.d->dpmx = dotsPerMeterX(); dImage.d->dpmx = dotsPerMeterX();
dImage.d->dpmy = dotsPerMeterY(); dImage.d->dpmy = dotsPerMeterY();
dImage.d->devicePixelRatio = devicePixelRatio();
switch (bpp) { switch (bpp) {
// initizialize the data // initizialize the data

View File

@ -211,6 +211,9 @@ public:
QVector<QRgb> colorTable() const; QVector<QRgb> colorTable() const;
void setColorTable(const QVector<QRgb> colors); void setColorTable(const QVector<QRgb> colors);
qreal devicePixelRatio() const;
void setDevicePixelRatio(qreal scaleFactor);
void fill(uint pixel); void fill(uint pixel);
void fill(const QColor &color); void fill(const QColor &color);
void fill(Qt::GlobalColor color); void fill(Qt::GlobalColor color);

View File

@ -74,6 +74,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data
int height; int height;
int depth; int depth;
int nbytes; // number of bytes data int nbytes; // number of bytes data
qreal devicePixelRatio;
QVector<QRgb> colortable; QVector<QRgb> colortable;
uchar *data; uchar *data;
QImage::Format format; QImage::Format format;
@ -81,8 +82,10 @@ struct Q_GUI_EXPORT QImageData { // internal image data
int ser_no; // serial number int ser_no; // serial number
int detach_no; int detach_no;
qreal dpmx; // dots per meter X (or 0) qreal ldpmx; // logical dots per meter X (or 0)
qreal dpmy; // dots per meter Y (or 0) qreal ldpmy; // logical dots per meter Y (or 0)
qreal dpmx; // device dots per meter X (or 0)
qreal dpmy; // device dots per meter Y (or 0)
QPoint offset; // offset in pixels QPoint offset; // offset in pixels
uint own_data : 1; uint own_data : 1;

View File

@ -1234,6 +1234,11 @@ bool QImageReader::read(QImage *image)
} }
} }
// successful read; check for "@2x" file name suffix and set device pixel ratio.
if (QFileInfo(fileName()).baseName().endsWith("@2x")) {
image->setDevicePixelRatio(2.0);
}
return true; return true;
} }

View File

@ -638,6 +638,50 @@ void QPixmap::setMask(const QBitmap &mask)
data->fromImage(image, Qt::AutoColor); data->fromImage(image, Qt::AutoColor);
} }
/*!
Returns the device pixel ratio for the pixmap. This is the
ratio between pixmap pixels and device-independent pixels.
Use this function when calculating layout geometry based on
the pixmap size: QSize layoutSize = image.size() / image.devicePixelRatio()
The default value is 1.0.
\sa setDevicePixelRatio()
*/
qreal QPixmap::devicePixelRatio() const
{
if (!data)
return qreal(1.0);
return data->devicePixelRatio();
}
/*!
Sets the the device pixel ratio for the pixmap. This is the
ratio between image pixels and device-independent pixels.
The default value is 1.0. Setting it to something else has
two effects:
QPainters that are opened on the pixmap will be scaled. For
example, painting on a 200x200 image if with a ratio of 2.0
will result in effective (device-independent) painting bounds
of 100x100.
Code paths in Qt that calculate layout geometry based on the
pixmap size will take the ratio into account:
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio()
The net effect of this is that the pixmap is displayed as
high-dpi pixmap rather than a large pixmap.
\sa devicePixelRatio()
*/
void QPixmap::setDevicePixelRatio(qreal scaleFactor)
{
detach();
data->setDevicePixelRatio(scaleFactor);
}
#ifndef QT_NO_IMAGE_HEURISTIC_MASK #ifndef QT_NO_IMAGE_HEURISTIC_MASK
/*! /*!
Creates and returns a heuristic mask for this pixmap. Creates and returns a heuristic mask for this pixmap.

View File

@ -102,6 +102,9 @@ public:
QBitmap mask() const; QBitmap mask() const;
void setMask(const QBitmap &); void setMask(const QBitmap &);
qreal devicePixelRatio() const;
void setDevicePixelRatio(qreal scaleFactor);
bool hasAlpha() const; bool hasAlpha() const;
bool hasAlphaChannel() const; bool hasAlphaChannel() const;

View File

@ -195,6 +195,16 @@ void QBlittablePlatformPixmap::fromImage(const QImage &image,
} }
} }
qreal QBlittablePlatformPixmap::devicePixelRatio() const
{
return m_devicePixelRatio;
}
void QBlittablePlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
{
m_devicePixelRatio = scaleFactor;
}
QPaintEngine *QBlittablePlatformPixmap::paintEngine() const QPaintEngine *QBlittablePlatformPixmap::paintEngine() const
{ {
if (!m_engine) { if (!m_engine) {

View File

@ -66,6 +66,8 @@ public:
QImage toImage() const; QImage toImage() const;
bool hasAlphaChannel() const; bool hasAlphaChannel() const;
void fromImage(const QImage &image, Qt::ImageConversionFlags flags); void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
qreal devicePixelRatio() const;
void setDevicePixelRatio(qreal scaleFactor);
QPaintEngine *paintEngine() const; QPaintEngine *paintEngine() const;
@ -89,6 +91,7 @@ protected:
QScopedPointer<QBlitterPaintEngine> m_engine; QScopedPointer<QBlitterPaintEngine> m_engine;
QScopedPointer<QBlittable> m_blittable; QScopedPointer<QBlittable> m_blittable;
bool m_alpha; bool m_alpha;
qreal m_devicePixelRatio;
#ifdef QT_BLITTER_RASTEROVERLAY #ifdef QT_BLITTER_RASTEROVERLAY
QImage *m_rasterOverlay; QImage *m_rasterOverlay;

View File

@ -272,12 +272,14 @@ int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
return d->colortable.size(); return d->colortable.size();
case QPaintDevice::PdmDepth: case QPaintDevice::PdmDepth:
return this->d; return this->d;
case QPaintDevice::PdmDpiX: // fall-through case QPaintDevice::PdmDpiX:
case QPaintDevice::PdmPhysicalDpiX: return qt_defaultDpiX();
case QPaintDevice::PdmPhysicalDpiX:
return qt_defaultDpiX() * image.devicePixelRatio();
case QPaintDevice::PdmDpiY:
return qt_defaultDpiX(); return qt_defaultDpiX();
case QPaintDevice::PdmDpiY: // fall-through
case QPaintDevice::PdmPhysicalDpiY: case QPaintDevice::PdmPhysicalDpiY:
return qt_defaultDpiY(); return qt_defaultDpiY() * image.devicePixelRatio();
default: default:
qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric); qWarning("QRasterPlatformPixmap::metric(): Unhandled metric type %d", metric);
break; break;
@ -350,6 +352,7 @@ void QRasterPlatformPixmap::createPixmapForImage(QImage &sourceImage, Qt::ImageC
} }
is_null = (w <= 0 || h <= 0); is_null = (w <= 0 || h <= 0);
image.d->devicePixelRatio = sourceImage.devicePixelRatio();
setSerialNumber(image.cacheKey() >> 32); setSerialNumber(image.cacheKey() >> 32);
} }
@ -358,4 +361,14 @@ QImage* QRasterPlatformPixmap::buffer()
return &image; return &image;
} }
qreal QRasterPlatformPixmap::devicePixelRatio() const
{
return image.devicePixelRatio();
}
void QRasterPlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
{
image.setDevicePixelRatio(scaleFactor);
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -79,6 +79,9 @@ public:
QImage toImage(const QRect &rect) const; QImage toImage(const QRect &rect) const;
QPaintEngine* paintEngine() const; QPaintEngine* paintEngine() const;
QImage* buffer(); QImage* buffer();
qreal devicePixelRatio() const;
void setDevicePixelRatio(qreal scaleFactor);
protected: protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const; int metric(QPaintDevice::PaintDeviceMetric metric) const;

View File

@ -108,6 +108,9 @@ public:
inline PixelType pixelType() const { return type; } inline PixelType pixelType() const { return type; }
inline ClassId classId() const { return static_cast<ClassId>(id); } inline ClassId classId() const { return static_cast<ClassId>(id); }
virtual qreal devicePixelRatio() const = 0;
virtual void setDevicePixelRatio(qreal scaleFactor) = 0;
virtual QImage* buffer(); virtual QImage* buffer();
inline int width() const { return w; } inline int width() const { return w; }

View File

@ -703,7 +703,34 @@ QList<QScreen *> QGuiApplication::screens()
/*! /*!
Returns the top level window at the given position \a pos, if any. Returns the highest screen device pixel ratio found on
the system. This is the ratio between physical pixels and
device-independent pixels.
Use this function only when you don't know which window you are targeting.
If you do know the target window use QWindow::devicePixelRatio() instead.
\sa QWindow::devicePixelRatio();
\sa QGuiApplicaiton::devicePixelRatio();
*/
qreal QGuiApplication::devicePixelRatio() const
{
// Cache topDevicePixelRatio, iterate through the screen list once only.
static qreal topDevicePixelRatio = 0.0;
if (!qFuzzyIsNull(topDevicePixelRatio)) {
return topDevicePixelRatio;
}
topDevicePixelRatio = 1.0; // make sure we never return 0.
foreach (QScreen *screen, QGuiApplicationPrivate::screen_list) {
topDevicePixelRatio = qMax(topDevicePixelRatio, screen->devicePixelRatio());
}
return topDevicePixelRatio;
}
/*!
Returns the top level window at the given position, if any.
*/ */
QWindow *QGuiApplication::topLevelAt(const QPoint &pos) QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
{ {

View File

@ -104,6 +104,7 @@ public:
static QScreen *primaryScreen(); static QScreen *primaryScreen();
static QList<QScreen *> screens(); static QList<QScreen *> screens();
qreal devicePixelRatio() const;
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR
static QCursor *overrideCursor(); static QCursor *overrideCursor();

View File

@ -160,6 +160,18 @@ QDpi QPlatformScreen::logicalDpi() const
25.4 * s.height() / ps.height()); 25.4 * s.height() / ps.height());
} }
/*!
Reimplement this function in subclass to return the device pixel
ratio for the screen. This is the ratio between physical pixels
and device-independent pixels.
\sa QPlatformWindow::devicePixelRatio();
*/
qreal QPlatformScreen::devicePixelRatio() const
{
return 1.0;
}
/*! /*!
Reimplement this function in subclass to return the vertical refresh rate Reimplement this function in subclass to return the vertical refresh rate
of the screen, in Hz. of the screen, in Hz.

View File

@ -98,6 +98,7 @@ public:
virtual QSizeF physicalSize() const; virtual QSizeF physicalSize() const;
virtual QDpi logicalDpi() const; virtual QDpi logicalDpi() const;
virtual qreal devicePixelRatio() const;
virtual qreal refreshRate() const; virtual qreal refreshRate() const;

View File

@ -355,6 +355,18 @@ Qt::ScreenOrientation QPlatformWindow::requestWindowOrientation(Qt::ScreenOrient
return Qt::PrimaryOrientation; return Qt::PrimaryOrientation;
} }
/*!
Reimplement this function in subclass to return the device pixel ratio
for the window. This is the ratio between physical pixels
and device-independent pixels.
\sa QPlatformWindow::devicePixelRatio();
*/
qreal QPlatformWindow::devicePixelRatio() const
{
return 1.0;
}
bool QPlatformWindow::setKeyboardGrabEnabled(bool grab) bool QPlatformWindow::setKeyboardGrabEnabled(bool grab)
{ {
Q_UNUSED(grab); Q_UNUSED(grab);

View File

@ -117,6 +117,8 @@ public:
virtual void handleContentOrientationChange(Qt::ScreenOrientation orientation); virtual void handleContentOrientationChange(Qt::ScreenOrientation orientation);
virtual Qt::ScreenOrientation requestWindowOrientation(Qt::ScreenOrientation orientation); virtual Qt::ScreenOrientation requestWindowOrientation(Qt::ScreenOrientation orientation);
virtual qreal devicePixelRatio() const;
virtual bool setKeyboardGrabEnabled(bool grab); virtual bool setKeyboardGrabEnabled(bool grab);
virtual bool setMouseGrabEnabled(bool grab); virtual bool setMouseGrabEnabled(bool grab);

View File

@ -214,6 +214,20 @@ qreal QScreen::logicalDotsPerInch() const
return (dpi.first + dpi.second) * qreal(0.5); return (dpi.first + dpi.second) * qreal(0.5);
} }
/*
Returns the ratio between physical pixels and device-independent pixels for the screen.
Common values are 1.0 on normal displays and 2.0 on Apple retina displays.
\sa QWindow::devicePixelRatio();
\sa QGuiApplicaiton::devicePixelRatio();
*/
qreal QScreen::devicePixelRatio() const
{
Q_D(const QScreen);
return d->platformScreen->devicePixelRatio();
}
/*! /*!
\property QScreen::physicalSize \property QScreen::physicalSize
\brief the screen's physical size (in millimeters) \brief the screen's physical size (in millimeters)

View File

@ -109,6 +109,8 @@ public:
qreal logicalDotsPerInchY() const; qreal logicalDotsPerInchY() const;
qreal logicalDotsPerInch() const; qreal logicalDotsPerInch() const;
qreal devicePixelRatio() const;
QSize availableSize() const; QSize availableSize() const;
QRect availableGeometry() const; QRect availableGeometry() const;

View File

@ -805,6 +805,24 @@ Qt::ScreenOrientation QWindow::orientation() const
return d->windowOrientation; return d->windowOrientation;
} }
/*!
Returns the ratio between physical pixels and device-independent pixels
for the window. This value is dependent on the screen the window is on,
and may change when the window is moved.
Common values are 1.0 on normal displays and 2.0 on Apple "retina" displays.
\sa QWindow::devicePixelRatio();
\sa QGuiApplicaiton::devicePixelRatio();
*/
qreal QWindow::devicePixelRatio() const
{
Q_D(const QWindow);
if (!d->platformWindow)
return 1.0;
return d->platformWindow->devicePixelRatio();
}
/*! /*!
\brief set the screen-occupation state of the window \brief set the screen-occupation state of the window

View File

@ -184,6 +184,8 @@ public:
void reportContentOrientationChange(Qt::ScreenOrientation orientation); void reportContentOrientationChange(Qt::ScreenOrientation orientation);
Qt::ScreenOrientation contentOrientation() const; Qt::ScreenOrientation contentOrientation() const;
qreal devicePixelRatio() const;
bool requestOrientation(Qt::ScreenOrientation orientation); bool requestOrientation(Qt::ScreenOrientation orientation);
Qt::ScreenOrientation orientation() const; Qt::ScreenOrientation orientation() const;

View File

@ -1072,10 +1072,12 @@ void QRasterPaintEnginePrivate::systemStateChanged()
exDeviceRect = deviceRect; exDeviceRect = deviceRect;
Q_Q(QRasterPaintEngine); Q_Q(QRasterPaintEngine);
if (q->state()) {
q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion; q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
q->state()->fillFlags |= QPaintEngine::DirtyClipRegion; q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion; q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
} }
}
void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m) void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
{ {
@ -2143,9 +2145,10 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
Q_D(QRasterPaintEngine); Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state(); QRasterPaintEngineState *s = state();
qreal scale = img.devicePixelRatio();
if (s->matrix.type() > QTransform::TxTranslate) { if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) {
drawImage(QRectF(p.x(), p.y(), img.width(), img.height()), drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
img, img,
QRectF(0, 0, img.width(), img.height())); QRectF(0, 0, img.width(), img.height()));
} else { } else {
@ -2349,6 +2352,22 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
return; return;
} }
} else { } else {
// Test for optimized high-dpi case: 2x source on 2x target. (Could be generalized to nX.)
bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
if (func) {
QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
if (!clip) {
d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
return;
} else if (clip->hasRectClip) {
d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
return;
}
}
}
SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()]; SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
if (func && (!clip || clip->hasRectClip)) { if (func && (!clip || clip->hasRectClip)) {
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),

View File

@ -939,12 +939,12 @@ void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDr
void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm) void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm)
{ {
drawPixmap(QRectF(pos, pm.size()), pm, pm.rect()); drawPixmap(QRectF(pos, pm.size() / pm.devicePixelRatio()), pm, pm.rect());
} }
void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image) void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image)
{ {
drawImage(QRectF(pos, image.size()), image, image.rect()); drawImage(QRectF(pos, image.size() / image.devicePixelRatio()), image, image.rect());
} }
void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)

View File

@ -225,6 +225,18 @@ QTransform QPainterPrivate::viewTransform() const
return QTransform(); return QTransform();
} }
QTransform QPainterPrivate::hidpiScaleTransform() const
{
#ifdef Q_OS_MAC
// Limited feature introduction for Qt 5.0.0, remove ifdef in a later release.
if (device->physicalDpiX() == 0 || device->logicalDpiX() == 0)
return QTransform();
const qreal deviceScale = (device->physicalDpiX() / device->logicalDpiX());
if (deviceScale > 1.0)
return QTransform::fromScale(deviceScale, deviceScale);
#endif
return QTransform();
}
/* /*
\internal \internal
@ -641,6 +653,8 @@ void QPainterPrivate::updateMatrix()
else else
state->dirtyFlags |= QPaintEngine::DirtyTransform; state->dirtyFlags |= QPaintEngine::DirtyTransform;
state->matrix *= hidpiScaleTransform();
// printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF); // printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
// qDebug() << " --- using matrix" << state->matrix << redirection_offset; // qDebug() << " --- using matrix" << state->matrix << redirection_offset;
} }
@ -1827,7 +1841,14 @@ bool QPainter::begin(QPaintDevice *pd)
Q_ASSERT(d->engine->isActive()); Q_ASSERT(d->engine->isActive());
if (!d->state->redirectionMatrix.isIdentity()) #ifdef Q_OS_MAC
// Limited feature introduction for Qt 5.0.0, remove ifdef in a later release.
const bool isHighDpi = (d->device->physicalDpiX() == 0 || d->device->logicalDpiX() == 0) ?
false : (d->device->physicalDpiX() / d->device->logicalDpiX() > 1);
#else
const bool isHighDpi = false;
#endif
if (!d->state->redirectionMatrix.isIdentity() || isHighDpi)
d->updateMatrix(); d->updateMatrix();
Q_ASSERT(d->engine->isActive()); Q_ASSERT(d->engine->isActive());
@ -5092,7 +5113,8 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
x += d->state->matrix.dx(); x += d->state->matrix.dx();
y += d->state->matrix.dy(); y += d->state->matrix.dy();
} }
d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(0, 0, w, h)); int scale = pm.devicePixelRatio();
d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
} }
} }
@ -5122,6 +5144,11 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
qreal sw = sr.width(); qreal sw = sr.width();
qreal sh = sr.height(); qreal sh = sr.height();
// Get pixmap scale. Use it when calculating the target
// rect size from pixmap size. For example, a 2X 64x64 pixel
// pixmap should result in a 32x32 point target rect.
const qreal pmscale = pm.devicePixelRatio();
// Sanity-check clipping // Sanity-check clipping
if (sw <= 0) if (sw <= 0)
sw = pm.width() - sx; sw = pm.width() - sx;
@ -5130,9 +5157,9 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
sh = pm.height() - sy; sh = pm.height() - sy;
if (w < 0) if (w < 0)
w = sw; w = sw / pmscale;
if (h < 0) if (h < 0)
h = sh; h = sh / pmscale;
if (sx < 0) { if (sx < 0) {
qreal w_ratio = sx * w/sw; qreal w_ratio = sx * w/sw;
@ -5345,6 +5372,7 @@ void QPainter::drawImage(const QPointF &p, const QImage &image)
int w = image.width(); int w = image.width();
int h = image.height(); int h = image.height();
qreal scale = image.devicePixelRatio();
d->updateState(d->state); d->updateState(d->state);
@ -5368,8 +5396,7 @@ void QPainter::drawImage(const QPointF &p, const QImage &image)
setBrush(brush); setBrush(brush);
setPen(Qt::NoPen); setPen(Qt::NoPen);
setBrushOrigin(QPointF(0, 0)); setBrushOrigin(QPointF(0, 0));
drawRect(QRect(QPoint(0, 0), image.size() / scale));
drawRect(image.rect());
restore(); restore();
return; return;
} }
@ -5380,7 +5407,7 @@ void QPainter::drawImage(const QPointF &p, const QImage &image)
y += d->state->matrix.dy(); y += d->state->matrix.dy();
} }
d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(0, 0, w, h), Qt::AutoColor); d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
} }
void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
@ -5399,6 +5426,7 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR
qreal sy = sourceRect.y(); qreal sy = sourceRect.y();
qreal sw = sourceRect.width(); qreal sw = sourceRect.width();
qreal sh = sourceRect.height(); qreal sh = sourceRect.height();
qreal imageScale = image.devicePixelRatio();
// Sanity-check clipping // Sanity-check clipping
if (sw <= 0) if (sw <= 0)
@ -5408,9 +5436,9 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR
sh = image.height() - sy; sh = image.height() - sy;
if (w < 0) if (w < 0)
w = sw; w = sw / imageScale;
if (h < 0) if (h < 0)
h = sh; h = sh / imageScale;
if (sx < 0) { if (sx < 0) {
qreal w_ratio = sx * w/sw; qreal w_ratio = sx * w/sw;
@ -8235,7 +8263,7 @@ QTransform QPainter::combinedTransform() const
qWarning("QPainter::combinedTransform: Painter not active"); qWarning("QPainter::combinedTransform: Painter not active");
return QTransform(); return QTransform();
} }
return d->state->worldMatrix * d->viewTransform(); return d->state->worldMatrix * d->viewTransform() * d->hidpiScaleTransform();
} }
/*! /*!

View File

@ -249,6 +249,7 @@ public:
} }
QTransform viewTransform() const; QTransform viewTransform() const;
QTransform hidpiScaleTransform() const;
static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev);
void detachPainterPrivate(QPainter *q); void detachPainterPrivate(QPainter *q);

View File

@ -4100,7 +4100,9 @@ void QGLWidget::glDraw()
#endif #endif
if (!d->glcx->initialized()) { if (!d->glcx->initialized()) {
glInit(); glInit();
resizeGL(d->glcx->device()->width(), d->glcx->device()->height()); // New context needs this "resize" const qreal scaleFactor = (window() && window()->windowHandle()) ?
window()->windowHandle()->devicePixelRatio() : 1.0;
resizeGL(d->glcx->device()->width() * scaleFactor, d->glcx->device()->height() * scaleFactor); // New context needs this "resize"
} }
paintGL(); paintGL();
if (doubleBuffer()) { if (doubleBuffer()) {

View File

@ -370,7 +370,10 @@ void QGLWidget::resizeEvent(QResizeEvent *e)
makeCurrent(); makeCurrent();
if (!d->glcx->initialized()) if (!d->glcx->initialized())
glInit(); glInit();
resizeGL(width(), height()); const qreal scaleFactor = (window() && window()->windowHandle()) ?
window()->windowHandle()->devicePixelRatio() : 1.0;
resizeGL(width() * scaleFactor, height() * scaleFactor);
} }

View File

@ -62,6 +62,7 @@ public:
void resize (const QSize &size, const QRegion &); void resize (const QSize &size, const QRegion &);
bool scroll(const QRegion &area, int dx, int dy); bool scroll(const QRegion &area, int dx, int dy);
CGImageRef getBackingStoreCGImage(); CGImageRef getBackingStoreCGImage();
qreal getBackingStoreDevicePixelRatio();
private: private:
QImage m_qImage; QImage m_qImage;

View File

@ -59,10 +59,22 @@ QCocoaBackingStore::~QCocoaBackingStore()
QPaintDevice *QCocoaBackingStore::paintDevice() QPaintDevice *QCocoaBackingStore::paintDevice()
{ {
if (m_qImage.size() != m_requestedSize) { if (m_qImage.size() / m_qImage.devicePixelRatio() != m_requestedSize) {
CGImageRelease(m_cgImage); CGImageRelease(m_cgImage);
m_cgImage = 0; m_cgImage = 0;
m_qImage = QImage(m_requestedSize, QImage::Format_ARGB32_Premultiplied);
int scaleFactor = 1;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle());
if (cocoaWindow && cocoaWindow->m_contentView) {
scaleFactor = int([[cocoaWindow->m_contentView window] backingScaleFactor]);
}
}
#endif
m_qImage = QImage(m_requestedSize * scaleFactor, QImage::Format_ARGB32_Premultiplied);
m_qImage.setDevicePixelRatio(scaleFactor);
} }
return &m_qImage; return &m_qImage;
} }
@ -90,10 +102,11 @@ void QCocoaBackingStore::resize(const QSize &size, const QRegion &)
bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy) bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy)
{ {
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
QPoint qpoint(dx, dy); const qreal devicePixelRatio = m_qImage.devicePixelRatio();
QPoint qpoint(dx * devicePixelRatio, dy * devicePixelRatio);
const QVector<QRect> qrects = area.rects(); const QVector<QRect> qrects = area.rects();
for (int i = 0; i < qrects.count(); ++i) { for (int i = 0; i < qrects.count(); ++i) {
const QRect &qrect = qrects.at(i); const QRect &qrect = QRect(qrects.at(i).topLeft() * devicePixelRatio, qrects.at(i).size() * devicePixelRatio);
qt_scrollRectInImage(m_qImage, qrect, qpoint); qt_scrollRectInImage(m_qImage, qrect, qpoint);
} }
return true; return true;
@ -110,4 +123,9 @@ CGImageRef QCocoaBackingStore::getBackingStoreCGImage()
return m_cgImage; return m_cgImage;
} }
qreal QCocoaBackingStore::getBackingStoreDevicePixelRatio()
{
return m_qImage.devicePixelRatio();
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -114,6 +114,18 @@ void QCocoaGLContext::setActiveWindow(QWindow *window)
cocoaWindow->setCurrentContext(this); cocoaWindow->setCurrentContext(this);
[(QNSView *) cocoaWindow->contentView() setQCocoaGLContext:this]; [(QNSView *) cocoaWindow->contentView() setQCocoaGLContext:this];
// Enable high-dpi OpenGL for retina displays. Enabling has the side
// effect that Cooca will start calling glViewport(0, 0, width, height),
// overriding any glViewport calls in application code. This is usually not a
// problem, except if the applcation wants to have a "custom" viewport.
// (like the hellogl example)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
if (cocoaWindow->devicePixelRatio() > 1)
[cocoaWindow->contentView() setWantsBestResolutionOpenGLSurface:YES];
}
#endif
} }
void QCocoaGLContext::doneCurrent() void QCocoaGLContext::doneCurrent()

View File

@ -68,6 +68,7 @@ public:
QRect availableGeometry() const { return m_availableGeometry; } QRect availableGeometry() const { return m_availableGeometry; }
int depth() const { return m_depth; } int depth() const { return m_depth; }
QImage::Format format() const { return m_format; } QImage::Format format() const { return m_format; }
qreal devicePixelRatio() const;
QSizeF physicalSize() const { return m_physicalSize; } QSizeF physicalSize() const { return m_physicalSize; }
QDpi logicalDpi() const { return m_logicalDpi; } QDpi logicalDpi() const { return m_logicalDpi; }
qreal refreshRate() const { return m_refreshRate; } qreal refreshRate() const { return m_refreshRate; }

View File

@ -115,6 +115,18 @@ void QCocoaScreen::updateGeometry()
QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry()); QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry());
} }
qreal QCocoaScreen::devicePixelRatio() const
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
return qreal([m_screen backingScaleFactor]);
} else
#endif
{
return 1.0;
}
}
extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev);
QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const

View File

@ -140,6 +140,8 @@ public:
void setMenubar(QCocoaMenuBar *mb); void setMenubar(QCocoaMenuBar *mb);
QCocoaMenuBar *menubar() const; QCocoaMenuBar *menubar() const;
qreal devicePixelRatio() const;
protected: protected:
// NSWindow handling. The QCocoaWindow/QNSView can either be displayed // NSWindow handling. The QCocoaWindow/QNSView can either be displayed
// in an existing NSWindow or in one created by Qt. // in an existing NSWindow or in one created by Qt.

View File

@ -39,6 +39,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include "qcocoawindow.h" #include "qcocoawindow.h"
#include "qcocoaintegration.h"
#include "qnswindowdelegate.h" #include "qnswindowdelegate.h"
#include "qcocoaautoreleasepool.h" #include "qcocoaautoreleasepool.h"
#include "qcocoaeventdispatcher.h" #include "qcocoaeventdispatcher.h"
@ -820,6 +821,20 @@ QCocoaMenuBar *QCocoaWindow::menubar() const
return m_menubar; return m_menubar;
} }
qreal QCocoaWindow::devicePixelRatio() const
{
if (!m_nsWindow)
return 1.0;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
return qreal([m_nsWindow backingScaleFactor]);
} else
#endif
{
return 1.0;
}
}
QMargins QCocoaWindow::frameMargins() const QMargins QCocoaWindow::frameMargins() const
{ {
NSRect frameW = [m_nsWindow frame]; NSRect frameW = [m_nsWindow frame];

View File

@ -244,7 +244,7 @@ static QTouchDevice *touchDevice = 0;
- (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset - (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
{ {
m_backingStore = backingStore; m_backingStore = backingStore;
m_backingStoreOffset = offset; m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
QRect br = region.boundingRect(); QRect br = region.boundingRect();
[self setNeedsDisplayInRect:NSMakeRect(br.x(), br.y(), br.width(), br.height())]; [self setNeedsDisplayInRect:NSMakeRect(br.x(), br.y(), br.width(), br.height())];
} }
@ -275,33 +275,44 @@ static QTouchDevice *touchDevice = 0;
if (!m_backingStore) if (!m_backingStore)
return; return;
CGRect dirtyCGRect = NSRectToCGRect(dirtyRect); // Calculate source and target rects. The target rect is the dirtyRect:
CGRect dirtyWindowRect = NSRectToCGRect(dirtyRect);
// The backing store source rect will be larger on retina displays.
// Scale dirtyRect by the device pixel ratio:
const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio();
CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio,
dirtyRect.origin.y * devicePixelRatio,
dirtyRect.size.width * devicePixelRatio,
dirtyRect.size.height * devicePixelRatio);
NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext]; NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort]; CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort];
// Translate coordiate system from CoreGraphics (bottom-left) to NSView (top-left): // Translate coordiate system from CoreGraphics (bottom-left) to NSView (top-left):
CGContextSaveGState(cgContext); CGContextSaveGState(cgContext);
int dy = dirtyCGRect.origin.y + CGRectGetMaxY(dirtyCGRect); int dy = dirtyWindowRect.origin.y + CGRectGetMaxY(dirtyWindowRect);
CGContextTranslateCTM(cgContext, 0, dy); CGContextTranslateCTM(cgContext, 0, dy);
CGContextScaleCTM(cgContext, 1, -1); CGContextScaleCTM(cgContext, 1, -1);
// If a mask is set, modify the sub image accordingly: // If a mask is set, modify the sub image accordingly:
CGImageRef subMask = 0; CGImageRef subMask = 0;
if (m_maskImage) { if (m_maskImage) {
subMask = CGImageCreateWithImageInRect(m_maskImage, dirtyCGRect); subMask = CGImageCreateWithImageInRect(m_maskImage, dirtyWindowRect);
CGContextClipToMask(cgContext, dirtyCGRect, subMask); CGContextClipToMask(cgContext, dirtyWindowRect, subMask);
} }
// Clip out and draw the correct sub image from the (shared) backingstore: // Clip out and draw the correct sub image from the (shared) backingstore:
CGRect backingStoreRect = CGRectMake( CGRect backingStoreRect = CGRectMake(
dirtyRect.origin.x + m_backingStoreOffset.x(), dirtyBackingRect.origin.x + m_backingStoreOffset.x(),
dirtyRect.origin.y + m_backingStoreOffset.y(), dirtyBackingRect.origin.y + m_backingStoreOffset.y(),
dirtyRect.size.width, dirtyBackingRect.size.width,
dirtyRect.size.height dirtyBackingRect.size.height
); );
CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage(); CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage();
CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect); CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
CGContextDrawImage(cgContext, dirtyCGRect, cleanImg); CGContextDrawImage(cgContext, dirtyWindowRect, cleanImg);
// Clean-up: // Clean-up:
CGContextRestoreGState(cgContext); CGContextRestoreGState(cgContext);

View File

@ -1060,10 +1060,12 @@ QRect QItemDelegate::rect(const QStyleOptionViewItem &option,
switch (value.type()) { switch (value.type()) {
case QVariant::Invalid: case QVariant::Invalid:
break; break;
case QVariant::Pixmap: case QVariant::Pixmap: {
return QRect(QPoint(0, 0), qvariant_cast<QPixmap>(value).size()); const QPixmap &pixmap = qvariant_cast<QPixmap>(value);
case QVariant::Image: return QRect(QPoint(0, 0), pixmap.size() / pixmap.devicePixelRatio() ); }
return QRect(QPoint(0, 0), qvariant_cast<QImage>(value).size()); case QVariant::Image: {
const QImage &image = qvariant_cast<QImage>(value);
return QRect(QPoint(0, 0), image.size() / image.devicePixelRatio() ); }
case QVariant::Icon: { case QVariant::Icon: {
QIcon::Mode mode = d->iconMode(option.state); QIcon::Mode mode = d->iconMode(option.state);
QIcon::State state = d->iconState(option.state); QIcon::State state = d->iconState(option.state);

View File

@ -1794,6 +1794,23 @@ QRegion QWidgetPrivate::clipRegion() const
return r; return r;
} }
void QWidgetPrivate::setSystemClip(QPaintDevice *paintDevice, const QRegion &region)
{
// Transform the system clip region from device-independent pixels to device pixels
// Qt 5.0.0: This is a Mac-only code path for now, can be made cross-platform once
// it has been tested.
QPaintEngine *paintEngine = paintDevice->paintEngine();
#ifdef Q_OS_MAC
const qreal devicePixelRatio = (paintDevice->physicalDpiX() == 0 || paintDevice->logicalDpiX() == 0) ?
1.0 : (paintDevice->physicalDpiX() / paintDevice->logicalDpiX());
QTransform scaleTransform;
scaleTransform.scale(devicePixelRatio, devicePixelRatio);
paintEngine->d_func()->systemClip = scaleTransform.map(region);
#else
paintEngine->d_func()->systemClip = region;
#endif
}
#ifndef QT_NO_GRAPHICSEFFECT #ifndef QT_NO_GRAPHICSEFFECT
void QWidgetPrivate::invalidateGraphicsEffectsRecursively() void QWidgetPrivate::invalidateGraphicsEffectsRecursively()
{ {
@ -4998,13 +5015,12 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
QWidgetPaintContext context(pdev, rgn, offset, flags, sharedPainter, backingStore); QWidgetPaintContext context(pdev, rgn, offset, flags, sharedPainter, backingStore);
sourced->context = &context; sourced->context = &context;
if (!sharedPainter) { if (!sharedPainter) {
QPaintEngine *paintEngine = pdev->paintEngine(); setSystemClip(pdev, rgn.translated(offset));
paintEngine->d_func()->systemClip = rgn.translated(offset);
QPainter p(pdev); QPainter p(pdev);
p.translate(offset); p.translate(offset);
context.painter = &p; context.painter = &p;
graphicsEffect->draw(&p); graphicsEffect->draw(&p);
paintEngine->d_func()->systemClip = QRegion(); setSystemClip(pdev, QRegion());
} else { } else {
context.painter = sharedPainter; context.painter = sharedPainter;
if (sharedPainter->worldTransform() != sourced->lastEffectTransform) { if (sharedPainter->worldTransform() != sourced->lastEffectTransform) {
@ -5061,7 +5077,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
#endif #endif
if (sharedPainter) if (sharedPainter)
paintEngine->d_func()->systemClip = toBePainted; setSystemClip(pdev, toBePainted);
else else
paintEngine->d_func()->systemRect = q->data->crect; paintEngine->d_func()->systemRect = q->data->crect;
@ -5073,7 +5089,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
} }
if (!sharedPainter) if (!sharedPainter)
paintEngine->d_func()->systemClip = toBePainted.translated(offset); setSystemClip(pdev, toBePainted.translated(offset));
if (!onScreen && !asRoot && !isOpaque && q->testAttribute(Qt::WA_TintedBackground)) { if (!onScreen && !asRoot && !isOpaque && q->testAttribute(Qt::WA_TintedBackground)) {
QPainter p(q); QPainter p(q);
@ -5108,7 +5124,8 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
paintEngine->d_func()->systemRect = QRect(); paintEngine->d_func()->systemRect = QRect();
else else
paintEngine->d_func()->currentClipDevice = 0; paintEngine->d_func()->currentClipDevice = 0;
paintEngine->d_func()->systemClip = QRegion();
setSystemClip(pdev, QRegion());
} }
q->setAttribute(Qt::WA_WState_InPaintEvent, false); q->setAttribute(Qt::WA_WState_InPaintEvent, false);
if (q->paintingActive()) if (q->paintingActive())

View File

@ -402,6 +402,7 @@ public:
QRect clipRect() const; QRect clipRect() const;
QRegion clipRegion() const; QRegion clipRegion() const;
void setSystemClip(QPaintDevice *paintDevice, const QRegion &region);
void subtractOpaqueChildren(QRegion &rgn, const QRect &clipRect) const; void subtractOpaqueChildren(QRegion &rgn, const QRect &clipRect) const;
void subtractOpaqueSiblings(QRegion &source, bool *hasDirtySiblingsAbove = 0, void subtractOpaqueSiblings(QRegion &source, bool *hasDirtySiblingsAbove = 0,
bool alsoNonOpaque = false) const; bool alsoNonOpaque = false) const;

View File

@ -303,7 +303,7 @@ static void qt_fusion_draw_mdibutton(QPainter *painter, const QStyleOptionTitleB
gradient.setColorAt(1, mdiButtonGradientStopColor); gradient.setColorAt(1, mdiButtonGradientStopColor);
QColor mdiButtonBorderColor(active ? option->palette.highlight().color().darker(180): dark.darker(110)); QColor mdiButtonBorderColor(active ? option->palette.highlight().color().darker(180): dark.darker(110));
painter->setPen(QPen(mdiButtonBorderColor, 1)); painter->setPen(QPen(mdiButtonBorderColor));
const QLine lines[4] = { const QLine lines[4] = {
QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()), QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()),
QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()), QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()),
@ -457,7 +457,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (const QStyleOptionTabBarBase *tbb if (const QStyleOptionTabBarBase *tbb
= qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) { = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
painter->save(); painter->save();
painter->setPen(QPen(outline.lighter(110), 0)); painter->setPen(QPen(outline.lighter(110)));
switch (tbb->shape) { switch (tbb->shape) {
case QTabBar::RoundedNorth: { case QTabBar::RoundedNorth: {
QRegion region(tbb->rect); QRegion region(tbb->rect);
@ -603,7 +603,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
} }
} }
break; break;
case PE_Frame: case PE_Frame: {
if (widget && widget->inherits("QComboBoxPrivateContainer")){ if (widget && widget->inherits("QComboBoxPrivateContainer")){
QStyleOption copy = *option; QStyleOption copy = *option;
copy.state |= State_Raised; copy.state |= State_Raised;
@ -611,14 +611,16 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
break; break;
} }
painter->save(); painter->save();
painter->setPen(outline.lighter(108)); QPen thePen(outline.lighter(108));
thePen.setCosmetic(false);
painter->setPen(thePen);
painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
painter->restore(); painter->restore(); }
break; break;
case PE_FrameMenu: case PE_FrameMenu:
painter->save(); painter->save();
{ {
painter->setPen(QPen(outline, 1)); painter->setPen(QPen(outline));
painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
QColor frameLight = option->palette.background().color().lighter(160); QColor frameLight = option->palette.background().color().lighter(160);
QColor frameShadow = option->palette.background().color().darker(110); QColor frameShadow = option->palette.background().color().darker(110);
@ -644,9 +646,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
QRect rect= option->rect; QRect rect= option->rect;
painter->setPen(softshadow); painter->setPen(softshadow);
painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
painter->setPen(QPen(option->palette.light(), 0)); painter->setPen(QPen(option->palette.light(), 1));
painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), QPoint(rect.left() + 1, rect.bottom() - 1)); painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), QPoint(rect.left() + 1, rect.bottom() - 1));
painter->setPen(QPen(option->palette.background().color().darker(120), 0)); painter->setPen(QPen(option->palette.background().color().darker(120)));
painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), QPoint(rect.right() - 2, rect.bottom() - 1)); painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), QPoint(rect.right() - 2, rect.bottom() - 1));
painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), QPoint(rect.right() - 1, rect.bottom() - 1)); painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), QPoint(rect.right() - 1, rect.bottom() - 1));
@ -680,12 +682,12 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
painter->save(); painter->save();
{ {
QRect rect= option->rect; QRect rect= option->rect;
painter->setPen(QPen(outline.darker(150), 0)); painter->setPen(QPen(outline.darker(150)));
painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
painter->setPen(QPen(option->palette.light(), 0)); painter->setPen(QPen(option->palette.light(), 1));
painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1),
QPoint(rect.left() + 1, rect.bottom() - 1)); QPoint(rect.left() + 1, rect.bottom() - 1));
painter->setPen(QPen(option->palette.background().color().darker(120), 0)); painter->setPen(QPen(option->palette.background().color().darker(120)));
painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1),
QPoint(rect.right() - 2, rect.bottom() - 1)); QPoint(rect.right() - 2, rect.bottom() - 1));
painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1),
@ -705,7 +707,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
painter->translate(0.5, 0.5); painter->translate(0.5, 0.5);
// Draw Outline // Draw Outline
painter->setPen( QPen(hasFocus ? highlightedOutline : outline, 0)); painter->setPen( QPen(hasFocus ? highlightedOutline : outline));
painter->setBrush(option->palette.base()); painter->setBrush(option->palette.base());
painter->drawRoundedRect(r.adjusted(0, 0, -1, -1), 2, 2); painter->drawRoundedRect(r.adjusted(0, 0, -1, -1), 2, 2);
@ -740,10 +742,10 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
gradient.setColorAt(1, (state & State_Sunken) ? pressedColor : option->palette.base().color()); gradient.setColorAt(1, (state & State_Sunken) ? pressedColor : option->palette.base().color());
painter->setBrush((state & State_Sunken) ? QBrush(pressedColor) : gradient); painter->setBrush((state & State_Sunken) ? QBrush(pressedColor) : gradient);
painter->setPen(QPen(outline.lighter(110), 1)); painter->setPen(QPen(outline.lighter(110)));
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
painter->setPen(QPen(highlightedOutline, 1)); painter->setPen(QPen(highlightedOutline));
painter->drawRect(rect); painter->drawRect(rect);
QColor checkMarkColor = option->palette.text().color().darker(120); QColor checkMarkColor = option->palette.text().color().darker(120);
@ -785,9 +787,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
painter->setRenderHint(QPainter::Antialiasing, true); painter->setRenderHint(QPainter::Antialiasing, true);
QPainterPath circle; QPainterPath circle;
circle.addEllipse(rect.center() + QPoint(1.0, 1.0), 6.5, 6.5); circle.addEllipse(rect.center() + QPoint(1.0, 1.0), 6.5, 6.5);
painter->setPen(QPen(option->palette.background().color().darker(150), 1)); painter->setPen(QPen(option->palette.background().color().darker(150)));
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
painter->setPen(QPen(highlightedOutline, 1)); painter->setPen(QPen(highlightedOutline));
painter->drawPath(circle); painter->drawPath(circle);
if (state & (State_On )) { if (state & (State_On )) {
@ -862,7 +864,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (isFlat && !isDown) { if (isFlat && !isDown) {
if (isDefault) { if (isDefault) {
r = option->rect.adjusted(0, 1, 0, -1); r = option->rect.adjusted(0, 1, 0, -1);
painter->setPen(QPen(Qt::black, 0)); painter->setPen(QPen(Qt::black));
const QLine lines[4] = { const QLine lines[4] = {
QLine(QPoint(r.left() + 2, r.top()), QLine(QPoint(r.left() + 2, r.top()),
QPoint(r.right() - 2, r.top())), QPoint(r.right() - 2, r.top())),
@ -910,7 +912,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
p->setBrush(Qt::NoBrush); p->setBrush(Qt::NoBrush);
// Outline // Outline
p->setPen(!isEnabled ? QPen(darkOutline.lighter(115)) : QPen(darkOutline, 1)); p->setPen(!isEnabled ? QPen(darkOutline.lighter(115)) : QPen(darkOutline));
p->drawRoundedRect(r, 2.0, 2.0); p->drawRoundedRect(r, 2.0, 2.0);
p->setPen(d->innerContrastLine()); p->setPen(d->innerContrastLine());
@ -1300,7 +1302,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
painter->drawLine(rect.topLeft() - QPoint(0, 1), rect.topRight() - QPoint(0, 1)); painter->drawLine(rect.topLeft() - QPoint(0, 1), rect.topRight() - QPoint(0, 1));
painter->setBrush(option->palette.base()); painter->setBrush(option->palette.base());
painter->setPen(QPen(outline, 0)); painter->setPen(QPen(outline));
painter->drawRoundedRect(rect.adjusted(0, 0, -1, -1), 2, 2); painter->drawRoundedRect(rect.adjusted(0, 0, -1, -1), 2, 2);
// Inner shadow // Inner shadow
@ -1359,14 +1361,14 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
progressBar.setRect(rect.left(), rect.top(), width - 1, rect.height() - 1); progressBar.setRect(rect.left(), rect.top(), width - 1, rect.height() - 1);
if (!complete) { if (!complete) {
painter->drawLine(progressBar.topRight() + QPoint(2, 1), progressBar.bottomRight() + QPoint(2, 0)); painter->drawLine(progressBar.topRight() + QPoint(2, 1), progressBar.bottomRight() + QPoint(2, 0));
painter->setPen(QPen(highlight.darker(140), 0)); painter->setPen(QPen(highlight.darker(140)));
painter->drawLine(progressBar.topRight() + QPoint(1, 1), progressBar.bottomRight() + QPoint(1, 0)); painter->drawLine(progressBar.topRight() + QPoint(1, 1), progressBar.bottomRight() + QPoint(1, 0));
} }
} else { } else {
progressBar.setRect(rect.right() - width - 1, rect.top(), width + 2, rect.height() - 1); progressBar.setRect(rect.right() - width - 1, rect.top(), width + 2, rect.height() - 1);
if (!complete) { if (!complete) {
painter->drawLine(progressBar.topLeft() + QPoint(-2, 1), progressBar.bottomLeft() + QPoint(-2, 0)); painter->drawLine(progressBar.topLeft() + QPoint(-2, 1), progressBar.bottomLeft() + QPoint(-2, 0));
painter->setPen(QPen(highlight.darker(140), 0)); painter->setPen(QPen(highlight.darker(140)));
painter->drawLine(progressBar.topLeft() + QPoint(-1, 1), progressBar.bottomLeft() + QPoint(-1, 0)); painter->drawLine(progressBar.topLeft() + QPoint(-1, 1), progressBar.bottomLeft() + QPoint(-1, 0));
} }
} }
@ -1376,7 +1378,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
if (indeterminate || bar->progress > bar->minimum) { if (indeterminate || bar->progress > bar->minimum) {
painter->setPen(QPen(outline, 0)); painter->setPen(QPen(outline));
QColor highlightedGradientStartColor = highlight.lighter(120); QColor highlightedGradientStartColor = highlight.lighter(120);
QColor highlightedGradientStopColor = highlight; QColor highlightedGradientStopColor = highlight;
@ -1471,7 +1473,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
QRect r = option->rect; QRect r = option->rect;
if (act) { if (act) {
painter->setBrush(option->palette.highlight().color()); painter->setBrush(option->palette.highlight().color());
painter->setPen(QPen(highlightOutline, 0)); painter->setPen(QPen(highlightOutline));
painter->drawRect(r.adjusted(0, 0, -1, -1)); painter->drawRect(r.adjusted(0, 0, -1, -1));
// painter->drawRoundedRect(r.adjusted(1, 1, -1, -1), 2, 2); // painter->drawRoundedRect(r.adjusted(1, 1, -1, -1), 2, 2);
@ -1518,7 +1520,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
if (selected) { if (selected) {
QRect r = option->rect; QRect r = option->rect;
painter->fillRect(r, highlight); painter->fillRect(r, highlight);
painter->setPen(QPen(highlightOutline, 0)); painter->setPen(QPen(highlightOutline));
const QLine lines[4] = { const QLine lines[4] = {
QLine(QPoint(r.left() + 1, r.bottom()), QPoint(r.right() - 1, r.bottom())), QLine(QPoint(r.left() + 1, r.bottom()), QPoint(r.right() - 1, r.bottom())),
QLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top())), QLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top())),
@ -2141,15 +2143,18 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
QPixmap upArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), QPixmap upArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"),
(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) ? arrowColor : disabledColor); (spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) ? arrowColor : disabledColor);
cachePainter.drawPixmap(QRect(upRect.center().x() - upArrow.width() / 4 + 1, QRectF upArrowRect = QRectF(upRect.center().x() - upArrow.width() / 4.0 + 1.0,
upRect.center().y() - upArrow.height() / 4 + 1, upRect.center().y() - upArrow.height() / 4.0 + 1.0,
upArrow.width()/2, upArrow.height()/2), upArrow); upArrow.width() / 2.0, upArrow.height() / 2.0);
cachePainter.drawPixmap(upArrowRect, upArrow, QRectF(QPointF(0.0, 0.0), upArrow.size()));
QPixmap downArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), QPixmap downArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"),
(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) ? arrowColor : disabledColor, 180); (spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) ? arrowColor : disabledColor, 180);
cachePainter.drawPixmap(QRect(downRect.center().x() - downArrow.width() / 4 + 1, QRectF downArrowRect = QRectF(downRect.center().x() - downArrow.width() / 4.0 + 1.0,
downRect.center().y() - downArrow.height() / 4 + 1, downRect.center().y() - downArrow.height() / 4.0 + 1.0,
downArrow.width()/2, downArrow.height()/2), downArrow); downArrow.width() / 2.0, downArrow.height() / 2.0);
cachePainter.drawPixmap(downArrowRect, downArrow, QRectF(QPointF(0.0, 0.0), downArrow.size()));
} }
cachePainter.end(); cachePainter.end();
@ -2486,7 +2491,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
// Paint slider // Paint slider
if (scrollBar->subControls & SC_ScrollBarSlider) { if (scrollBar->subControls & SC_ScrollBarSlider) {
QRect pixmapRect = scrollBarSlider; QRect pixmapRect = scrollBarSlider;
painter->setPen(QPen(alphaOutline, 0)); painter->setPen(QPen(alphaOutline));
if (option->state & State_Sunken && scrollBar->activeSubControls & SC_ScrollBarSlider) if (option->state & State_Sunken && scrollBar->activeSubControls & SC_ScrollBarSlider)
painter->setBrush(midColor2); painter->setBrush(midColor2);
else if (option->state & State_MouseOver && scrollBar->activeSubControls & SC_ScrollBarSlider) else if (option->state & State_MouseOver && scrollBar->activeSubControls & SC_ScrollBarSlider)
@ -2521,7 +2526,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0)); painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0));
painter->setPen(QPen(alphaOutline, 1)); painter->setPen(QPen(alphaOutline));
if (option->state & State_Horizontal) { if (option->state & State_Horizontal) {
if (option->direction == Qt::RightToLeft) { if (option->direction == Qt::RightToLeft) {
pixmapRect.setLeft(scrollBarSubLine.left()); pixmapRect.setLeft(scrollBarSubLine.left());
@ -2545,9 +2550,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
rotation = option->direction == Qt::LeftToRight ? -90 : 90; rotation = option->direction == Qt::LeftToRight ? -90 : 90;
QRect upRect = scrollBarSubLine.translated(horizontal ? -2 : -1, 0); QRect upRect = scrollBarSubLine.translated(horizontal ? -2 : -1, 0);
QPixmap arrowPixmap = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation); QPixmap arrowPixmap = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation);
painter->drawPixmap(QRect(upRect.center().x() - arrowPixmap.width() / 4 + 2, painter->drawPixmap(QRectF(upRect.center().x() - arrowPixmap.width() / 4.0 + 2.0,
upRect.center().y() - arrowPixmap.height() / 4 + 1, upRect.center().y() - arrowPixmap.height() / 4.0 + 1.0,
arrowPixmap.width()/2, arrowPixmap.height()/2), arrowPixmap); arrowPixmap.width() / 2.0, arrowPixmap.height() / 2.0),
arrowPixmap, QRectF(QPoint(0.0, 0.0), arrowPixmap.size()));
} }
// The AddLine (down/right) button // The AddLine (down/right) button
@ -2584,9 +2590,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
rotation = option->direction == Qt::LeftToRight ? 90 : -90; rotation = option->direction == Qt::LeftToRight ? 90 : -90;
QRect downRect = scrollBarAddLine.translated(-1, 1); QRect downRect = scrollBarAddLine.translated(-1, 1);
QPixmap arrowPixmap = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation); QPixmap arrowPixmap = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation);
painter->drawPixmap(QRect(downRect.center().x() - arrowPixmap.width() / 4 + 2, painter->drawPixmap(QRectF(downRect.center().x() - arrowPixmap.width() / 4.0 + 2.0,
downRect.center().y() - arrowPixmap.height() / 4, downRect.center().y() - arrowPixmap.height() / 4.0,
arrowPixmap.width()/2, arrowPixmap.height()/2), arrowPixmap); arrowPixmap.width() / 2.0, arrowPixmap.height() / 2.0),
arrowPixmap, QRectF(QPoint(0.0, 0.0), arrowPixmap.size()));
} }
} }
@ -2640,7 +2647,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
downArrowRect.left() - 6: downArrowRect.right() + 6); downArrowRect.left() - 6: downArrowRect.right() + 6);
proxy()->drawPrimitive(PE_PanelButtonCommand, &buttonOption, &cachePainter, widget); proxy()->drawPrimitive(PE_PanelButtonCommand, &buttonOption, &cachePainter, widget);
cachePainter.restore(); cachePainter.restore();
cachePainter.setPen( QPen(hasFocus ? option->palette.highlight() : outline.lighter(110), 0)); cachePainter.setPen( QPen(hasFocus ? option->palette.highlight() : outline.lighter(110), 1));
if (!sunken) { if (!sunken) {
int borderSize = 1; int borderSize = 1;
@ -2677,9 +2684,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
QColor arrowColor = option->palette.buttonText().color(); QColor arrowColor = option->palette.buttonText().color();
arrowColor.setAlpha(220); arrowColor.setAlpha(220);
QPixmap downArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180); QPixmap downArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180);
cachePainter.drawPixmap(QRect(downArrowRect.center().x() - downArrow.width() / 4 + 1, cachePainter.drawPixmap(QRectF(downArrowRect.center().x() - downArrow.width() / 4.0 + 1.0,
downArrowRect.center().y() - downArrow.height() / 4 + 1, downArrowRect.center().y() - downArrow.height() / 4.0 + 1.0,
downArrow.width()/2, downArrow.height()/2), downArrow); downArrow.width() / 2.0, downArrow.height() / 2.0),
downArrow, QRectF(QPointF(0.0, 0.0), downArrow.size()));
} }
cachePainter.end(); cachePainter.end();
QPixmapCache::insert(pixmapName, cache); QPixmapCache::insert(pixmapName, cache);
@ -2730,7 +2738,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
gradient.setStart(pixmapRect.left(), pixmapRect.center().y()); gradient.setStart(pixmapRect.left(), pixmapRect.center().y());
gradient.setFinalStop(pixmapRect.right(), pixmapRect.center().y()); gradient.setFinalStop(pixmapRect.right(), pixmapRect.center().y());
} }
groovePainter.setPen(QPen(outline, 0)); groovePainter.setPen(QPen(outline));
gradient.setColorAt(0, grooveColor.darker(110)); gradient.setColorAt(0, grooveColor.darker(110));
gradient.setColorAt(1, grooveColor.lighter(110));//palette.button().color().darker(115)); gradient.setColorAt(1, grooveColor.lighter(110));//palette.button().color().darker(115));
groovePainter.setBrush(gradient); groovePainter.setBrush(gradient);
@ -2764,7 +2772,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
groovePainter.setRenderHint(QPainter::Antialiasing, true); groovePainter.setRenderHint(QPainter::Antialiasing, true);
groovePainter.translate(0.5, 0.5); groovePainter.translate(0.5, 0.5);
groovePainter.setPen(QPen(outline, 0)); groovePainter.setPen(QPen(outline));
gradient.setColorAt(0, activeHighlight); gradient.setColorAt(0, activeHighlight);
gradient.setColorAt(1, activeHighlight.lighter(130)); gradient.setColorAt(1, activeHighlight.lighter(130));
groovePainter.setBrush(gradient); groovePainter.setBrush(gradient);
@ -2813,9 +2821,9 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
handlePainter.setBrush(QColor(0, 0, 0, 40)); handlePainter.setBrush(QColor(0, 0, 0, 40));
handlePainter.drawRect(r.adjusted(-1, 2, 1, -2)); handlePainter.drawRect(r.adjusted(-1, 2, 1, -2));
handlePainter.setPen(QPen(d->outline(option->palette), 1)); handlePainter.setPen(QPen(d->outline(option->palette)));
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
handlePainter.setPen(QPen(d->highlightedOutline(option->palette), 1)); handlePainter.setPen(QPen(d->highlightedOutline(option->palette)));
handlePainter.setBrush(gradient); handlePainter.setBrush(gradient);
handlePainter.drawRoundedRect(r, 2, 2); handlePainter.drawRoundedRect(r, 2, 2);

View File

@ -462,7 +462,7 @@ class QMacCGContext
{ {
CGContextRef context; CGContextRef context;
public: public:
QMacCGContext(QPainter *p); //qpaintengine_mac.cpp QMacCGContext(QPainter *p);
inline QMacCGContext() { context = 0; } inline QMacCGContext() { context = 0; }
inline QMacCGContext(const QPaintDevice *pdev) { inline QMacCGContext(const QPaintDevice *pdev) {
extern CGContextRef qt_mac_cg_context(const QPaintDevice *); extern CGContextRef qt_mac_cg_context(const QPaintDevice *);
@ -6476,6 +6476,18 @@ void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig
} }
} }
// move to QRegion?
void qt_mac_scale_region(QRegion *region, qreal scaleFactor)
{
QVector<QRect> scaledRects;
scaledRects.reserve(region->rects().count());
foreach (const QRect &rect, region->rects()) {
scaledRects.append(QRect(rect.topLeft(), rect.size() * scaleFactor));
}
region->setRects(&scaledRects[0], scaledRects.count());
}
QMacCGContext::QMacCGContext(QPainter *p) QMacCGContext::QMacCGContext(QPainter *p)
{ {
QPaintEngine *pe = p->paintEngine(); QPaintEngine *pe = p->paintEngine();
@ -6502,20 +6514,28 @@ QMacCGContext::QMacCGContext(QPainter *p)
CGContextScaleCTM(context, 1, -1); CGContextScaleCTM(context, 1, -1);
if (devType == QInternal::Widget) { if (devType == QInternal::Widget) {
QRegion clip = p->paintEngine()->systemClip(); // Set the clip rect which is an intersection of the system clip
QTransform native = p->deviceTransform(); // and the painter clip. To make matters more interesting these
// are in device pixels and device-independent pixels, respectively.
const qreal devicePixelRatio = image->devicePixelRatio();
QRegion clip = p->paintEngine()->systemClip(); // get system clip in device pixels
QTransform native = p->deviceTransform(); // get device transform. dx/dy is in device pixels
if (p->hasClipping()) { if (p->hasClipping()) {
QRegion r = p->clipRegion(); QRegion r = p->clipRegion(); // get painter clip, which is in device-independent pixels
qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels
r.translate(native.dx(), native.dy()); r.translate(native.dx(), native.dy());
if (clip.isEmpty()) if (clip.isEmpty())
clip = r; clip = r;
else else
clip &= r; clip &= r;
} }
qt_mac_clip_cg(context, clip, 0); qt_mac_clip_cg(context, clip, 0); // clip in device pixels
CGContextTranslateCTM(context, native.dx(), native.dy()); // Scale the context so that painting happens in device-independet pixels.
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio);
} }
} else { } else {
qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType;

View File

@ -618,10 +618,11 @@ void QStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, c
void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
const QPixmap &pixmap) const const QPixmap &pixmap) const
{ {
QRect aligned = alignedRect(QApplication::layoutDirection(), QFlag(alignment), pixmap.size(), rect); int scale = pixmap.devicePixelRatio();
QRect aligned = alignedRect(QApplication::layoutDirection(), QFlag(alignment), pixmap.size() / scale, rect);
QRect inter = aligned.intersected(rect); QRect inter = aligned.intersected(rect);
painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width(), inter.height()); painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width() * scale, inter.height() *scale);
} }
/*! /*!

View File

@ -43,6 +43,7 @@
#define QSTYLE_P_H #define QSTYLE_P_H
#include "private/qobject_p.h" #include "private/qobject_p.h"
#include <QtGui/qguiapplication.h>
#include <QtWidgets/qstyle.h> #include <QtWidgets/qstyle.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -74,12 +75,18 @@ public:
inline QImage styleCacheImage(const QSize &size) inline QImage styleCacheImage(const QSize &size)
{ {
return QImage(size, QImage::Format_ARGB32_Premultiplied); const qreal pixelRatio = qApp->devicePixelRatio();
QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
cacheImage.setDevicePixelRatio(pixelRatio);
return cacheImage;
} }
inline QPixmap styleCachePixmap(const QSize &size) inline QPixmap styleCachePixmap(const QSize &size)
{ {
return QPixmap(size); const qreal pixelRatio = qApp->devicePixelRatio();
QPixmap cachePixmap = QPixmap(size * pixelRatio);
cachePixmap.setDevicePixelRatio(pixelRatio);
return cachePixmap;
} }
#define BEGIN_STYLE_PIXMAPCACHE(a) \ #define BEGIN_STYLE_PIXMAPCACHE(a) \

View File

@ -562,17 +562,18 @@ QSize QLabelPrivate::sizeForWidth(int w) const
int vextra = hextra; int vextra = hextra;
QFontMetrics fm = q->fontMetrics(); QFontMetrics fm = q->fontMetrics();
if (pixmap && !pixmap->isNull()) if (pixmap && !pixmap->isNull()) {
br = pixmap->rect(); br = pixmap->rect();
br.setSize(br.size() / pixmap->devicePixelRatio());
#ifndef QT_NO_PICTURE #ifndef QT_NO_PICTURE
else if (picture && !picture->isNull()) } else if (picture && !picture->isNull()) {
br = picture->boundingRect(); br = picture->boundingRect();
#endif #endif
#ifndef QT_NO_MOVIE #ifndef QT_NO_MOVIE
else if (movie && !movie->currentPixmap().isNull()) } else if (movie && !movie->currentPixmap().isNull()) {
br = movie->currentPixmap().rect(); br = movie->currentPixmap().rect();
#endif #endif
else if (isTextLabel) { } else if (isTextLabel) {
int align = QStyle::visualAlignment(textDirection(), QFlag(this->align)); int align = QStyle::visualAlignment(textDirection(), QFlag(this->align));
// Add indentation // Add indentation
int m = indent; int m = indent;

View File

@ -0,0 +1,12 @@
TEMPLATE = app
TARGET = highdpi
DEPENDPATH += .
INCLUDEPATH += .
QT += widgets
# Input
SOURCES += main.cpp
RESOURCES += \
highdpi.qrc

View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/">
<file>qticon.png</file>
<file>qticon@2x.png</file>
<file>qticon_large.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,366 @@
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
class PixmapPainter : public QWidget
{
public:
PixmapPainter();
void paintEvent(QPaintEvent *event);
QPixmap pixmap1X;
QPixmap pixmap2X;
QPixmap pixmapLarge;
QImage image1X;
QImage image2X;
QImage imageLarge;
QIcon qtIcon;
};
PixmapPainter::PixmapPainter()
{
pixmap1X = QPixmap(":/qticon.png");
pixmap2X = QPixmap(":/qticon@2x.png");
pixmapLarge = QPixmap(":/qticon_large.png");
image1X = QImage(":/qticon.png");
image2X = QImage(":/qticon@2x.png");
imageLarge = QImage(":/qticon_large.png");
qtIcon.addFile(":/qticon.png");
qtIcon.addFile(":/qticon@2x.png");
}
void PixmapPainter::paintEvent(QPaintEvent *event)
{
QPainter p(this);
p.fillRect(QRect(QPoint(0, 0), size()), QBrush(Qt::gray));
int pixmapPointSize = 64;
int y = 30;
int dy = 150;
int x = 10;
int dx = 80;
// draw at point
// qDebug() << "paint pixmap" << pixmap1X.devicePixelRatio();
p.drawPixmap(x, y, pixmap1X);
x+=dx;p.drawPixmap(x, y, pixmap2X);
x+=dx;p.drawPixmap(x, y, pixmapLarge);
x+=dx*2;p.drawPixmap(x, y, qtIcon.pixmap(QSize(pixmapPointSize, pixmapPointSize)));
x+=dx;p.drawImage(x, y, image1X);
x+=dx;p.drawImage(x, y, image2X);
x+=dx;p.drawImage(x, y, imageLarge);
// draw at 64x64 rect
y+=dy;
x = 10;
p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), pixmap1X);
x+=dx;p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), pixmap2X);
x+=dx;p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), pixmapLarge);
x+=dx;p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), qtIcon.pixmap(QSize(pixmapPointSize, pixmapPointSize)));
x+=dx;p.drawImage(QRect(x, y, pixmapPointSize, pixmapPointSize), image1X);
x+=dx;p.drawImage(QRect(x, y, pixmapPointSize, pixmapPointSize), image2X);
x+=dx;p.drawImage(QRect(x, y, pixmapPointSize, pixmapPointSize), imageLarge);
// draw at 128x128 rect
y+=dy - 50;
x = 10;
p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), pixmap1X);
x+=dx * 2; p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), pixmap2X);
x+=dx * 2; p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), pixmapLarge);
x+=dx * 2; p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), qtIcon.pixmap(QSize(pixmapPointSize, pixmapPointSize)));
x+=dx * 2; p.drawImage(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), image1X);
x+=dx * 2; p.drawImage(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), image2X);
x+=dx * 2; p.drawImage(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), imageLarge);
}
class Labels : public QWidget
{
public:
Labels();
QPixmap pixmap1X;
QPixmap pixmap2X;
QPixmap pixmapLarge;
QIcon qtIcon;
};
Labels::Labels()
{
pixmap1X = QPixmap(":/qticon.png");
pixmap2X = QPixmap(":/qticon@2x.png");
pixmapLarge = QPixmap(":/qticon_large.png");
qtIcon.addFile(":/qticon.png");
qtIcon.addFile(":/qticon@2x.png");
setWindowIcon(qtIcon);
setWindowTitle("Labels");
QLabel *label1x = new QLabel();
label1x->setPixmap(pixmap1X);
QLabel *label2x = new QLabel();
label2x->setPixmap(pixmap2X);
QLabel *labelIcon = new QLabel();
labelIcon->setPixmap(qtIcon.pixmap(QSize(64,64)));
QLabel *labelLarge = new QLabel();
labelLarge->setPixmap(pixmapLarge);
QHBoxLayout *layout = new QHBoxLayout(this);
// layout->addWidget(label1x); //expected low-res on high-dpi displays
layout->addWidget(label2x);
// layout->addWidget(labelIcon);
// layout->addWidget(labelLarge); // expected large size and low-res
setLayout(layout);
}
class MainWindow : public QMainWindow
{
public:
MainWindow();
QIcon qtIcon;
QIcon qtIcon1x;
QIcon qtIcon2x;
QToolBar *fileToolBar;
};
MainWindow::MainWindow()
{
qtIcon.addFile(":/qticon.png");
qtIcon.addFile(":/qticon@2x.png");
qtIcon1x.addFile(":/qticon.png");
qtIcon2x.addFile(":/qticon@2x.png");
setWindowIcon(qtIcon);
setWindowTitle("MainWindow");
fileToolBar = addToolBar(tr("File"));
// fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
fileToolBar->addAction(new QAction(qtIcon, QString("1x and 2x"), this));
fileToolBar->addAction(new QAction(qtIcon1x, QString("1x"), this));
fileToolBar->addAction(new QAction(qtIcon2x, QString("2x"), this));
}
class StandardIcons : public QWidget
{
public:
void paintEvent(QPaintEvent *event)
{
int x = 10;
int y = 10;
int dx = 50;
int dy = 50;
int maxX = 500;
for (int iconIndex = QStyle::SP_TitleBarMenuButton; iconIndex < QStyle::SP_MediaVolumeMuted; ++iconIndex) {
QIcon icon = qApp->style()->standardIcon(QStyle::StandardPixmap(iconIndex));
QPainter p(this);
p.drawPixmap(x, y, icon.pixmap(dx - 5, dy - 5));
if (x + dx > maxX)
y+=dy;
x = ((x + dx) % maxX);
}
};
};
class Caching : public QWidget
{
public:
void paintEvent(QPaintEvent *event)
{
QSize layoutSize(75, 75);
QPainter widgetPainter(this);
widgetPainter.fillRect(QRect(QPoint(0, 0), this->size()), Qt::gray);
{
const qreal devicePixelRatio = this->windowHandle()->devicePixelRatio();
QPixmap cache(layoutSize * devicePixelRatio);
cache.setDevicePixelRatio(devicePixelRatio);
QPainter cachedPainter(&cache);
cachedPainter.fillRect(QRect(0,0, 75, 75), Qt::blue);
cachedPainter.fillRect(QRect(10,10, 55, 55), Qt::red);
cachedPainter.drawEllipse(QRect(10,10, 55, 55));
QPainter widgetPainter(this);
widgetPainter.drawPixmap(QPoint(10, 10), cache);
}
{
const qreal devicePixelRatio = this->windowHandle()->devicePixelRatio();
QImage cache = QImage(layoutSize * devicePixelRatio, QImage::QImage::Format_ARGB32_Premultiplied);
cache.setDevicePixelRatio(devicePixelRatio);
QPainter cachedPainter(&cache);
cachedPainter.fillRect(QRect(0,0, 75, 75), Qt::blue);
cachedPainter.fillRect(QRect(10,10, 55, 55), Qt::red);
cachedPainter.drawEllipse(QRect(10,10, 55, 55));
QPainter widgetPainter(this);
widgetPainter.drawImage(QPoint(95, 10), cache);
}
}
};
class Style : public QWidget {
public:
QPushButton *button;
QLineEdit *lineEdit;
QSlider *slider;
QHBoxLayout *row1;
Style() {
row1 = new QHBoxLayout();
setLayout(row1);
button = new QPushButton();
button->setText("Test Button");
row1->addWidget(button);
lineEdit = new QLineEdit();
lineEdit->setText("Test Lineedit");
row1->addWidget(lineEdit);
slider = new QSlider();
row1->addWidget(slider);
row1->addWidget(new QSpinBox);
row1->addWidget(new QScrollBar);
QTabBar *tab = new QTabBar();
tab->addTab("Foo");
tab->addTab("Bar");
row1->addWidget(tab);
}
};
class Fonts : public QWidget
{
public:
void paintEvent(QPaintEvent *event)
{
QPainter painter(this);
int y = 40;
for (int fontSize = 2; fontSize < 18; fontSize += 2) {
QFont font;
font.setPointSize(fontSize);
QString string = QString(QStringLiteral("%1 The quick brown fox jumped over the lazy Doug.")).arg(fontSize);
painter.setFont(font);
painter.drawText(10, y, string);
y += (fontSize * 2.5);
}
}
};
template <typename T>
void apiTestdevicePixelRatioGetter()
{
if (0) {
T *t = 0;
t->devicePixelRatio();
}
}
template <typename T>
void apiTestdevicePixelRatioSetter()
{
if (0) {
T *t = 0;
t->setDevicePixelRatio(2.0);
}
}
void apiTest()
{
// compile call to devicePixelRatio getter and setter (verify spelling)
apiTestdevicePixelRatioGetter<QWindow>();
apiTestdevicePixelRatioGetter<QScreen>();
apiTestdevicePixelRatioGetter<QGuiApplication>();
apiTestdevicePixelRatioGetter<QImage>();
apiTestdevicePixelRatioSetter<QImage>();
apiTestdevicePixelRatioGetter<QPixmap>();
apiTestdevicePixelRatioSetter<QPixmap>();
}
int main(int argc, char **argv)
{
qputenv("QT_HIGHDPI_AWARE", "1");
QApplication app(argc, argv);
PixmapPainter pixmapPainter;
// Enable for lots of pixmap drawing
pixmapPainter.show();
Labels label;
label.resize(200, 200);
label.show();
MainWindow mainWindow;
mainWindow.show();
StandardIcons icons;
icons.resize(510, 510);
icons.show();
Caching caching;
caching.resize(300, 300);
caching.show();
Style style;
style.show();
Fonts fonts;
fonts.show();
return app.exec();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -121,6 +121,7 @@ static void printHelp()
" -commands Displays all available commands\n" " -commands Displays all available commands\n"
" -w Width of the paintdevice\n" " -w Width of the paintdevice\n"
" -h Height of the paintdevice\n" " -h Height of the paintdevice\n"
" -scalefactor Scale factor (device pixel ratio) of the paintdevice\n"
" -cmp Show the reference picture\n" " -cmp Show the reference picture\n"
" -bg-white No checkers background\n"); " -bg-white No checkers background\n");
} }
@ -238,6 +239,8 @@ int main(int argc, char **argv)
bool highres = false; bool highres = false;
bool show_cmp = false; bool show_cmp = false;
int width = 800, height = 800; int width = 800, height = 800;
int scaledWidth = width, scaledHeight = height;
qreal scalefactor = 1.0;
bool verboseMode = false; bool verboseMode = false;
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
@ -328,6 +331,9 @@ int main(int argc, char **argv)
} else if (option == "h") { } else if (option == "h") {
Q_ASSERT_X(i + 1 < argc, "main", "-h must be followed by a value"); Q_ASSERT_X(i + 1 < argc, "main", "-h must be followed by a value");
height = atoi(argv[++i]); height = atoi(argv[++i]);
} else if (option == "scalefactor") {
Q_ASSERT_X(i + 1 < argc, "main", "-scalefactor must be followed by a value");
scalefactor = atof(argv[++i]);
} else if (option == "cmp") { } else if (option == "cmp") {
show_cmp = true; show_cmp = true;
} else if (option == "bg-white") { } else if (option == "bg-white") {
@ -350,6 +356,8 @@ int main(int argc, char **argv)
#endif #endif
} }
} }
scaledWidth = width * scalefactor;
scaledHeight = height * scalefactor;
PaintCommands pcmd(QStringList(), 800, 800); PaintCommands pcmd(QStringList(), 800, 800);
pcmd.setVerboseMode(verboseMode); pcmd.setVerboseMode(verboseMode);
@ -514,7 +522,8 @@ int main(int argc, char **argv)
#endif #endif
case PixmapType: case PixmapType:
{ {
QPixmap pixmap(width, height); QPixmap pixmap(scaledWidth, scaledHeight);
pixmap.setDevicePixelRatio(scalefactor);
pixmap.fill(Qt::white); pixmap.fill(Qt::white);
QPainter pt(&pixmap); QPainter pt(&pixmap);
pcmd.setPainter(&pt); pcmd.setPainter(&pt);
@ -527,7 +536,8 @@ int main(int argc, char **argv)
case BitmapType: case BitmapType:
{ {
QBitmap bitmap(width, height); QBitmap bitmap(scaledWidth, scaledHeight);
bitmap.setDevicePixelRatio(scalefactor);
QPainter pt(&bitmap); QPainter pt(&bitmap);
pcmd.setPainter(&pt); pcmd.setPainter(&pt);
pcmd.setFilePath(fileinfo.absolutePath()); pcmd.setFilePath(fileinfo.absolutePath());
@ -547,9 +557,10 @@ int main(int argc, char **argv)
case ImageType: case ImageType:
{ {
qDebug() << "Creating image"; qDebug() << "Creating image";
QImage image(width, height, type == ImageMonoType QImage image(scaledWidth, scaledHeight, type == ImageMonoType
? QImage::Format_MonoLSB ? QImage::Format_MonoLSB
: imageFormat); : imageFormat);
image.setDevicePixelRatio(scalefactor);
image.fill(0); image.fill(0);
QPainter pt(&image); QPainter pt(&image);
pcmd.setPainter(&pt); pcmd.setPainter(&pt);
@ -557,6 +568,7 @@ int main(int argc, char **argv)
pcmd.runCommands(); pcmd.runCommands();
pt.end(); pt.end();
image.convertToFormat(QImage::Format_ARGB32).save("output_image.png", "PNG"); image.convertToFormat(QImage::Format_ARGB32).save("output_image.png", "PNG");
image.setDevicePixelRatio(1.0); // reset scale factor: display "large" image.
#ifndef CONSOLE_APPLICATION #ifndef CONSOLE_APPLICATION
QLabel *label = createLabel(); QLabel *label = createLabel();
label->setPixmap(QPixmap::fromImage(image)); label->setPixmap(QPixmap::fromImage(image));