X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fgui%2Fpainting%2Fqpaintengine_raster.cpp;h=0e9129f8c01c9a7bb3546c7186dffce538546a4a;hb=49ba35b9904a05ec1c7d768f8c079ce3c7d283fe;hp=15f344bf81bc54c272459e2980b4338acd99fae9;hpb=ca572c0b806388cbc58dcba4ab6d7cc25d89366a;p=profile%2Fivi%2Fqtbase.git diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 15f344b..0e9129f 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1,38 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ +** 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 -** 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. +** 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 +** 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** +** 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$ @@ -84,6 +84,54 @@ QT_BEGIN_NAMESPACE +class QRectVectorPath : public QVectorPath { +public: + inline void set(const QRect &r) { + qreal left = r.x(); + qreal right = r.x() + r.width(); + qreal top = r.y(); + qreal bottom = r.y() + r.height(); + pts[0] = left; + pts[1] = top; + pts[2] = right; + pts[3] = top; + pts[4] = right; + pts[5] = bottom; + pts[6] = left; + pts[7] = bottom; + } + + inline void set(const QRectF &r) { + qreal left = r.x(); + qreal right = r.x() + r.width(); + qreal top = r.y(); + qreal bottom = r.y() + r.height(); + pts[0] = left; + pts[1] = top; + pts[2] = right; + pts[3] = top; + pts[4] = right; + pts[5] = bottom; + pts[6] = left; + pts[7] = bottom; + } + inline QRectVectorPath(const QRect &r) + : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose) + { + set(r); + } + inline QRectVectorPath(const QRectF &r) + : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose) + { + set(r); + } + inline QRectVectorPath() + : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose) + { } + + qreal pts[8]; +}; + Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp #define qreal_to_fixed_26_6(f) (int(f * 64)) @@ -118,6 +166,9 @@ static inline bool winClearTypeFontsEnabled() return result == FE_FONTSMOOTHINGCLEARTYPE; } +/*! + \internal + */ bool QRasterPaintEngine::clearTypeFontsEnabled() { static const bool result = winClearTypeFontsEnabled(); @@ -593,6 +644,7 @@ QRasterPaintEngineState::QRasterPaintEngineState() flags.fast_pen = true; flags.antialiased = false; flags.bilinear = false; + flags.legacy_rounding = false; flags.fast_text = true; flags.int_xform = true; flags.tx_noshear = true; @@ -719,7 +771,7 @@ void QRasterPaintEngine::updatePen(const QPen &pen) } else if (pen_style != Qt::NoPen) { if (!d->dashStroker) d->dashStroker.reset(new QDashStroker(&d->basicStroker)); - if (pen.isCosmetic()) { + if (qt_pen_is_cosmetic(pen, s->renderHints)) { d->dashStroker->setClipRect(d->deviceRect); } else { // ### I've seen this inverted devrect multiple places now... @@ -734,10 +786,11 @@ void QRasterPaintEngine::updatePen(const QPen &pen) } ensureRasterState(); // needed because of tx_noshear... + bool cosmetic = qt_pen_is_cosmetic(pen, s->renderHints); s->flags.fast_pen = pen_style > Qt::NoPen && s->penData.blend - && ((pen.isCosmetic() && penWidth <= 1) - || (!pen.isCosmetic() && s->flags.tx_noshear && penWidth * s->txscale <= 1)); + && ((cosmetic && penWidth <= 1) + || (!cosmetic && s->flags.tx_noshear && penWidth * s->txscale <= 1)); s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear; @@ -876,6 +929,7 @@ void QRasterPaintEngine::renderHintsChanged() s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing); s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform); + s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting); if (was_aa != s->flags.antialiased) s->strokeFlags |= DirtyHints; @@ -1018,9 +1072,11 @@ void QRasterPaintEnginePrivate::systemStateChanged() exDeviceRect = deviceRect; Q_Q(QRasterPaintEngine); - q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion; - q->state()->fillFlags |= QPaintEngine::DirtyClipRegion; - q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion; + if (q->state()) { + q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion; + q->state()->fillFlags |= QPaintEngine::DirtyClipRegion; + q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion; + } } void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m) @@ -1321,6 +1377,13 @@ void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) } /*! + \fn const QClipData *QRasterPaintEngine::clipData() const + + \internal +*/ + + +/*! \internal */ void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData) @@ -1466,6 +1529,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) QRectVectorPath path; if (s->flags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); for (int i = 0; i < rectCount; ++i) { path.set(rects[i]); stroker.drawPath(path); @@ -1512,6 +1576,7 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) QRectVectorPath path; if (s->flags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); for (int i = 0; i < rectCount; ++i) { path.set(rects[i]); stroker.drawPath(path); @@ -1545,9 +1610,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) if (s->flags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPath(path); } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) { - qreal width = s->lastPen.isCosmetic() + qreal width = qt_pen_is_cosmetic(s->lastPen, s->renderHints) ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen)) : qpen_widthf(s->lastPen) * s->txscale; int dashIndex = 0; @@ -1600,12 +1666,16 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) QPaintEngineEx::stroke(path, pen); } -static inline QRect toNormalizedFillRect(const QRectF &rect) +QRect QRasterPaintEngine::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); + QRasterPaintEngineState *s = state(); + + qreal delta = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0); + + int x1 = qRound(rect.x() + delta); + int y1 = qRound(rect.y() + delta); + int x2 = qRound(rect.right() + delta); + int y2 = qRound(rect.bottom() + delta); if (x2 < x1) qSwap(x1, x2); @@ -1874,11 +1944,8 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly if (mode != PolylineMode) { // Do the fill... ensureBrush(); - if (s->brushData.blend) { - d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque()); + if (s->brushData.blend) fillPolygon(points, pointCount, mode); - d->outlineMapper->setCoordinateRounding(false); - } } // Do the outline... @@ -1886,6 +1953,7 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode)); if (s->flags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPath(vp); } else { QPaintEngineEx::stroke(vp, s->lastPen); @@ -1924,7 +1992,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; @@ -1938,7 +2005,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); } } @@ -1952,6 +2018,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg if (s->flags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPath(vp); } else { QPaintEngineEx::stroke(vp, s->lastPen); @@ -2049,17 +2116,6 @@ void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, cons } } -// assumes that rect has positive width and height -static inline const QRect toRect_normalized(const QRectF &rect) -{ - const int x = qRound(rect.x()); - const int y = qRound(rect.y()); - const int w = int(rect.width() + qreal(0.5)); - const int h = int(rect.height() + qreal(0.5)); - - return QRect(x, y, w, h); -} - static inline int fast_ceil_positive(const qreal &v) { const int iv = int(v); @@ -2089,9 +2145,10 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img) Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); + qreal scale = img.devicePixelRatio(); - if (s->matrix.type() > QTransform::TxTranslate) { - drawImage(QRectF(p.x(), p.y(), img.width(), img.height()), + if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) { + drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale), img, QRectF(0, 0, img.width(), img.height())); } else { @@ -2191,7 +2248,9 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe // 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); + + if (s->flags.legacy_rounding) + 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); @@ -2293,6 +2352,22 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; } } 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()]; if (func && (!clip || clip->hasRectClip)) { func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), @@ -2334,8 +2409,9 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) { d->initializeRasterizer(&d->image_filler_xform); d->rasterizer->setAntialiased(s->flags.antialiased); + d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding); - const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta); + const QPointF offs = s->flags.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF(); const QRectF &rect = r.normalized(); const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs; @@ -2348,7 +2424,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; } #endif - const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta; + const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0); QPainterPath path; path.addRect(r); QTransform m = s->matrix; @@ -2429,6 +2505,7 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) { d->initializeRasterizer(&d->image_filler_xform); d->rasterizer->setAntialiased(s->flags.antialiased); + d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding); const QRectF &rect = r.normalized(); const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f); @@ -2700,6 +2777,9 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx blend(current, spans, &s->penData); } +/*! + \internal +*/ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) { @@ -2726,7 +2806,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(), qFloor(positions[i].x) + offset.x(), - qFloor(positions[i].y) + offset.y(), + qRound(positions[i].y) + offset.y(), alphaMap->width(), alphaMap->height()); fontEngine->unlockAlphaMapForGlyph(); @@ -2757,7 +2837,6 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, rightShift = 3; // divide by 8 int margin = fontEngine->glyphMargin(glyphType); - const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); for (int i=0; ifontEngine(); - if (shouldDrawCachedGlyphs(fontEngine, state()->matrix)) { + if (!supportsTransformations(fontEngine)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); } else if (state()->matrix.type() < QTransform::TxProject) { @@ -3033,6 +3112,7 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount) } QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPoints(points, pointCount); } @@ -3052,6 +3132,7 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) } QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPoints(points, pointCount); } @@ -3072,6 +3153,7 @@ void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount) if (s->flags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); for (int i=0; iflags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); for (int i=0; imatrix; return supportsTransformations(fontEngine, m); } +/*! + \internal +*/ bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const { - if (m.type() >= QTransform::TxProject) + if (fontEngine->supportsTransformations(m)) return true; return !shouldDrawCachedGlyphs(fontEngine, m); @@ -3372,6 +3458,7 @@ void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data) QRasterPaintEngineState *s = q->state(); rasterizer->setAntialiased(s->flags.antialiased); + rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding); QRect clipRect(deviceRect); ProcessSpans blend; @@ -3436,6 +3523,7 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, if (!s->flags.antialiased) { rasterizer->setAntialiased(s->flags.antialiased); + rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding); rasterizer->setClipRect(deviceRect); rasterizer->initialize(callback, userData); @@ -4500,7 +4588,7 @@ void QSpanData::setupMatrix(const QTransform &matrix, int bilin) txop = inv.type(); bilinear = bilin; - const bool affine = !m13 && !m23; + const bool affine = inv.isAffine(); fast_matrix = affine && m11 * m11 + m21 * m21 < 1e4 && m12 * m12 + m22 * m22 < 1e4 @@ -4677,20 +4765,9 @@ static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, /*! \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) \overload - - Draws the first \a pointCount points in the buffer \a points - - The default implementation converts the first \a pointCount QPoints in \a points - to QPointFs and calls the floating point version of drawPoints. + \reimp */ -/*! - \fn void QRasterPaintEngine::drawEllipse(const QRect &rect) - \overload - - Reimplement this function to draw the largest ellipse that can be - contained within rectangle \a rect. -*/ #ifdef QT_DEBUG_DRAW void dumpClip(int width, int height, const QClipData *clip)