X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fgui%2Fpainting%2Fqpaintengine_raster.cpp;h=0e9129f8c01c9a7bb3546c7186dffce538546a4a;hb=49ba35b9904a05ec1c7d768f8c079ce3c7d283fe;hp=7232f9c9105b7c004f1d8fbf9d771d9141095078;hpb=66febd27cb3bacf5a4996f184725f318bce0f4fc;p=profile%2Fivi%2Fqtbase.git diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 7232f9c..0e9129f 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1,38 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** 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$ @@ -54,10 +54,6 @@ #include #include -#if defined (Q_WS_X11) -# include -#endif - // #include // #include #include @@ -75,30 +71,67 @@ // #include "qbezier_p.h" #include "qoutlinemapper_p.h" -#if defined(Q_OS_WIN) -# include +#include + +#ifdef Q_OS_WIN # include # include -# if defined(Q_OS_WINCE) -# include "qguifunctions_wince.h" +# include +#ifdef Q_OS_WIN64 +# include # endif -#elif defined(Q_WS_MAC) -# include -# include -# include -#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) -# include -#elif defined(Q_WS_QPA) -# include #endif -#if defined(Q_OS_WIN64) -# include -#endif -#include - 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,15 +151,24 @@ void dumpClip(int width, int height, const QClipData *clip); // 4 pixels. #define int_dim(pos, dim) (int(pos+dim) - int(pos)) +static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; + #ifdef Q_OS_WIN static inline bool winClearTypeFontsEnabled() { UINT result = 0; +#if !defined(SPI_GETFONTSMOOTHINGTYPE) // MinGW +# define SPI_GETFONTSMOOTHINGTYPE 0x200A +# define FE_FONTSMOOTHINGCLEARTYPE 0x002 +#endif SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0); return result == FE_FONTSMOOTHINGCLEARTYPE; } +/*! + \internal + */ bool QRasterPaintEngine::clearTypeFontsEnabled() { static const bool result = winClearTypeFontsEnabled(); @@ -135,9 +177,6 @@ bool QRasterPaintEngine::clearTypeFontsEnabled() #endif // Q_OS_WIN -#ifdef Q_WS_MAC -extern bool qt_applefontsmoothing_enabled; -#endif /******************************************************************************** @@ -146,7 +185,6 @@ extern bool qt_applefontsmoothing_enabled; static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData); static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData); static void qt_span_clip(int count, const QSpan *spans, void *userData); -static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result); struct ClipData { @@ -161,6 +199,10 @@ enum LineDrawMode { LineDrawIncludeLastPixel }; +static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, + ProcessSpans pen_func, ProcessSpans brush_func, + QSpanData *pen_data, QSpanData *brush_data); + struct QRasterFloatPoint { qreal x; qreal y; @@ -428,8 +470,8 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) if (device->devType() == QInternal::Pixmap) { QPixmap *pixmap = static_cast(device); - QPixmapData *pd = pixmap->pixmapData(); - if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass) + QPlatformPixmap *pd = pixmap->handle(); + if (pd->classId() == QPlatformPixmap::RasterClass || pd->classId() == QPlatformPixmap::BlitterClass) d->device = pd->buffer(); } else { d->device = device; @@ -475,16 +517,10 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) } #endif -#if defined(Q_OS_WIN) - d->isPlain45DegreeRotation = true; -#endif - if (d->mono_surface) d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono; #if defined(Q_OS_WIN) else if (clearTypeFontsEnabled()) -#elif defined (Q_WS_MAC) - else if (qt_applefontsmoothing_enabled) #else else if (false) #endif @@ -582,33 +618,6 @@ void QRasterPaintEngine::updateMatrix(const QTransform &matrix) s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale); ensureOutlineMapper(); - -#ifdef Q_OS_WIN - Q_D(QRasterPaintEngine); - d->isPlain45DegreeRotation = false; - if (txop >= QTransform::TxRotate) { - d->isPlain45DegreeRotation = - (qFuzzyIsNull(matrix.m11()) - && qFuzzyIsNull(matrix.m12() - qreal(1)) - && qFuzzyIsNull(matrix.m21() + qreal(1)) - && qFuzzyIsNull(matrix.m22()) - ) - || - (qFuzzyIsNull(matrix.m11() + qreal(1)) - && qFuzzyIsNull(matrix.m12()) - && qFuzzyIsNull(matrix.m21()) - && qFuzzyIsNull(matrix.m22() + qreal(1)) - ) - || - (qFuzzyIsNull(matrix.m11()) - && qFuzzyIsNull(matrix.m12() + qreal(1)) - && qFuzzyIsNull(matrix.m21() - qreal(1)) - && qFuzzyIsNull(matrix.m22()) - ) - ; - } -#endif - } @@ -635,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; @@ -761,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... @@ -775,11 +785,12 @@ void QRasterPaintEngine::updatePen(const QPen &pen) s->stroker = 0; } - ensureState(); // needed because of tx_noshear... + 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) - || (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; @@ -843,7 +854,7 @@ void QRasterPaintEngine::updateOutlineMapper() d->outlineMapper->setMatrix(state()->matrix); } -void QRasterPaintEngine::updateState() +void QRasterPaintEngine::updateRasterState() { QRasterPaintEngineState *s = state(); @@ -918,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; @@ -1060,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) @@ -1178,8 +1192,7 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) const QPainterPath::ElementType *types = path.elements(); // There are some cases that are not supported by clip(QRect) - if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip - || s->clip->hasRectClip || s->clip->hasRegionClip)) { + if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) { if (s->matrix.type() <= QTransform::TxScale && ((path.shape() == QVectorPath::RectangleHint) || (isRect(points, path.elementCount()) @@ -1222,18 +1235,6 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) newClip->fixup(); - if (op == Qt::UniteClip) { - // merge clips - QClipData *result = new QClipData(d->rasterBuffer->height()); - QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height()); - qt_merge_clip(current, newClip, result); - result->fixup(); - delete newClip; - if (!s->clip) - delete current; - newClip = result; - } - if (s->flags.has_clip_ownership) delete s->clip; @@ -1259,7 +1260,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) if (op == Qt::NoClip) { qrasterpaintengine_state_setNoClip(s); - } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) { + } else if (s->matrix.type() > QTransform::TxScale) { QPaintEngineEx::clip(rect, op); return; @@ -1344,7 +1345,6 @@ void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) if (op == Qt::NoClip) { qrasterpaintengine_state_setNoClip(s); } else if (s->matrix.type() > QTransform::TxScale - || op == Qt::UniteClip || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip) || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) { QPaintEngineEx::clip(region, op); @@ -1377,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) @@ -1490,7 +1497,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount); #endif Q_D(QRasterPaintEngine); - ensureState(); + ensureRasterState(); QRasterPaintEngineState *s = state(); // Fill @@ -1522,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); @@ -1545,7 +1553,7 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) #endif #ifdef QT_FAST_SPANS Q_D(QRasterPaintEngine); - ensureState(); + ensureRasterState(); QRasterPaintEngineState *s = state(); @@ -1568,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); @@ -1601,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; @@ -1656,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()); - int y1 = qRound(rect.y()); - int x2 = qRound(rect.right()); - int y2 = qRound(rect.bottom()); + 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); @@ -1701,7 +1715,7 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d); return; } - ensureState(); + ensureRasterState(); if (s->flags.tx_noshear) { d->initializeRasterizer(&s->brushData); // ### Is normalizing really necessary here? @@ -1758,7 +1772,7 @@ void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data) return; } } - ensureState(); + ensureRasterState(); if (s->flags.tx_noshear) { d->initializeRasterizer(data); QRectF nr = r.normalized(); @@ -1930,9 +1944,8 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly if (mode != PolylineMode) { // Do the fill... ensureBrush(); - if (s->brushData.blend) { + if (s->brushData.blend) fillPolygon(points, pointCount, mode); - } } // Do the outline... @@ -1940,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); @@ -1998,19 +2012,13 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg if (s->penData.blend) { int count = pointCount * 2; QVarLengthArray fpoints(count); - #ifdef Q_WS_MAC - for (int i=0; iflags.fast_pen) { QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPath(vp); } else { QPaintEngineEx::stroke(vp, s->lastPen); @@ -2027,9 +2035,9 @@ void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap) qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth(); #endif - QPixmapData *pd = pixmap.pixmapData(); - if (pd->classId() == QPixmapData::RasterClass) { - const QImage &image = static_cast(pd)->image; + QPlatformPixmap *pd = pixmap.handle(); + if (pd->classId() == QPlatformPixmap::RasterClass) { + const QImage &image = static_cast(pd)->image; if (image.depth() == 1) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); @@ -2068,9 +2076,9 @@ void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, cons qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth(); #endif - QPixmapData* pd = pixmap.pixmapData(); - if (pd->classId() == QPixmapData::RasterClass) { - const QImage &image = static_cast(pd)->image; + QPlatformPixmap* pd = pixmap.handle(); + if (pd->classId() == QPlatformPixmap::RasterClass) { + const QImage &image = static_cast(pd)->image; if (image.depth() == 1) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); @@ -2108,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); @@ -2148,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 { @@ -2247,8 +2245,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe int sr_b = qCeil(sr.bottom()) - 1; if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) { + // as fillRect will apply the aliased coordinate delta we need to + // subtract it here as we don't use it for image drawing QTransform old = s->matrix; + 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); switch (img.format()) { @@ -2349,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(), @@ -2386,14 +2405,17 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe } #ifdef QT_FAST_SPANS - ensureState(); + ensureRasterState(); 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.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF(); const QRectF &rect = r.normalized(); - const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f); - const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f); + const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs; + const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs; if (s->flags.tx_noshear) d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width()); @@ -2402,12 +2424,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe return; } #endif + const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0); QPainterPath path; path.addRect(r); QTransform m = s->matrix; s->matrix = QTransform(m.m11(), m.m12(), m.m13(), m.m21(), m.m22(), m.m23(), - m.m31(), m.m32(), m.m33()); + m.m31() - offs, m.m32() - offs, m.m33()); fillPath(path, &d->image_filler_xform); s->matrix = m; } else { @@ -2457,9 +2480,9 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, QImage image; - QPixmapData *pd = pixmap.pixmapData(); - if (pd->classId() == QPixmapData::RasterClass) { - image = static_cast(pd)->image; + QPlatformPixmap *pd = pixmap.handle(); + if (pd->classId() == QPlatformPixmap::RasterClass) { + image = static_cast(pd)->image; } else { image = pixmap.toImage(); } @@ -2478,10 +2501,11 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, d->image_filler_xform.setupMatrix(copy, s->flags.bilinear); #ifdef QT_FAST_SPANS - ensureState(); + ensureRasterState(); 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); @@ -2520,6 +2544,15 @@ static inline bool monoVal(const uchar* s, int x) /*! \internal + */ +QRasterBuffer *QRasterPaintEngine::rasterBuffer() +{ + Q_D(QRasterPaintEngine); + return d->rasterBuffer.data(); +} + +/*! + \internal */ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h) { @@ -2744,97 +2777,42 @@ 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) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); -#if !defined(QT_NO_FREETYPE) - if (fontEngine->type() == QFontEngine::Freetype) { - QFontEngineFT *fe = static_cast(fontEngine); - QFontEngineFT::GlyphFormat neededFormat = + if (fontEngine->hasInternalCaching()) { + QFontEngine::GlyphFormat neededFormat = painter()->device()->devType() == QInternal::Widget - ? fe->defaultGlyphFormat() - : QFontEngineFT::Format_A8; - - if (d_func()->mono_surface - || fe->isBitmapFont() // alphaPenBlt can handle mono, too - ) - neededFormat = QFontEngineFT::Format_Mono; - - if (neededFormat == QFontEngineFT::Format_None) - neededFormat = QFontEngineFT::Format_A8; - - QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs(); - if (s->matrix.type() >= QTransform::TxScale) { - if (s->matrix.isAffine()) - gset = fe->loadTransformedGlyphSet(s->matrix); - else - gset = 0; - } - - if (!gset || gset->outline_drawing - || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat)) - return false; + ? QFontEngine::Format_None + : QFontEngine::Format_A8; - FT_Face lockedFace = 0; - - int depth; - switch (neededFormat) { - case QFontEngineFT::Format_Mono: - depth = 1; - break; - case QFontEngineFT::Format_A8: - depth = 8; - break; - case QFontEngineFT::Format_A32: - depth = 32; - break; - default: - Q_ASSERT(false); - depth = 0; - }; + if (d_func()->mono_surface) // alphaPenBlt can handle mono, too + neededFormat = QFontEngine::Format_Mono; for (int i = 0; i < numGlyphs; i++) { - QFixed spp = fe->subPixelPositionForX(positions[i].x); - QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp); - - if (!glyph || glyph->format != neededFormat) { - if (!lockedFace) - lockedFace = fe->lockFace(); - glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat); - } + QFixed spp = fontEngine->subPixelPositionForX(positions[i].x); - if (!glyph || !glyph->data) + QPoint offset; + QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix, + &offset); + if (alphaMap == 0 || alphaMap->isNull()) continue; - int pitch; - switch (neededFormat) { - case QFontEngineFT::Format_Mono: - pitch = ((glyph->width + 31) & ~31) >> 3; - break; - case QFontEngineFT::Format_A8: - pitch = (glyph->width + 3) & ~3; - break; - case QFontEngineFT::Format_A32: - pitch = glyph->width * 4; - break; - default: - Q_ASSERT(false); - pitch = 0; - }; - - alphaPenBlt(glyph->data, pitch, depth, - qFloor(positions[i].x) + glyph->x, - qFloor(positions[i].y) - glyph->y, - glyph->width, glyph->height); + alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(), + qFloor(positions[i].x) + offset.x(), + qRound(positions[i].y) + offset.y(), + alphaMap->width(), alphaMap->height()); + + fontEngine->unlockAlphaMapForGlyph(); } - if (lockedFace) - fe->unlockFace(); - } else -#endif - { + + } else { QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; QImageTextureGlyphCache *cache = @@ -2858,18 +2836,18 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, else if (depth == 1) rightShift = 3; // divide by 8 - int margin = cache->glyphMargin(); + int margin = fontEngine->glyphMargin(glyphType); const uchar *bits = image.bits(); for (int i=0; isubPixelPositionForX(positions[i].x); + QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x); QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition); const QTextureGlyphCache::Coord &c = cache->coords[glyph]; if (c.isNull()) continue; int x = qFloor(positions[i].x) + c.baseLineX - margin; - int y = qFloor(positions[i].y) - c.baseLineY - margin; + int y = qRound(positions[i].y) - c.baseLineY - margin; // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n", // c.x, c.y, @@ -2885,44 +2863,6 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, return true; } -#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) -void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti) -{ - Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - QFontEngine *fontEngine = ti.fontEngine; - if (fontEngine->type() != QFontEngine::S60FontEngine) { - QPaintEngineEx::drawTextItem(p, ti); - return; - } - - QFontEngineS60 *fe = static_cast(fontEngine); - - QVarLengthArray positions; - QVarLengthArray glyphs; - QTransform matrix = s->matrix; - matrix.translate(p.x(), p.y()); - if (matrix.type() == QTransform::TxScale) - fe->setFontScale(matrix.m11()); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - - for (int i=0; igetCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize); - const int x = qFloor(positions[i].x + tmetrics.HorizBearingX()); - const int y = qFloor(positions[i].y - tmetrics.HorizBearingY()); - alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight); - } - - if (matrix.type() == QTransform::TxScale) - fe->setFontScale(1.0); - - return; -} -#endif // Q_OS_SYMBIAN && QT_NO_FREETYPE /*! * Returns true if the rectangle is completely within the current clip @@ -3013,21 +2953,81 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect, return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend; } +inline ProcessSpans +QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, + const QSpanData *data) const +{ + Q_Q(const QRasterPaintEngine); + const QRasterPaintEngineState *s = q->state(); + + if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate) + return data->blend; + const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF()); + return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; +} + +static QPair visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine, + glyph_t *glyphs, QFixedPoint *positions, int numGlyphs) +{ + QFixed clipLeft = QFixed::fromReal(clip.left()); + QFixed clipRight = QFixed::fromReal(clip.right()); + QFixed clipTop = QFixed::fromReal(clip.top()); + QFixed clipBottom = QFixed::fromReal(clip.bottom()); + + int first = 0; + while (first < numGlyphs) { + glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]); + QFixed left = metrics.x + positions[first].x; + QFixed top = metrics.y + positions[first].y; + QFixed right = left + metrics.width; + QFixed bottom = top + metrics.height; + if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop) + break; + ++first; + } + int last = numGlyphs - 1; + while (last > first) { + glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]); + QFixed left = metrics.x + positions[last].x; + QFixed top = metrics.y + positions[last].y; + QFixed right = left + metrics.width; + QFixed bottom = top + metrics.height; + if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop) + break; + --last; + } + return QPair(first, last + 1); +} + /*! \reimp */ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { - ensurePen(); - ensureState(); + if (textItem->numGlyphs == 0) + return; - QRasterPaintEngineState *s = state(); + ensurePen(); + ensureRasterState(); QFontEngine *fontEngine = textItem->fontEngine(); - const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) < 64 * 64) { + if (!supportsTransformations(fontEngine)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); + } else if (state()->matrix.type() < QTransform::TxProject) { + bool invertible; + QTransform invMat = state()->matrix.inverted(&invertible); + if (!invertible) + return; + + QPair range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()), + textItem->fontEngine(), textItem->glyphs, + textItem->glyphPositions, textItem->numGlyphs); + QStaticTextItem copy = *textItem; + copy.glyphs += range.first; + copy.glyphPositions += range.first; + copy.numGlyphs = range.second - range.first; + QPaintEngineEx::drawStaticTextItem(©); } else { QPaintEngineEx::drawStaticTextItem(textItem); } @@ -3039,7 +3039,6 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) { const QTextItemInt &ti = static_cast(textItem); - QRasterPaintEngineState *s = state(); #ifdef QT_DEBUG_DRAW Q_D(QRasterPaintEngine); @@ -3048,119 +3047,51 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte d->glyphCacheType); #endif + if (ti.glyphs.numGlyphs == 0) + return; ensurePen(); - ensureState(); - -#if defined (Q_OS_WIN) || defined(Q_WS_MAC) - - bool drawCached = true; + ensureRasterState(); - if (s->matrix.type() >= QTransform::TxProject) - drawCached = false; - - // don't try to cache huge fonts - const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64) - drawCached = false; - - // ### Remove the TestFontEngine and Box engine crap, in these - // ### cases we should delegate painting to the font engine - // ### directly... - -/* - #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) - conQFontEngine::Type fontEngineType = ti.fontEngine->type(); - // qDebug() << "type" << fontEngineType << s->matrix.type(); - if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate) - || (s->matrix.type() <= QTransform::TxTranslate - && (fontEngineType == QFontEngine::TestFontEngine - || fontEngineType == QFontEngine::Box))) { - drawCached = false; - } -#else -*/ - if (s->matrix.type() > QTransform::TxTranslate) - drawCached = false; -// #endif - if (drawCached) { - QRasterPaintEngineState *s = state(); + QRasterPaintEngineState *s = state(); + QTransform matrix = s->matrix; + if (!supportsTransformations(ti.fontEngine)) { QVarLengthArray positions; QVarLengthArray glyphs; - QTransform matrix = s->matrix; matrix.translate(p.x(), p.y()); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine); - return; - } - -#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_OS_WIN || Q_WS_MAC - if (s->matrix.type() <= QTransform::TxTranslate - || (s->matrix.type() == QTransform::TxScale - && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) { - drawGlyphsS60(p, ti); - return; - } -#else // Q_OS_WIN || Q_WS_MAC - - QFontEngine *fontEngine = ti.fontEngine; - -#ifdef Q_WS_QPA - if (s->matrix.type() < QTransform::TxScale) { + } else if (matrix.type() < QTransform::TxProject) { + bool invertible; + QTransform invMat = matrix.inverted(&invertible); + if (!invertible) + return; QVarLengthArray positions; QVarLengthArray glyphs; - QTransform matrix = state()->transform(); - qreal _x = qFloor(p.x()); - qreal _y = qFloor(p.y()); - matrix.translate(_x, _y); + ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()), + ti.flags, glyphs, positions); + QPair range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()), + ti.fontEngine, glyphs.data(), positions.data(), + glyphs.size()); - fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - if (glyphs.size() == 0) + if (range.first >= range.second) return; - for(int i = 0; i < glyphs.size(); i++) { - QImage img = fontEngine->alphaMapForGlyph(glyphs[i]); - glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]); - alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(), - qRound(positions[i].x + metrics.x), - qRound(positions[i].y + metrics.y), - img.width(), img.height()); - } - return; - } -#endif //Q_WS_QPA - -#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE) - - if (fontEngine->type() != QFontEngine::Freetype) { + QStaticTextItem staticTextItem; + staticTextItem.color = s->pen.color(); + staticTextItem.font = s->font; + staticTextItem.setFontEngine(ti.fontEngine); + staticTextItem.numGlyphs = range.second - range.first; + staticTextItem.glyphs = glyphs.data() + range.first; + staticTextItem.glyphPositions = positions.data() + range.first; + QPaintEngineEx::drawStaticTextItem(&staticTextItem); + } else { QPaintEngineEx::drawTextItem(p, ti); - return; } - - QFontEngineFT *fe = static_cast(fontEngine); - - QTransform matrix = s->matrix; - matrix.translate(p.x(), p.y()); - - QVarLengthArray positions; - QVarLengthArray glyphs; - fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - if (glyphs.size() == 0) - return; - - if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine)) - QPaintEngine::drawTextItem(p, ti); - - return; -#endif -#endif - - QPaintEngineEx::drawTextItem(p, ti); } /*! @@ -3181,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); } @@ -3200,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); } @@ -3220,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; ilastPen) == Qt::SolidLine && s->flags.fast_pen) + || (qpen_style(s->lastPen) == Qt::NoPen)) + && !s->flags.antialiased + && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT + && !rect.isEmpty() + && s->matrix.type() <= QTransform::TxScale) // no shear + { + ensureBrush(); + const QRectF r = s->matrix.mapRect(rect); + ProcessSpans penBlend = d->getPenFunc(r, &s->penData); + ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData); + const QRect brect = QRect(int(r.x()), int(r.y()), + int_dim(r.x(), r.width()), + int_dim(r.y(), r.height())); + if (brect == r) { + drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend, + &s->penData, &s->brushData); + return; + } + } QPaintEngineEx::drawEllipse(rect); } + +#ifdef Q_OS_WIN /*! \internal */ -#ifdef Q_WS_MAC -void QRasterPaintEngine::setCGContext(CGContextRef ctx) -{ +void QRasterPaintEngine::setDC(HDC hdc) { Q_D(QRasterPaintEngine); - d->cgContext = ctx; + d->hdc = hdc; } /*! \internal */ -CGContextRef QRasterPaintEngine::getCGContext() const +HDC QRasterPaintEngine::getDC() const { Q_D(const QRasterPaintEngine); - return d->cgContext; + return d->hdc; } -#endif -#ifdef Q_OS_WIN /*! \internal */ -void QRasterPaintEngine::setDC(HDC hdc) { - Q_D(QRasterPaintEngine); - d->hdc = hdc; +void QRasterPaintEngine::releaseDC(HDC) const +{ } +#endif + /*! \internal */ -HDC QRasterPaintEngine::getDC() const +bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const { - Q_D(const QRasterPaintEngine); - return d->hdc; + const QTransform &m = state()->matrix; + return supportsTransformations(fontEngine, m); } /*! \internal */ -void QRasterPaintEngine::releaseDC(HDC) const +bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const { -} + if (fontEngine->supportsTransformations(m)) + return true; -#endif + return !shouldDrawCachedGlyphs(fontEngine, m); +} /*! \internal @@ -3403,7 +3363,7 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp spans[n].y = y; spans[n].coverage = 255; int len = 1; - while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) { + while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) { ++src_x; ++len; } @@ -3429,7 +3389,7 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp spans[n].y = y; spans[n].coverage = 255; int len = 1; - while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) { + while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) { ++src_x; ++len; } @@ -3492,82 +3452,13 @@ QRect QRasterPaintEngine::clipBoundingRect() const return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin); } -static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result) -{ - Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight); - - QVarLengthArray buffer; - - QClipData::ClipLine *c1ClipLines = const_cast(c1)->clipLines(); - QClipData::ClipLine *c2ClipLines = const_cast(c2)->clipLines(); - result->initialize(); - - for (int y = 0; y < c1->clipSpanHeight; ++y) { - const QSpan *c1_spans = c1ClipLines[y].spans; - int c1_count = c1ClipLines[y].count; - const QSpan *c2_spans = c2ClipLines[y].spans; - int c2_count = c2ClipLines[y].count; - - if (c1_count == 0 && c2_count == 0) - continue; - if (c1_count == 0) { - result->appendSpans(c2_spans, c2_count); - continue; - } else if (c2_count == 0) { - result->appendSpans(c1_spans, c1_count); - continue; - } - - // we need to merge the two - - // find required length - int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len, - c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len); - buffer.resize(max); - memset(buffer.data(), 0, buffer.size() * sizeof(short)); - - // Fill with old spans. - for (int i = 0; i < c1_count; ++i) { - const QSpan *cs = c1_spans + i; - for (int j=cs->x; jx + cs->len; ++j) - buffer[j] = cs->coverage; - } - - // Fill with new spans - for (int i = 0; i < c2_count; ++i) { - const QSpan *cs = c2_spans + i; - for (int j = cs->x; j < cs->x + cs->len; ++j) { - buffer[j] += cs->coverage; - if (buffer[j] > 255) - buffer[j] = 255; - } - } - - int x = 0; - while (x= max) break; - - int sx = x; - int coverage = buffer[x]; - - // Find length of span - while (x < max && buffer[x] == coverage) - ++x; - - result->appendSpan(sx, x - sx, y, coverage); - } - } -} - void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data) { Q_Q(QRasterPaintEngine); QRasterPaintEngineState *s = q->state(); rasterizer->setAntialiased(s->flags.antialiased); + rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding); QRect clipRect(deviceRect); ProcessSpans blend; @@ -3615,6 +3506,11 @@ extern "C" { int q_gray_rendered_spans(QT_FT_Raster raster); } +static inline uchar *alignAddress(uchar *address, quintptr alignmentMask) +{ + return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask); +} + void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, ProcessSpans callback, void *userData, QRasterBuffer *) @@ -3627,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); @@ -3642,19 +3539,10 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, // minimize memory reallocations. However if initial size for // raster pool is changed for lower value, reallocations will // occur normally. - const int rasterPoolInitialSize = MINIMUM_POOL_SIZE; - int rasterPoolSize = rasterPoolInitialSize; - unsigned char *rasterPoolBase; -#if defined(Q_OS_WIN64) - rasterPoolBase = - // We make use of setjmp and longjmp in qgrayraster.c which requires - // 16-byte alignment, hence we hardcode this requirement here.. - (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2); -#else - unsigned char rasterPoolOnStack[rasterPoolInitialSize]; - rasterPoolBase = rasterPoolOnStack; -#endif - Q_CHECK_PTR(rasterPoolBase); + int rasterPoolSize = MINIMUM_POOL_SIZE; + uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf]; + uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf); + uchar *rasterPoolOnHeap = 0; qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize); @@ -3690,31 +3578,20 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, // Out of memory, reallocate some more and try again... if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c - int new_size = rasterPoolSize * 2; - if (new_size > 1024 * 1024) { + rasterPoolSize *= 2; + if (rasterPoolSize > 1024 * 1024) { qWarning("QPainter: Rasterization of primitive failed"); break; } rendered_spans += q_gray_rendered_spans(*grayRaster.data()); -#if defined(Q_OS_WIN64) - _aligned_free(rasterPoolBase); -#else - if (rasterPoolBase != rasterPoolOnStack) // initially on the stack - free(rasterPoolBase); -#endif + free(rasterPoolOnHeap); + rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf); - rasterPoolSize = new_size; - rasterPoolBase = -#if defined(Q_OS_WIN64) - // We make use of setjmp and longjmp in qgrayraster.c which requires - // 16-byte alignment, hence we hardcode this requirement here.. - (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2); -#else - (unsigned char *) malloc(rasterPoolSize); -#endif - Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal. + Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal. + + rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf); qt_ft_grays_raster.raster_done(*grayRaster.data()); qt_ft_grays_raster.raster_new(grayRaster.data()); @@ -3724,12 +3601,7 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, } } -#if defined(Q_OS_WIN64) - _aligned_free(rasterPoolBase); -#else - if (rasterPoolBase != rasterPoolOnStack) // initially on the stack - free(rasterPoolBase); -#endif + free(rasterPoolOnHeap); } void QRasterPaintEnginePrivate::recalculateFastImages() @@ -4227,7 +4099,6 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData) } break; - case Qt::UniteClip: case Qt::ReplaceClip: clipData->newClip->appendSpans(spans, count); break; @@ -4717,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 @@ -4727,8 +4598,6 @@ void QSpanData::setupMatrix(const QTransform &matrix, int bilin) adjustSpanMethods(); } -extern const QVector *qt_image_colortable(const QImage &image); - void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect) { const QImageData *d = const_cast(image)->data_ptr(); @@ -4773,25 +4642,133 @@ void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _ adjustSpanMethods(); } - /*! - \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) - \overload + \internal + \a x and \a y is relative to the midpoint of \a rect. +*/ +static inline void drawEllipsePoints(int x, int y, int length, + const QRect &rect, + const QRect &clip, + ProcessSpans pen_func, ProcessSpans brush_func, + QSpanData *pen_data, QSpanData *brush_data) +{ + if (length == 0) + return; - Draws the first \a pointCount points in the buffer \a points + QT_FT_Span outline[4]; + const int midx = rect.x() + (rect.width() + 1) / 2; + const int midy = rect.y() + (rect.height() + 1) / 2; + + x = x + midx; + y = midy - y; + + // topleft + outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1); + outline[0].len = qMin(length, x - outline[0].x); + outline[0].y = y; + outline[0].coverage = 255; + + // topright + outline[1].x = x; + outline[1].len = length; + outline[1].y = y; + outline[1].coverage = 255; + + // bottomleft + outline[2].x = outline[0].x; + outline[2].len = outline[0].len; + outline[2].y = midy + (midy - y) - (rect.height() & 0x1); + outline[2].coverage = 255; + + // bottomright + outline[3].x = x; + outline[3].len = length; + outline[3].y = outline[2].y; + outline[3].coverage = 255; + + if (brush_func && outline[0].x + outline[0].len < outline[1].x) { + QT_FT_Span fill[2]; + + // top fill + fill[0].x = outline[0].x + outline[0].len - 1; + fill[0].len = qMax(0, outline[1].x - fill[0].x); + fill[0].y = outline[1].y; + fill[0].coverage = 255; + + // bottom fill + fill[1].x = outline[2].x + outline[2].len - 1; + fill[1].len = qMax(0, outline[3].x - fill[1].x); + fill[1].y = outline[3].y; + fill[1].coverage = 255; + + int n = (fill[0].y >= fill[1].y ? 1 : 2); + n = qt_intersect_spans(fill, n, clip); + if (n > 0) + brush_func(n, fill, brush_data); + } + if (pen_func) { + int n = (outline[1].y >= outline[2].y ? 2 : 4); + n = qt_intersect_spans(outline, n, clip); + if (n > 0) + pen_func(n, outline, pen_data); + } +} - The default implementation converts the first \a pointCount QPoints in \a points - to QPointFs and calls the floating point version of drawPoints. +/*! + \internal + Draws an ellipse using the integer point midpoint algorithm. */ +static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, + ProcessSpans pen_func, ProcessSpans brush_func, + QSpanData *pen_data, QSpanData *brush_data) +{ + const qreal a = qreal(rect.width()) / 2; + const qreal b = qreal(rect.height()) / 2; + qreal d = b*b - (a*a*b) + 0.25*a*a; + + int x = 0; + int y = (rect.height() + 1) / 2; + int startx = x; + + // region 1 + while (a*a*(2*y - 1) > 2*b*b*(x + 1)) { + if (d < 0) { // select E + d += b*b*(2*x + 3); + ++x; + } else { // select SE + d += b*b*(2*x + 3) + a*a*(-2*y + 2); + drawEllipsePoints(startx, y, x - startx + 1, rect, clip, + pen_func, brush_func, pen_data, brush_data); + startx = ++x; + --y; + } + } + drawEllipsePoints(startx, y, x - startx + 1, rect, clip, + pen_func, brush_func, pen_data, brush_data); + + // region 2 + d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b); + const int miny = rect.height() & 0x1; + while (y > miny) { + if (d < 0) { // select SE + d += b*b*(2*x + 2) + a*a*(-2*y + 3); + ++x; + } else { // select S + d += a*a*(-2*y + 3); + } + --y; + drawEllipsePoints(x, y, 1, rect, clip, + pen_func, brush_func, pen_data, brush_data); + } +} /*! - \fn void QRasterPaintEngine::drawEllipse(const QRect &rect) + \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) \overload - - Reimplement this function to draw the largest ellipse that can be - contained within rectangle \a rect. + \reimp */ + #ifdef QT_DEBUG_DRAW void dumpClip(int width, int height, const QClipData *clip) {