X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fgui%2Fpainting%2Fqpaintengine_raster.cpp;h=0e9129f8c01c9a7bb3546c7186dffce538546a4a;hb=49ba35b9904a05ec1c7d768f8c079ce3c7d283fe;hp=2119e307d7e06c0497736e8d1ac0c298ab3915e7;hpb=d4a50774469e92a7c55bf0b184fe8e9e29d2c1cf;p=profile%2Fivi%2Fqtbase.git diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 2119e30..0e9129f 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1,17 +1,18 @@ /**************************************************************************** ** -** 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$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. +** 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 @@ -21,18 +22,17 @@ ** 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. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** +** 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$ @@ -51,14 +51,9 @@ #include #include #include -#include #include #include -#if defined (Q_WS_X11) -# include -#endif - // #include // #include #include @@ -69,44 +64,74 @@ // #include #include #include +#include #include "qmemrotate_p.h" #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" #include "qoutlinemapper_p.h" -#if defined(Q_WS_WIN) -# include +#include + +#ifdef Q_OS_WIN # include # include -# if defined(Q_OS_WINCE) -# include "qguifunctions_wince.h" -# endif -#elif defined(Q_WS_MAC) -# include -# include -# include -#elif defined(Q_WS_QWS) -# if !defined(QT_NO_FREETYPE) -# include -# endif -# if !defined(QT_NO_QWS_QPF2) -# include +# include +#ifdef Q_OS_WIN64 +# include # endif -# include -#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) -# include -#elif defined(Q_WS_QPA) -# include -#endif - -#if defined(Q_WS_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)) @@ -126,13 +151,32 @@ void dumpClip(int width, int height, const QClipData *clip); // 4 pixels. #define int_dim(pos, dim) (int(pos+dim) - int(pos)) -#ifdef Q_WS_WIN -extern bool qt_cleartype_enabled; -#endif +static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; + +#ifdef Q_OS_WIN -#ifdef Q_WS_MAC -extern bool qt_applefontsmoothing_enabled; +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(); + return result; +} + +#endif // Q_OS_WIN + /******************************************************************************** @@ -141,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 { @@ -156,16 +199,6 @@ enum LineDrawMode { LineDrawIncludeLastPixel }; -static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &rect); -static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2, - QPen *pen, ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &devRect, - int *patternOffset); -// static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2, -// ProcessSpans span_func, QSpanData *data, -// LineDrawMode style, const QRect &devRect); - static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, ProcessSpans pen_func, ProcessSpans brush_func, QSpanData *pen_data, QSpanData *brush_data); @@ -338,7 +371,7 @@ void QRasterPaintEngine::init() Q_D(QRasterPaintEngine); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN d->hdc = 0; #endif @@ -384,11 +417,6 @@ void QRasterPaintEngine::init() case QInternal::Image: format = d->rasterBuffer->prepare(static_cast(d->device)); break; -#ifdef Q_WS_QWS - case QInternal::CustomRaster: - d->rasterBuffer->prepare(static_cast(d->device)); - break; -#endif default: qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType()); d->device = 0; @@ -442,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; @@ -489,16 +517,10 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) } #endif -#if defined(Q_WS_WIN) - d->isPlain45DegreeRotation = true; -#endif - if (d->mono_surface) d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono; -#if defined(Q_WS_WIN) - else if (qt_cleartype_enabled) -#elif defined (Q_WS_MAC) - else if (qt_applefontsmoothing_enabled) +#if defined(Q_OS_WIN) + else if (clearTypeFontsEnabled()) #else else if (false) #endif @@ -596,33 +618,6 @@ void QRasterPaintEngine::updateMatrix(const QTransform &matrix) s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale); ensureOutlineMapper(); - -#ifdef Q_WS_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 - } @@ -649,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; @@ -775,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... @@ -789,14 +785,13 @@ void QRasterPaintEngine::updatePen(const QPen &pen) s->stroker = 0; } + 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 - && !s->flags.antialiased - && (penWidth == 0 || (penWidth <= 1 - && (s->matrix.type() <= QTransform::TxTranslate - || pen.isCosmetic()))); + && s->penData.blend + && ((cosmetic && penWidth <= 1) + || (!cosmetic && s->flags.tx_noshear && penWidth * s->txscale <= 1)); - ensureState(); // needed because of tx_noshear... s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear; s->strokeFlags = 0; @@ -859,7 +854,7 @@ void QRasterPaintEngine::updateOutlineMapper() d->outlineMapper->setMatrix(state()->matrix); } -void QRasterPaintEngine::updateState() +void QRasterPaintEngine::updateRasterState() { QRasterPaintEngineState *s = state(); @@ -934,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; @@ -986,13 +982,6 @@ void QRasterPaintEngine::clipEnabledChanged() } } -#ifdef Q_WS_QWS -void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device) -{ - rasterBuffer->prepare(device); -} -#endif - void QRasterPaintEnginePrivate::drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func, @@ -1083,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) @@ -1201,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()) @@ -1245,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; @@ -1282,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; @@ -1367,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); @@ -1400,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) @@ -1513,6 +1497,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount); #endif Q_D(QRasterPaintEngine); + ensureRasterState(); QRasterPaintEngineState *s = state(); // Fill @@ -1541,32 +1526,15 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) ensurePen(); if (s->penData.blend) { - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) { - const QRect *r = rects; - const QRect *lastRect = rects + rectCount; - while (r < lastRect) { - int left = r->x(); - int right = r->x() + r->width(); - int top = r->y(); - int bottom = r->y() + r->height(); - -#ifdef Q_WS_MAC - int pts[] = { top, left, - top, right, - bottom, right, - bottom, left }; -#else - int pts[] = { left, top, - right, top, - right, bottom, - left, bottom }; -#endif - - strokePolygonCosmetic((QPoint *) pts, 4, WindingMode); - ++r; + 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); } } else { - QRectVectorPath path; for (int i = 0; i < rectCount; ++i) { path.set(rects[i]); stroke(path, s->pen); @@ -1581,13 +1549,13 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount) void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) { #ifdef QT_DEBUG_DRAW - qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount); + qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount); #endif #ifdef QT_FAST_SPANS Q_D(QRasterPaintEngine); + ensureRasterState(); QRasterPaintEngineState *s = state(); - ensureState(); if (s->flags.tx_noshear) { ensureBrush(); @@ -1605,59 +1573,18 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) ensurePen(); if (s->penData.blend) { - qreal width = s->pen.isCosmetic() - ? (s->lastPen.widthF() == 0 ? 1 : s->lastPen.widthF()) - : s->lastPen.widthF() * s->txscale; - - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) { - for (int i = 0; i < rectCount; ++i) { - const QRectF &r = rects[i]; - qreal left = r.x(); - qreal right = r.x() + r.width(); - qreal top = r.y(); - qreal bottom = r.y() + r.height(); - qreal pts[] = { left, top, - right, top, - right, bottom, - left, bottom }; - strokePolygonCosmetic((QPointF *) pts, 4, WindingMode); - } - } else if (width <= 1 && qpen_style(s->lastPen) == Qt::SolidLine) { - d->initializeRasterizer(&s->penData); - + 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) { - const QRectF &rect = rects[i].normalized(); - if (rect.isEmpty()) { - qreal pts[] = { rect.left(), rect.top(), rect.right(), rect.bottom() }; - QVectorPath vp(pts, 2, 0, QVectorPath::LinesHint); - QPaintEngineEx::stroke(vp, s->lastPen); - } else { - const QPointF tl = s->matrix.map(rect.topLeft()); - const QPointF tr = s->matrix.map(rect.topRight()); - const QPointF bl = s->matrix.map(rect.bottomLeft()); - const QPointF br = s->matrix.map(rect.bottomRight()); - const qreal w = width / (rect.width() * s->txscale); - const qreal h = width / (rect.height() * s->txscale); - d->rasterizer->rasterizeLine(tl, tr, w); // top - d->rasterizer->rasterizeLine(bl, br, w); // bottom - d->rasterizer->rasterizeLine(bl, tl, h); // left - d->rasterizer->rasterizeLine(br, tr, h); // right - } + path.set(rects[i]); + stroker.drawPath(path); } } else { for (int i = 0; i < rectCount; ++i) { - const QRectF &r = rects[i]; - qreal left = r.x(); - qreal right = r.x() + r.width(); - qreal top = r.y(); - qreal bottom = r.y() + r.height(); - qreal pts[] = { left, top, - right, top, - right, bottom, - left, bottom, - left, top }; - QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint); - QPaintEngineEx::stroke(vp, s->lastPen); + path.set(rects[i]); + QPaintEngineEx::stroke(path, s->lastPen); } } } @@ -1674,38 +1601,19 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount) */ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) { + Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); + ensurePen(pen); if (!s->penData.blend) return; - if (s->flags.fast_pen && !path.isCurved() - && s->lastPen.brush().isOpaque()) { - int count = path.elementCount(); - QPointF *points = (QPointF *) path.points(); - const QPainterPath::ElementType *types = path.elements(); - if (types) { - int first = 0; - int last; - while (first < count) { - while (first < count && types[first] != QPainterPath::MoveToElement) ++first; - last = first + 1; - while (last < count && types[last] == QPainterPath::LineToElement) ++last; - strokePolygonCosmetic(points + first, last - first, - path.hasImplicitClose() && last == count // only close last one.. - ? WindingMode - : PolylineMode); - first = last; - } - } else { - strokePolygonCosmetic(points, count, - path.hasImplicitClose() - ? WindingMode - : PolylineMode); - } - + 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; @@ -1758,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); @@ -1803,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? @@ -1818,26 +1730,6 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) } } - if (path.shape() == QVectorPath::EllipseHint) { - if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) { - const qreal *p = path.points(); - QPointF tl = QPointF(p[0], p[1]) * s->matrix; - QPointF br = QPointF(p[4], p[5]) * s->matrix; - QRectF r = s->matrix.mapRect(QRectF(tl, br)); - - 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; - } - } - } - // ### Optimize for non transformed ellipses and rectangles... QRectF cpRect = path.controlPointRect(); const QRect deviceRect = s->matrix.mapRect(cpRect).toRect(); @@ -1880,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(); @@ -2032,6 +1924,7 @@ void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, Poly */ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) { + Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); #ifdef QT_DEBUG_DRAW @@ -2048,20 +1941,21 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly } ensurePen(); - ensureBrush(); if (mode != PolylineMode) { // Do the fill... - if (s->brushData.blend) { + ensureBrush(); + if (s->brushData.blend) fillPolygon(points, pointCount, mode); - } } // Do the outline... if (s->penData.blend) { - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) - strokePolygonCosmetic(points, pointCount, mode); - else { - QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode)); + 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); } } @@ -2090,13 +1984,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg return; } - ensureState(); ensurePen(); - if (!(s->flags.int_xform && s->flags.fast_pen && (!s->penData.blend || s->pen.brush().isOpaque()))) { - // this calls the float version - QPaintEngineEx::drawPolygon(points, pointCount, mode); - return; - } // Do the fill if (mode != PolylineMode) { @@ -2122,230 +2010,18 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg // Do the outline... if (s->penData.blend) { - if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) - strokePolygonCosmetic(points, pointCount, mode); - else { - int count = pointCount * 2; - QVarLengthArray fpoints(count); -#ifdef Q_WS_MAC - for (int i=0; ilastPen); - } - } -} - -/*! - \internal -*/ -void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointCount, PolygonDrawMode mode) -{ - Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - Q_ASSERT(s->penData.blend); - Q_ASSERT(s->flags.fast_pen); - - bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1]; - - // Use fast path for 0 width / trivial pens. - QIntRect devRect; - devRect.set(d->deviceRect); - - LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap - ? LineDrawIncludeLastPixel - : LineDrawNormal); - int dashOffset = int(s->lastPen.dashOffset()); - - // Draw all the line segments. - for (int i=1; imatrix; - QPointF lp2 = points[i] * s->matrix; - - const QRectF brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) { - drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect); - } else { - drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - &s->lastPen, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect, &dashOffset); - } - } - - // Polygons are implicitly closed. - if (needs_closing) { - QPointF lp1 = points[pointCount-1] * s->matrix; - QPointF lp2 = points[0] * s->matrix; - - const QRectF brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) { - drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - penBlend, &s->penData, - LineDrawIncludeLastPixel, - devRect); + int count = pointCount * 2; + QVarLengthArray fpoints(count); + for (int i=0; iflags.fast_pen) { + QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); + stroker.drawPath(vp); } else { - drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()), - qFloor(lp2.x()), qFloor(lp2.y()), - &s->lastPen, - penBlend, &s->penData, - LineDrawIncludeLastPixel, - devRect, &dashOffset); - } - } - -} - -/*! - \internal -*/ -void QRasterPaintEngine::strokePolygonCosmetic(const QPoint *points, int pointCount, PolygonDrawMode mode) -{ - Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - // We assert here because this function is called from drawRects - // and drawPolygon and they already do ensurePen(), so we skip that - // here to avoid duplicate checks.. - Q_ASSERT(s->penData.blend); - - bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1]; - - QIntRect devRect; - devRect.set(d->deviceRect); - - LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap - ? LineDrawIncludeLastPixel - : LineDrawNormal); - - int m11 = int(s->matrix.m11()); - int m22 = int(s->matrix.m22()); - int dx = int(s->matrix.dx()); - int dy = int(s->matrix.dy()); - int m13 = int(s->matrix.m13()); - int m23 = int(s->matrix.m23()); - bool affine = !m13 && !m23; - - int dashOffset = int(s->lastPen.dashOffset()); - - if (affine) { - // Draw all the line segments. - for (int i=1; imatrix; - const QPoint lp2 = points[i] * s->matrix; - const QRect brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - &s->lastPen, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect, &dashOffset); - - } - - // Polygons are implicitly closed. - if (needs_closing) { - const QPoint lp1 = points[pointCount - 1] * s->matrix; - const QPoint lp2 = points[0] * s->matrix; - const QRect brect(lp1, lp2); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(lp1.x(), lp1.y(), - lp2.x(), lp2.y(), - &s->lastPen, - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect, &dashOffset); - } - } else { - // Draw all the line segments. - for (int i=1; igetPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(x1, y1, x2, y2, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(x1, y1, x2, y2, - &s->lastPen, - penBlend, &s->penData, - i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel, - devRect, &dashOffset); - - } - - int x1 = points[pointCount-1].x() * m11 + dx; - int y1 = points[pointCount-1].y() * m22 + dy; - qreal w = m13*points[pointCount-1].x() + m23*points[pointCount-1].y() + 1.; - w = 1/w; - x1 = int(x1*w); - y1 = int(y1*w); - int x2 = points[0].x() * m11 + dx; - int y2 = points[0].y() * m22 + dy; - w = m13*points[0].x() + m23*points[0].y() + 1.; - w = 1/w; - x2 = int(x2 * w); - y2 = int(y2 * w); - // Polygons are implicitly closed. - - if (needs_closing) { - const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(x1, y1, x2, y2, - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect); - else - drawLine_midpoint_dashed_i(x1, y1, x2, y2, - &s->lastPen, - penBlend, &s->penData, LineDrawIncludeLastPixel, - devRect, &dashOffset); + QPaintEngineEx::stroke(vp, s->lastPen); } } } @@ -2359,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(); @@ -2400,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(); @@ -2440,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); @@ -2480,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 { @@ -2579,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()) { @@ -2681,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(), @@ -2718,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()); @@ -2734,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 { @@ -2789,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(); } @@ -2810,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); @@ -2852,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) { @@ -3076,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; - - FT_Face lockedFace = 0; + ? QFontEngine::Format_None + : QFontEngine::Format_A8; - 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 = @@ -3190,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, @@ -3217,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 @@ -3346,7 +2954,7 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect, } inline ProcessSpans -QRasterPaintEnginePrivate::getPenFunc(const QRect &rect, +QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, const QSpanData *data) const { Q_Q(const QRasterPaintEngine); @@ -3354,21 +2962,41 @@ QRasterPaintEnginePrivate::getPenFunc(const QRect &rect, if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate) return data->blend; - const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->pen.widthF()); + const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF()); return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; } -inline ProcessSpans -QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, - const QSpanData *data) const +static QPair visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine, + glyph_t *glyphs, QFixedPoint *positions, int numGlyphs) { - Q_Q(const QRasterPaintEngine); - const QRasterPaintEngineState *s = q->state(); + QFixed clipLeft = QFixed::fromReal(clip.left()); + QFixed clipRight = QFixed::fromReal(clip.right()); + QFixed clipTop = QFixed::fromReal(clip.top()); + QFixed clipBottom = QFixed::fromReal(clip.bottom()); - 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; + 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); } /*! @@ -3376,11 +3004,33 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, */ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { + if (textItem->numGlyphs == 0) + return; + ensurePen(); - ensureState(); + ensureRasterState(); + + QFontEngine *fontEngine = textItem->fontEngine(); + 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; - drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, - textItem->fontEngine()); + 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); + } } /*! @@ -3389,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); @@ -3398,141 +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_WS_WIN) || defined(Q_WS_MAC) - - bool drawCached = true; - - 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; + ensureRasterState(); - // ### Remove the TestFontEngine and Box engine crap, in these - // ### cases we should delegate painting to the font engine - // ### directly... - -#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) - QFontEngine::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; - } + } else if (matrix.type() < QTransform::TxProject) { + bool invertible; + QTransform invMat = matrix.inverted(&invertible); + if (!invertible) + return; -#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_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_WS_WIN || Q_WS_MAC + QVarLengthArray positions; + QVarLengthArray glyphs; - QFontEngine *fontEngine = ti.fontEngine; + 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()); -#if defined(Q_WS_QWS) - if (fontEngine->type() == QFontEngine::Box) { - fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti); - return; - } - - if (s->matrix.type() < QTransform::TxScale - && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2 - || (fontEngine->type() == QFontEngine::Proxy - && !(static_cast(fontEngine)->drawAsOutline())) - )) { - fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti); - return; - } -#endif // Q_WS_QWS - -#ifdef Q_WS_QPA - if (s->matrix.type() < QTransform::TxScale) { - - QVarLengthArray positions; - QVarLengthArray glyphs; - QTransform matrix = state()->transform(); - - qreal _x = qFloor(p.x()); - qreal _y = qFloor(p.y()); - matrix.translate(_x, _y); - - fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - if (glyphs.size() == 0) + 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 defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2) - if (fontEngine->type() == QFontEngine::QPF2) { - QFontEngine *renderingEngine = static_cast(fontEngine)->renderingEngine(); - if (renderingEngine) - fontEngine = renderingEngine; - } -#endif - - 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); } /*! @@ -3544,48 +3103,17 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount) QRasterPaintEngineState *s = state(); ensurePen(); - qreal pw = s->lastPen.widthF(); - if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) { - QPaintEngineEx::drawPoints(points, pointCount); - - } else { - if (!s->penData.blend) - return; - - QVarLengthArray array(pointCount); - QT_FT_Span span = { 0, 1, 0, 255 }; - const QPointF *end = points + pointCount; - qreal trans_x, trans_y; - int x, y; - int left = d->deviceRect.x(); - int right = left + d->deviceRect.width(); - int top = d->deviceRect.y(); - int bottom = top + d->deviceRect.height(); - int count = 0; - while (points < end) { - s->matrix.map(points->x(), points->y(), &trans_x, &trans_y); - x = qFloor(trans_x); - y = qFloor(trans_y); - if (x >= left && x < right && y >= top && y < bottom) { - if (count > 0) { - const QT_FT_Span &last = array[count - 1]; - // spans must be sorted on y (primary) and x (secondary) - if (y < last.y || (y == last.y && x < last.x)) { - s->penData.blend(count, array.constData(), &s->penData); - count = 0; - } - } - - span.x = x; - span.y = y; - array[count++] = span; - } - ++points; - } + if (!s->penData.blend) + return; - if (count > 0) - s->penData.blend(count, array.constData(), &s->penData); + if (!s->flags.fast_pen) { + QPaintEngineEx::drawPoints(points, pointCount); + return; } + + QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); + stroker.drawPoints(points, pointCount); } @@ -3595,48 +3123,17 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) QRasterPaintEngineState *s = state(); ensurePen(); - double pw = s->lastPen.widthF(); - if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) { - QPaintEngineEx::drawPoints(points, pointCount); - - } else { - if (!s->penData.blend) - return; - - QVarLengthArray array(pointCount); - QT_FT_Span span = { 0, 1, 0, 255 }; - const QPoint *end = points + pointCount; - qreal trans_x, trans_y; - int x, y; - int left = d->deviceRect.x(); - int right = left + d->deviceRect.width(); - int top = d->deviceRect.y(); - int bottom = top + d->deviceRect.height(); - int count = 0; - while (points < end) { - s->matrix.map(points->x(), points->y(), &trans_x, &trans_y); - x = qFloor(trans_x); - y = qFloor(trans_y); - if (x >= left && x < right && y >= top && y < bottom) { - if (count > 0) { - const QT_FT_Span &last = array[count - 1]; - // spans must be sorted on y (primary) and x (secondary) - if (y < last.y || (y == last.y && x < last.x)) { - s->penData.blend(count, array.constData(), &s->penData); - count = 0; - } - } - - span.x = x; - span.y = y; - array[count++] = span; - } - ++points; - } + if (!s->penData.blend) + return; - if (count > 0) - s->penData.blend(count, array.constData(), &s->penData); + if (!s->flags.fast_pen) { + QPaintEngineEx::drawPoints(points, pointCount); + return; } + + QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); + stroker.drawPoints(points, pointCount); } /*! @@ -3645,59 +3142,23 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount) void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount) { #ifdef QT_DEBUG_DRAW - qDebug() << " - QRasterPaintEngine::drawLine()"; + qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount; #endif Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); ensurePen(); + if (!s->penData.blend) + return; + if (s->flags.fast_pen) { - QIntRect bounds; bounds.set(d->deviceRect); - LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap - ? LineDrawNormal - : LineDrawIncludeLastPixel; - - int m11 = int(s->matrix.m11()); - int m22 = int(s->matrix.m22()); - int dx = qFloor(s->matrix.dx()); - int dy = qFloor(s->matrix.dy()); + QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); for (int i=0; ilastPen.dashOffset()); - if (s->flags.int_xform) { - const QLine &l = lines[i]; - int x1 = l.x1() * m11 + dx; - int y1 = l.y1() * m22 + dy; - int x2 = l.x2() * m11 + dx; - int y2 = l.y2() * m22 + dy; - - const QRect brect(QPoint(x1, y1), QPoint(x2, y2)); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(x1, y1, x2, y2, - penBlend, &s->penData, mode, bounds); - else - drawLine_midpoint_dashed_i(x1, y1, x2, y2, - &s->lastPen, penBlend, - &s->penData, mode, bounds, - &dashOffset); - } else { - QLineF line = lines[i] * s->matrix; - const QRectF brect(QPointF(line.x1(), line.y1()), - QPointF(line.x2(), line.y2())); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - penBlend, &s->penData, mode, bounds); - else - drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - &s->lastPen, penBlend, - &s->penData, mode, bounds, - &dashOffset); - } + const QLine &l = lines[i]; + stroker.drawLine(l.p1(), l.p2()); } - } else if (s->penData.blend) { + } else { QPaintEngineEx::drawLines(lines, lineCount); } } @@ -3754,7 +3215,7 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line, void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) { #ifdef QT_DEBUG_DRAW - qDebug() << " - QRasterPaintEngine::drawLine()"; + qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount; #endif Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); @@ -3763,28 +3224,11 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount) if (!s->penData.blend) return; if (s->flags.fast_pen) { - QIntRect bounds; - bounds.set(d->deviceRect); - LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap - ? LineDrawNormal - : LineDrawIncludeLastPixel; - + QCosmeticStroker stroker(s, d->deviceRect); + stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); for (int i=0; ilastPen.dashOffset()); - QLineF line = lines[i] * s->matrix; - const QRectF brect(QPointF(line.x1(), line.y1()), - QPointF(line.x2(), line.y2())); - ProcessSpans penBlend = d->getPenFunc(brect, &s->penData); - if (qpen_style(s->lastPen) == Qt::SolidLine) - drawLine_midpoint_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - penBlend, &s->penData, mode, bounds); - else - drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()), - int(line.x2()), int(line.y2()), - &s->lastPen, - penBlend, &s->penData, mode, - bounds, &dashOffset); + QLineF line = lines[i]; + stroker.drawLine(line.p1(), line.p2()); } } else { QPaintEngineEx::drawLines(lines, lineCount); @@ -3802,7 +3246,8 @@ void QRasterPaintEngine::drawEllipse(const QRectF &rect) ensurePen(); if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen) - || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased)) + || (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 @@ -3823,27 +3268,8 @@ void QRasterPaintEngine::drawEllipse(const QRectF &rect) QPaintEngineEx::drawEllipse(rect); } -/*! - \internal -*/ -#ifdef Q_WS_MAC -void QRasterPaintEngine::setCGContext(CGContextRef ctx) -{ - Q_D(QRasterPaintEngine); - d->cgContext = ctx; -} - -/*! - \internal -*/ -CGContextRef QRasterPaintEngine::getCGContext() const -{ - Q_D(const QRasterPaintEngine); - return d->cgContext; -} -#endif -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN /*! \internal */ @@ -3873,63 +3299,30 @@ void QRasterPaintEngine::releaseDC(HDC) const /*! \internal */ -QPoint QRasterPaintEngine::coordinateOffset() const +bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const { - return QPoint(0, 0); + const QTransform &m = state()->matrix; + return supportsTransformations(fontEngine, m); } /*! - Draws the given color \a spans with the specified \a color. The \a - count parameter specifies the number of spans. - - The default implementation does nothing; reimplement this function - to draw the given color \a spans with the specified \a color. Note - that this function \e must be reimplemented if the framebuffer is - not memory-mapped. - - \sa drawBufferSpan() + \internal */ -#if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS) -void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color) +bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const { - Q_UNUSED(spans); - Q_UNUSED(count); - Q_UNUSED(color); - qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on " - "a non memory-mapped device"); + if (fontEngine->supportsTransformations(m)) + return true; + + return !shouldDrawCachedGlyphs(fontEngine, m); } /*! - \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha) - - Draws the given \a buffer. - - The default implementation does nothing; reimplement this function - to draw a buffer that contains more than one color. Note that this - function \e must be reimplemented if the framebuffer is not - memory-mapped. - - The \a size parameter specifies the total size of the given \a - buffer, while the \a length parameter specifies the number of - pixels to draw. The buffer's position is given by (\a x, \a - y). The provided \a alpha value is added to each pixel in the - buffer when drawing. - - \sa drawColorSpans() + \internal */ -void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, - int x, int y, int length, uint const_alpha) +QPoint QRasterPaintEngine::coordinateOffset() const { - Q_UNUSED(buffer); - Q_UNUSED(bufsize); - Q_UNUSED(x); - Q_UNUSED(y); - Q_UNUSED(length); - Q_UNUSED(const_alpha); - qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on " - "a non memory-mapped device"); + return QPoint(0, 0); } -#endif // Q_WS_QWS void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg) { @@ -3970,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; } @@ -3996,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; } @@ -4059,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; @@ -4182,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 *) @@ -4194,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); @@ -4209,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_WS_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); @@ -4257,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_WS_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_WS_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()); @@ -4291,12 +3601,7 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, } } -#if defined(Q_WS_WIN64) - _aligned_free(rasterPoolBase); -#else - if (rasterPoolBase != rasterPoolOnStack) // initially on the stack - free(rasterPoolBase); -#endif + free(rasterPoolOnHeap); } void QRasterPaintEnginePrivate::recalculateFastImages() @@ -4378,127 +3683,6 @@ void QRasterBuffer::resetBuffer(int val) memset(m_buffer, val, m_height*bytes_per_line); } - -#if defined(Q_WS_QWS) -void QRasterBuffer::prepare(QCustomRasterPaintDevice *device) -{ - m_buffer = reinterpret_cast(device->memory()); - m_width = qMin(QT_RASTER_COORD_LIMIT, device->width()); - m_height = qMin(QT_RASTER_COORD_LIMIT, device->height()); - bytes_per_pixel = device->depth() / 8; - bytes_per_line = device->bytesPerLine(); - format = device->format(); -#ifndef QT_NO_RASTERCALLBACKS - if (!m_buffer) - drawHelper = qDrawHelperCallback + format; - else -#endif - drawHelper = qDrawHelper + format; -} - -int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const -{ - switch (m) { - case PdmWidth: - return widget->frameGeometry().width(); - case PdmHeight: - return widget->frameGeometry().height(); - default: - break; - } - - return qt_paint_device_metric(widget, m); -} - -int QCustomRasterPaintDevice::bytesPerLine() const -{ - return (width() * depth() + 7) / 8; -} - -#elif defined(Q_OS_SYMBIAN) - -void QRasterBuffer::prepareBuffer(int /* width */, int /* height */) -{ -} - -#endif // Q_OS_SYMBIAN - -/*! - \class QCustomRasterPaintDevice - \preliminary - \ingroup qws - \since 4.2 - - \brief The QCustomRasterPaintDevice class is provided to activate - hardware accelerated paint engines in Qt for Embedded Linux. - - Note that this class is only available in \l{Qt for Embedded Linux}. - - In \l{Qt for Embedded Linux}, painting is a pure software - implementation. But starting with Qt 4.2, it is - possible to add an accelerated graphics driver to take advantage - of available hardware resources. - - Hardware acceleration is accomplished by creating a custom screen - driver, accelerating the copying from memory to the screen, and - implementing a custom paint engine accelerating the various - painting operations. Then a custom paint device (derived from the - QCustomRasterPaintDevice class) and a custom window surface - (derived from QWSWindowSurface) must be implemented to make - \l{Qt for Embedded Linux} aware of the accelerated driver. - - See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux} - documentation for details. - - \sa QRasterPaintEngine, QPaintDevice -*/ - -/*! - \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget) - - Constructs a custom raster based paint device for the given - top-level \a widget. -*/ - -/*! - \fn int QCustomRasterPaintDevice::bytesPerLine() const - - Returns the number of bytes per line in the framebuffer. Note that - this number might be larger than the framebuffer width. -*/ - -/*! - \fn int QCustomRasterPaintDevice::devType() const - \internal -*/ - -/*! - \fn QImage::Format QCustomRasterPaintDevice::format() const - - Returns the format of the device's memory buffet. - - The default format is QImage::Format_ARGB32_Premultiplied. The - only other valid format is QImage::Format_RGB16. -*/ - -/*! - \fn void * QCustomRasterPaintDevice::memory () const - - Returns a pointer to the paint device's memory buffer, or 0 if no - such buffer exists. -*/ - -/*! - \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const - \reimp -*/ - -/*! - \fn QSize QCustomRasterPaintDevice::size () const - \internal -*/ - - QClipData::QClipData(int height) { clipSpanHeight = height; @@ -4821,7 +4005,7 @@ static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userDa while (spans < end) { QSpan *clipped = cspans; spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS); -// qDebug() << "processed " << processed << "clipped" << clipped-cspans +// qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage; if (clipped - cspans) @@ -4915,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; @@ -5223,9 +4406,6 @@ Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache) void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe) { rasterBuffer = rb; -#ifdef Q_WS_QWS - rasterEngine = const_cast(pe); -#endif type = None; txop = 0; bilinear = false; @@ -5371,16 +4551,7 @@ void QSpanData::adjustSpanMethods() unclipped_blend = rasterBuffer->drawHelper->blendGradient; break; case Texture: -#ifdef Q_WS_QWS -#ifndef QT_NO_RASTERCALLBACKS - if (!rasterBuffer->buffer()) - unclipped_blend = qBlendTextureCallback; - else -#endif - unclipped_blend = qBlendTexture; -#else unclipped_blend = qBlendTexture; -#endif if (!texture.imageData) unclipped_blend = 0; @@ -5417,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 @@ -5427,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(); @@ -5473,759 +4642,6 @@ void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _ adjustSpanMethods(); } -#ifdef Q_WS_WIN - - -#endif - - -/*! - \internal - - Draws a line using the floating point midpoint algorithm. The line - \a line is already in device coords at this point. -*/ - -static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &devRect) -{ -#ifdef QT_DEBUG_DRAW - qDebug() << " - drawLine_midpoint_i" << QLine(QPoint(x1, y1), QPoint(x2, y2)); -#endif - - int x, y; - int dx, dy, d, incrE, incrNE; - - dx = x2 - x1; - dy = y2 - y1; - - const int NSPANS = 256; - QT_FT_Span spans[NSPANS]; - int current = 0; - bool ordered = true; - - if (dy == 0) { - // specialcase horizontal lines - if (y1 >= devRect.y1 && y1 < devRect.y2) { - int start = qMax(devRect.x1, qMin(x1, x2)); - int stop = qMax(x1, x2) + 1; - int stop_clipped = qMin(devRect.x2, stop); - int len = stop_clipped - start; - if (style == LineDrawNormal && stop == stop_clipped) - len--; - if (len > 0) { - spans[0].x = ushort(start); - spans[0].len = ushort(len); - spans[0].y = y1; - spans[0].coverage = 255; - span_func(1, spans, data); - } - } - return; - } else if (dx == 0) { - // specialcase vertical lines - if (x1 >= devRect.x1 && x1 < devRect.x2) { - int start = qMax(devRect.y1, qMin(y1, y2)); - int stop = qMax(y1, y2) + 1; - int stop_clipped = qMin(devRect.y2, stop); - int len = stop_clipped - start; - if (style == LineDrawNormal && stop == stop_clipped) - len--; - // hw: create spans directly instead to possibly avoid clipping - if (len > 0) - fillRect_normalized(QRect(x1, start, 1, len).normalized(), data, 0); - } - return; - } - - - if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */ - - if (x2 < x1) { /* if coordinates are out of order */ - qt_swap_int(x1, x2); - dx = -dx; - - qt_swap_int(y1, y2); - dy = -dy; - } - - int x_lower_limit = - 128; - if (x1 < x_lower_limit) { - int cy = dy * (x_lower_limit - x1) / dx + y1; - drawLine_midpoint_i(x_lower_limit, cy, x2, y2, span_func, data, style, devRect); - return; - } - - if (style == LineDrawNormal) - --x2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - x2 = qMin(x2, devRect.x2 - 1); - - // completely clipped, so abort - if (x2 <= x1) { - return; - } - - int x = x1; - int y = y1; - - if (y2 <= y1) - ordered = false; - - { - const int index = (ordered ? current : NSPANS - 1 - current); - spans[index].coverage = 255; - spans[index].x = x; - spans[index].y = y; - - if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2) - spans[index].len = 1; - else - spans[index].len = 0; - } - - if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees) - y2 = qMin(y2, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE - dx; - incrNE = (dy - dx) * 2; - - if (y > y2) - goto flush_and_return; - - while (x < x2) { - ++x; - if (d > 0) { - if (spans[current].len > 0) - ++current; - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - - ++y; - d += incrNE; - if (y > y2) - goto flush_and_return; - - spans[current].len = 0; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - } else { - d += incrE; - if (x == devRect.x1) - spans[current].x = devRect.x1; - } - - if (x < devRect.x1 || y < devRect.y1) - continue; - - Q_ASSERT(x 0) { - ++current; - } - } else { // 0-45 and 180->225 (unit circle degrees) - - y1 = qMin(y1, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE + dx; - incrNE = (dy + dx) * 2; - - if (y < devRect.y1) - goto flush_and_return; - - while (x < x2) { - ++x; - if (d < 0) { - if (spans[NSPANS - 1 - current].len > 0) - ++current; - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - - --y; - d += incrNE; - if (y < devRect.y1) - goto flush_and_return; - - const int index = NSPANS - 1 - current; - spans[index].len = 0; - spans[index].coverage = 255; - spans[index].x = x; - spans[index].y = y; - } else { - d += incrE; - if (x == devRect.x1) - spans[NSPANS - 1 - current].x = devRect.x1; - } - - if (x < devRect.x1 || y > y1) - continue; - - Q_ASSERT(x 0) { - ++current; - } - } - - } else { - - // if y is the major axis: - - if (y2 < y1) { /* if coordinates are out of order */ - qt_swap_int(y1, y2); - dy = -dy; - - qt_swap_int(x1, x2); - dx = -dx; - } - - int y_lower_limit = - 128; - if (y1 < y_lower_limit) { - int cx = dx * (y_lower_limit - y1) / dy + x1; - drawLine_midpoint_i(cx, y_lower_limit, x2, y2, span_func, data, style, devRect); - return; - } - - if (style == LineDrawNormal) - --y2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - y2 = qMin(y2, devRect.y2 - 1); - - // completely clipped, so abort - if (y2 <= y1) { - return; - } - - x = x1; - y = y1; - - if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) { - Q_ASSERT(x >= devRect.x1 && y >= devRect.y1 && x < devRect.x2 && y < devRect.y2); - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - - if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees) - x2 = qMin(x2, devRect.x2 - 1); - incrE = dx * 2; - d = incrE - dy; - incrNE = (dx - dy) * 2; - - if (x > x2) - goto flush_and_return; - - while (y < y2) { - if (d > 0) { - ++x; - d += incrNE; - if (x > x2) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - if (x < devRect.x1 || y < devRect.y1) - continue; - Q_ASSERT(x 90 and 225 -> 270 (unit circle degrees) - x1 = qMin(x1, devRect.x2 - 1); - incrE = dx * 2; - d = incrE + dy; - incrNE = (dx + dy) * 2; - - if (x < devRect.x1) - goto flush_and_return; - - while (y < y2) { - if (d < 0) { - --x; - d += incrNE; - if (x < devRect.x1) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - if (y < devRect.y1 || x > x1) - continue; - Q_ASSERT(x>=devRect.x1 && x=devRect.y1 && y 0) - span_func(current, ordered ? spans : spans + (NSPANS - current), data); -} - -static void offset_pattern(int offset, bool *inDash, int *dashIndex, int *currentOffset, const QVarLengthArray &pattern) -{ - while (offset--) { - if (--*currentOffset == 0) { - *inDash = !*inDash; - *dashIndex = ((*dashIndex + 1) % pattern.size()); - *currentOffset = int(pattern[*dashIndex]); - } - } -} - -static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2, - QPen *pen, - ProcessSpans span_func, QSpanData *data, - LineDrawMode style, const QIntRect &devRect, - int *patternOffset) -{ -#ifdef QT_DEBUG_DRAW - qDebug() << " - drawLine_midpoint_dashed_i" << x1 << y1 << x2 << y2 << *patternOffset; -#endif - - int x, y; - int dx, dy, d, incrE, incrNE; - - dx = x2 - x1; - dy = y2 - y1; - - Q_ASSERT(*patternOffset >= 0); - - const QVector penPattern = pen->dashPattern(); - QVarLengthArray pattern(penPattern.size()); - - int patternLength = 0; - for (int i = 0; i < penPattern.size(); ++i) - patternLength += qMax(1.0, (penPattern.at(i))); - - // pattern must be reversed if coordinates are out of order - int reverseLength = -1; - if (dy == 0 && x1 > x2) - reverseLength = x1 - x2; - else if (dx == 0 && y1 > y2) - reverseLength = y1 - y2; - else if (qAbs(dx) >= qAbs(dy) && x2 < x1) // x major axis - reverseLength = qAbs(dx); - else if (qAbs(dy) >= qAbs(dx) && y2 < y1) // y major axis - reverseLength = qAbs(dy); - - const bool reversed = (reverseLength > -1); - if (reversed) { // reverse pattern - for (int i = 0; i < penPattern.size(); ++i) - pattern[penPattern.size() - 1 - i] = qMax(1.0, penPattern.at(i)); - - *patternOffset = (patternLength - 1 - *patternOffset); - *patternOffset += patternLength - (reverseLength % patternLength); - *patternOffset = *patternOffset % patternLength; - } else { - for (int i = 0; i < penPattern.size(); ++i) - pattern[i] = qMax(1.0, penPattern.at(i)); - } - - int dashIndex = 0; - bool inDash = !reversed; - int currPattern = int(pattern[dashIndex]); - - // adjust pattern for offset - offset_pattern(*patternOffset, &inDash, &dashIndex, &currPattern, pattern); - - const int NSPANS = 256; - QT_FT_Span spans[NSPANS]; - int current = 0; - bool ordered = true; - - if (dy == 0) { - // specialcase horizontal lines - if (y1 >= devRect.y1 && y1 < devRect.y2) { - int start_unclipped = qMin(x1, x2); - int start = qMax(devRect.x1, start_unclipped); - int stop = qMax(x1, x2) + 1; - int stop_clipped = qMin(devRect.x2, stop); - int len = stop_clipped - start; - if (style == LineDrawNormal && stop == stop_clipped) - len--; - - // adjust pattern for starting offset - offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern); - - if (len > 0) { - int x = start; - while (x < stop_clipped) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - const int dash = qMin(currPattern, stop_clipped - x); - if (inDash) { - spans[current].x = ushort(x); - spans[current].len = ushort(dash); - spans[current].y = y1; - spans[current].coverage = 255; - ++current; - } - if (dash < currPattern) { - currPattern -= dash; - } else { - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - inDash = !inDash; - } - x += dash; - } - } - } - goto flush_and_return; - } else if (dx == 0) { - if (x1 >= devRect.x1 && x1 < devRect.x2) { - int start_unclipped = qMin(y1, y2); - int start = qMax(devRect.y1, start_unclipped); - int stop = qMax(y1, y2) + 1; - int stop_clipped = qMin(devRect.y2, stop); - if (style == LineDrawNormal && stop == stop_clipped) - --stop; - else - stop = stop_clipped; - - // adjust pattern for starting offset - offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern); - - // loop over dashes - int y = start; - while (y < stop) { - const int dash = qMin(currPattern, stop - y); - if (inDash) { - for (int i = 0; i < dash; ++i) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].x = x1; - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].y = ushort(y + i); - ++current; - } - } - if (dash < currPattern) { - currPattern -= dash; - } else { - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - inDash = !inDash; - } - y += dash; - } - } - goto flush_and_return; - } - - if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */ - - if (x2 < x1) { /* if coordinates are out of order */ - qt_swap_int(x1, x2); - dx = -dx; - - qt_swap_int(y1, y2); - dy = -dy; - } - - if (style == LineDrawNormal) - --x2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - x2 = qMin(x2, devRect.x2 - 1); - - // completely clipped, so abort - if (x2 <= x1) - goto flush_and_return; - - int x = x1; - int y = y1; - - if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2) { - Q_ASSERT(x < devRect.x2); - if (inDash) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - - if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees) - y2 = qMin(y2, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE - dx; - incrNE = (dy - dx) * 2; - - if (y > y2) - goto flush_and_return; - - while (x < x2) { - if (d > 0) { - ++y; - d += incrNE; - if (y > y2) - goto flush_and_return; - } else { - d += incrE; - } - ++x; - - const bool skip = x < devRect.x1 || y < devRect.y1; - Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } else { // 0-45 and 180->225 (unit circle degrees) - y1 = qMin(y1, devRect.y2 - 1); - - incrE = dy * 2; - d = incrE + dx; - incrNE = (dy + dx) * 2; - - if (y < devRect.y1) - goto flush_and_return; - - while (x < x2) { - if (d < 0) { - if (current > 0) { - span_func(current, spans, data); - current = 0; - } - - --y; - d += incrNE; - if (y < devRect.y1) - goto flush_and_return; - } else { - d += incrE; - } - ++x; - - const bool skip = x < devRect.x1 || y > y1; - Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } - } else { - - // if y is the major axis: - - if (y2 < y1) { /* if coordinates are out of order */ - qt_swap_int(y1, y2); - dy = -dy; - - qt_swap_int(x1, x2); - dx = -dx; - } - - if (style == LineDrawNormal) - --y2; - - // In the loops below we increment before call the span function so - // we need to stop one pixel before - y2 = qMin(y2, devRect.y2 - 1); - - // completely clipped, so abort - if (y2 <= y1) - goto flush_and_return; - - x = x1; - y = y1; - - if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) { - Q_ASSERT(x < devRect.x2); - if (inDash) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - - if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees) - x2 = qMin(x2, devRect.x2 - 1); - incrE = dx * 2; - d = incrE - dy; - incrNE = (dx - dy) * 2; - - if (x > x2) - goto flush_and_return; - - while (y < y2) { - if (d > 0) { - ++x; - d += incrNE; - if (x > x2) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - const bool skip = x < devRect.x1 || y < devRect.y1; - Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } else { // 45 -> 90 and 225 -> 270 (unit circle degrees) - x1 = qMin(x1, devRect.x2 - 1); - incrE = dx * 2; - d = incrE + dy; - incrNE = (dx + dy) * 2; - - if (x < devRect.x1) - goto flush_and_return; - - while (y < y2) { - if (d < 0) { - --x; - d += incrNE; - if (x < devRect.x1) - goto flush_and_return; - } else { - d += incrE; - } - ++y; - const bool skip = y < devRect.y1 || x > x1; - Q_ASSERT(skip || (x >= devRect.x1 && x < devRect.x2 && y < devRect.y2)); - if (inDash && !skip) { - if (current == NSPANS) { - span_func(NSPANS, spans, data); - current = 0; - } - spans[current].len = 1; - spans[current].coverage = 255; - spans[current].x = x; - spans[current].y = y; - ++current; - } - if (--currPattern <= 0) { - inDash = !inDash; - dashIndex = (dashIndex + 1) % pattern.size(); - currPattern = int(pattern[dashIndex]); - } - } - } - } -flush_and_return: - if (current > 0) - span_func(current, ordered ? spans : spans + (NSPANS - current), data); - - // adjust offset - if (reversed) { - *patternOffset = (patternLength - 1 - *patternOffset); - } else { - *patternOffset = 0; - for (int i = 0; i <= dashIndex; ++i) - *patternOffset += int(pattern[i]); - *patternOffset += patternLength - currPattern - 1; - *patternOffset = (*patternOffset % patternLength); - } -} - /*! \internal \a x and \a y is relative to the midpoint of \a rect. @@ -6349,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)