summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
authorDavid Boddie <david.boddie@nokia.com>2011-06-17 11:54:16 (GMT)
committerDavid Boddie <david.boddie@nokia.com>2011-06-17 11:54:16 (GMT)
commit2b39081bf101e53a70ff056d527dc3dfb8208bf0 (patch)
treea8e57489e18dbdd620b8880eda5c8e2d77049a07 /src/gui/painting
parent5e1112ec04dcef671700e326186ca56b790f7e08 (diff)
parentc390312f8fbea14ac4df0c5185ca814054f448d8 (diff)
downloadQt-2b39081bf101e53a70ff056d527dc3dfb8208bf0.zip
Qt-2b39081bf101e53a70ff056d527dc3dfb8208bf0.tar.gz
Qt-2b39081bf101e53a70ff056d527dc3dfb8208bf0.tar.bz2
Merge branch '4.8' of scm.dev.nokia.troll.no:qt/qt
Conflicts: doc/src/declarative/righttoleft.qdoc examples/draganddrop/fridgemagnets/main.cpp examples/script/context2d/main.cpp
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/painting.pri4
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp1010
-rw-r--r--src/gui/painting/qcosmeticstroker_p.h152
-rw-r--r--src/gui/painting/qgraphicssystemex_symbian.cpp36
-rw-r--r--src/gui/painting/qgraphicssystemex_symbian_p.h3
-rw-r--r--src/gui/painting/qoutlinemapper.cpp9
-rw-r--r--src/gui/painting/qoutlinemapper_p.h8
-rw-r--r--src/gui/painting/qpaintengine_mac_p.h2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp1484
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h6
-rw-r--r--src/gui/painting/qpaintengineex.cpp47
-rw-r--r--src/gui/painting/qpaintengineex_p.h3
-rw-r--r--src/gui/painting/qpainter.cpp63
-rw-r--r--src/gui/painting/qpainter_p.h2
-rw-r--r--src/gui/painting/qrasterizer.cpp4
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp16
-rw-r--r--src/gui/painting/qunifiedtoolbarsurface_mac.cpp6
-rw-r--r--src/gui/painting/qwindowsurface_qws.cpp72
18 files changed, 1510 insertions, 1417 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index f1496b1..d5ae364 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -6,6 +6,7 @@ HEADERS += \
painting/qcolor.h \
painting/qcolor_p.h \
painting/qcolormap.h \
+ painting/qcosmeticstroker_p.h \
painting/qdrawutil.h \
painting/qemulationpaintengine_p.h \
painting/qgraphicssystem_p.h \
@@ -15,7 +16,7 @@ HEADERS += \
painting/qoutlinemapper_p.h \
painting/qpaintdevice.h \
painting/qpaintengine.h \
- painting/qpaintengine_p.h \
+ painting/qpaintengine_p.h \
painting/qpaintengine_alpha_p.h \
painting/qpaintengine_preview_p.h \
painting/qpaintengineex_p.h \
@@ -54,6 +55,7 @@ SOURCES += \
painting/qbrush.cpp \
painting/qcolor.cpp \
painting/qcolor_p.cpp \
+ painting/qcosmeticstroker.cpp \
painting/qcssutil.cpp \
painting/qdrawutil.cpp \
painting/qemulationpaintengine.cpp \
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
new file mode 100644
index 0000000..cdc0978
--- /dev/null
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -0,0 +1,1010 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcosmeticstroker_p.h"
+#include "private/qpainterpath_p.h"
+#include <qdebug.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+#if 0
+inline QString capString(int caps)
+{
+ QString str;
+ if (caps & QCosmeticStroker::CapBegin) {
+ str += "CapBegin ";
+ }
+ if (caps & QCosmeticStroker::CapEnd) {
+ str += "CapEnd ";
+ }
+ return str;
+}
+#endif
+
+#define toF26Dot6(x) ((int)((x)*64.))
+
+static inline uint sourceOver(uint d, uint color)
+{
+ return color + BYTE_MUL(d, qAlpha(~color));
+}
+
+inline static int F16Dot16FixedDiv(int x, int y)
+{
+ if (qAbs(x) > 0x7fff)
+ return (((qlonglong)x) << 16) / y;
+ return (x << 16) / y;
+}
+
+typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage);
+
+namespace {
+
+struct Dasher {
+ QCosmeticStroker *stroker;
+ int *pattern;
+ int offset;
+ int dashIndex;
+ int dashOn;
+
+ Dasher(QCosmeticStroker *s, bool reverse, int start, int stop)
+ : stroker(s)
+ {
+ int delta = stop - start;
+ if (reverse) {
+ pattern = stroker->reversePattern;
+ offset = stroker->patternLength - stroker->patternOffset - delta - ((start & 63) - 32);
+ dashOn = 0;
+ } else {
+ pattern = stroker->pattern;
+ offset = stroker->patternOffset - ((start & 63) - 32);
+ dashOn = 1;
+ }
+ offset %= stroker->patternLength;
+ if (offset < 0)
+ offset += stroker->patternLength;
+
+ dashIndex = 0;
+ while (offset>= pattern[dashIndex])
+ ++dashIndex;
+
+// qDebug() << " dasher" << offset/64. << reverse << dashIndex;
+ stroker->patternOffset += delta;
+ stroker->patternOffset %= stroker->patternLength;
+ }
+
+ bool on() const {
+ return (dashIndex + dashOn) & 1;
+ }
+ void adjust() {
+ offset += 64;
+ if (offset >= pattern[dashIndex]) {
+ ++dashIndex;
+ dashIndex %= stroker->patternSize;
+ }
+ offset %= stroker->patternLength;
+// qDebug() << "dasher.adjust" << offset/64. << dashIndex;
+ }
+};
+
+struct NoDasher {
+ NoDasher(QCosmeticStroker *, bool, int, int) {}
+ bool on() const { return true; }
+ void adjust(int = 0) {}
+};
+
+};
+
+template<DrawPixel drawPixel, class Dasher>
+static void drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
+template<DrawPixel drawPixel, class Dasher>
+static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
+
+inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
+{
+ const QRect &cl = stroker->clip;
+ if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
+ return;
+
+ int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ;
+ int lasty = stroker->spans[stroker->current_span-1].y;
+
+ if (stroker->current_span == QCosmeticStroker::NSPANS || y < lasty || (y == lasty && x < lastx)) {
+ stroker->blend(stroker->current_span, stroker->spans, &stroker->state->penData);
+ stroker->current_span = 0;
+ }
+
+ stroker->spans[stroker->current_span].x = ushort(x);
+ stroker->spans[stroker->current_span].len = 1;
+ stroker->spans[stroker->current_span].y = y;
+ stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8;
+ ++stroker->current_span;
+}
+
+inline void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage)
+{
+ const QRect &cl = stroker->clip;
+ if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
+ return;
+
+ int offset = x + stroker->ppl*y;
+ uint c = BYTE_MUL(stroker->color, coverage);
+ stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
+}
+
+inline void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int)
+{
+ const QRect &cl = stroker->clip;
+ if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
+ return;
+
+ int offset = x + stroker->ppl*y;
+ stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
+}
+
+enum StrokeSelection {
+ Aliased = 0,
+ AntiAliased = 1,
+ Solid = 0,
+ Dashed = 2,
+ RegularDraw = 0,
+ FastDraw = 4
+};
+
+static StrokeLine strokeLine(int strokeSelection)
+{
+ StrokeLine stroke;
+
+ switch (strokeSelection) {
+ case Aliased|Solid|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, NoDasher>;
+ break;
+ case Aliased|Solid|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, NoDasher>;
+ break;
+ case Aliased|Dashed|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, Dasher>;
+ break;
+ case Aliased|Dashed|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, Dasher>;
+ break;
+ case AntiAliased|Solid|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, NoDasher>;
+ break;
+ case AntiAliased|Solid|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, NoDasher>;
+ break;
+ case AntiAliased|Dashed|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, Dasher>;
+ break;
+ case AntiAliased|Dashed|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, Dasher>;
+ break;
+ default:
+ Q_ASSERT(false);
+ stroke = 0;
+ }
+ return stroke;
+}
+
+void QCosmeticStroker::setup()
+{
+ blend = state->penData.blend;
+ if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
+ clip &= state->clip->clipRect;
+ blend = state->penData.unclipped_blend;
+ }
+
+ int strokeSelection = 0;
+ if (blend == state->penData.unclipped_blend
+ && state->penData.type == QSpanData::Solid
+ && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
+ || state->penData.rasterBuffer->format == QImage::Format_RGB32)
+ && state->compositionMode() == QPainter::CompositionMode_SourceOver)
+ strokeSelection |= FastDraw;
+
+ if (state->renderHints & QPainter::Antialiasing)
+ strokeSelection |= AntiAliased;
+
+ const QVector<qreal> &penPattern = state->lastPen.dashPattern();
+ if (penPattern.isEmpty()) {
+ Q_ASSERT(!pattern && !reversePattern);
+ pattern = 0;
+ reversePattern = 0;
+ patternLength = 0;
+ patternSize = 0;
+ } else {
+ pattern = (int *)malloc(penPattern.size()*sizeof(int));
+ reversePattern = (int *)malloc(penPattern.size()*sizeof(int));
+ patternSize = penPattern.size();
+
+ patternLength = 0;
+ for (int i = 0; i < patternSize; ++i) {
+ patternLength += (int) qMax(1. , penPattern.at(i)*64.);
+ pattern[i] = patternLength;
+ }
+ patternLength = 0;
+ for (int i = 0; i < patternSize; ++i) {
+ patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.);
+ reversePattern[i] = patternLength;
+ }
+ strokeSelection |= Dashed;
+// qDebug() << "setup: size=" << patternSize << "length=" << patternLength/64.;
+ }
+
+ stroke = strokeLine(strokeSelection);
+
+ qreal width = state->lastPen.widthF();
+ if (width == 0)
+ opacity = 256;
+ else if (state->lastPen.isCosmetic())
+ opacity = (int) 256*width;
+ else
+ opacity = (int) 256*width*state->txscale;
+ opacity = qBound(0, opacity, 256);
+
+ drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
+
+ if (strokeSelection & FastDraw) {
+ color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0);
+ QRasterBuffer *buffer = state->penData.rasterBuffer;
+ pixels = (uint *)buffer->buffer();
+ ppl = buffer->bytesPerLine()>>2;
+ }
+
+ // setup FP clip bounds
+ xmin = clip.left() - 1;
+ xmax = clip.right() + 2;
+ ymin = clip.top() - 1;
+ ymax = clip.bottom() + 2;
+
+ lastPixel.x = -1;
+}
+
+// returns true if the whole line gets clipped away
+bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
+{
+ // basic/rough clipping is done in floating point coordinates to avoid
+ // integer overflow problems.
+ if (x1 < xmin) {
+ if (x2 <= xmin)
+ goto clipped;
+ y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
+ x1 = xmin;
+ } else if (x1 > xmax) {
+ if (x2 >= xmax)
+ goto clipped;
+ y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
+ x1 = xmax;
+ }
+ if (x2 < xmin) {
+ lastPixel.x = -1;
+ y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
+ x2 = xmin;
+ } else if (x2 > xmax) {
+ lastPixel.x = -1;
+ y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
+ x2 = xmax;
+ }
+
+ if (y1 < ymin) {
+ if (y2 <= ymin)
+ goto clipped;
+ x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
+ y1 = ymin;
+ } else if (y1 > ymax) {
+ if (y2 >= ymax)
+ goto clipped;
+ x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
+ y1 = ymax;
+ }
+ if (y2 < ymin) {
+ lastPixel.x = -1;
+ x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
+ y2 = ymin;
+ } else if (y2 > ymax) {
+ lastPixel.x = -1;
+ x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
+ y2 = ymax;
+ }
+
+ return false;
+
+ clipped:
+ lastPixel.x = -1;
+ return true;
+}
+
+
+void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
+{
+ QPointF start = p1 * state->matrix;
+ QPointF end = p2 * state->matrix;
+
+ patternOffset = state->lastPen.dashOffset()*64;
+ lastPixel.x = -1;
+
+ stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0);
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::drawPoints(const QPoint *points, int num)
+{
+ const QPoint *end = points + num;
+ while (points < end) {
+ QPointF p = QPointF(*points) * state->matrix;
+ drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ ++points;
+ }
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::drawPoints(const QPointF *points, int num)
+{
+ const QPointF *end = points + num;
+ while (points < end) {
+ QPointF p = (*points) * state->matrix;
+ drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ ++points;
+ }
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
+{
+ // this is basically the same code as used in the aliased stroke method,
+ // but it only determines the direction and last point of a line
+ //
+ // This is being used to have proper dropout control for closed contours
+ // by calculating the direction and last pixel of the last segment in the contour.
+ // the info is then used to perform dropout control when drawing the first line segment
+ // of the contour
+ lastPixel.x = -1;
+ lastPixel.y = -1;
+
+ if (clipLine(rx1, ry1, rx2, ry2))
+ return;
+
+ const int half = 32;
+ int x1 = toF26Dot6(rx1) + half;
+ int y1 = toF26Dot6(ry1) + half;
+ int x2 = toF26Dot6(rx2) + half;
+ int y2 = toF26Dot6(ry2) + half;
+
+ int dx = qAbs(x2 - x1);
+ int dy = qAbs(y2 - y1);
+
+ if (dx < dy) {
+ // vertical
+ bool swapped = false;
+ if (y1 > y2) {
+ swapped = true;
+ qSwap(y1, y2);
+ qSwap(x1, x2);
+ --x1; --x2; --y1; --y2;
+ }
+ int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
+ int x = x1 << 10;
+
+ int y = (y1+32) >> 6;
+ int ys = (y2+32) >> 6;
+
+ if (y != ys) {
+ x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
+
+ if (swapped) {
+ lastPixel.x = x >> 16;
+ lastPixel.y = y;
+ lastDir = QCosmeticStroker::BottomToTop;
+ } else {
+ lastPixel.x = (x + (ys - y - 1)*xinc) >> 16;
+ lastPixel.y = ys - 1;
+ lastDir = QCosmeticStroker::TopToBottom;
+ }
+ lastAxisAligned = qAbs(xinc) < (1 << 14);
+ }
+ } else {
+ // horizontal
+ if (!dx)
+ return;
+
+ bool swapped = false;
+ if (x1 > x2) {
+ swapped = true;
+ qSwap(x1, x2);
+ qSwap(y1, y2);
+ --x1; --x2; --y1; --y2;
+ }
+ int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
+ int y = y1 << 10;
+
+ int x = (x1+32) >> 6;
+ int xs = (x2+32) >> 6;
+
+ if (x != xs) {
+ y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
+
+ if (swapped) {
+ lastPixel.x = x;
+ lastPixel.y = y >> 16;
+ lastDir = QCosmeticStroker::RightToLeft;
+ } else {
+ lastPixel.x = xs - 1;
+ lastPixel.y = (y + (xs - x - 1)*yinc) >> 16;
+ lastDir = QCosmeticStroker::LeftToRight;
+ }
+ lastAxisAligned = qAbs(yinc) < (1 << 14);
+ }
+ }
+// qDebug() << " moveTo: setting last pixel to x/y dir" << lastPixel.x << lastPixel.y << lastDir;
+}
+
+static inline const QPainterPath::ElementType *subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end,
+ const qreal *points, bool *closed)
+{
+ const QPainterPath::ElementType *start = t;
+ ++t;
+
+ // find out if the subpath is closed
+ while (t < end) {
+ if (*t == QPainterPath::MoveToElement)
+ break;
+ ++t;
+ }
+
+ int offset = t - start - 1;
+// qDebug() << "subpath" << offset << points[0] << points[1] << points[2*offset] << points[2*offset+1];
+ *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
+
+ return t;
+}
+
+void QCosmeticStroker::drawPath(const QVectorPath &path)
+{
+// qDebug() << ">>>> drawpath" << path.convertToPainterPath()
+// << "antialiasing:" << (bool)(state->renderHints & QPainter::Antialiasing) << " implicit close:" << path.hasImplicitClose();
+ if (path.isEmpty())
+ return;
+
+ const qreal *points = path.points();
+ const QPainterPath::ElementType *type = path.elements();
+
+ if (type) {
+ const QPainterPath::ElementType *end = type + path.elementCount();
+
+ while (type < end) {
+ Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
+
+ QPointF p = QPointF(points[0], points[1]) * state->matrix;
+ QPointF movedTo = p;
+ patternOffset = state->lastPen.dashOffset()*64;
+ lastPixel.x = -1;
+
+ bool closed;
+ const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
+ if (closed) {
+ const qreal *p = points + 2*(e-type);
+ QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix;
+ QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix;
+ calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y());
+ }
+ int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
+// qDebug() << "closed =" << closed << capString(caps);
+
+ points += 2;
+ ++type;
+
+ while (type < e) {
+ QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
+ switch (*type) {
+ case QPainterPath::MoveToElement:
+ Q_ASSERT(!"Logic error");
+ break;
+
+ case QPainterPath::LineToElement:
+ if (!closed && drawCaps && type == e - 1)
+ caps |= CapEnd;
+ stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
+ p = p2;
+ points += 2;
+ ++type;
+ break;
+
+ case QPainterPath::CurveToElement: {
+ if (!closed && drawCaps && type == e - 3)
+ caps |= CapEnd;
+ QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
+ QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
+ renderCubic(p, p2, p3, p4, caps);
+ p = p4;
+ type += 3;
+ points += 6;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
+ break;
+ }
+ caps = NoCaps;
+ }
+ }
+ } else { // !type, simple polygon
+ QPointF p = QPointF(points[0], points[1]) * state->matrix;
+ QPointF movedTo = p;
+ patternOffset = state->lastPen.dashOffset()*64;
+ lastPixel.x = -1;
+
+ const qreal *end = points + 2*path.elementCount();
+ // handle closed path case
+ bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
+ int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
+ if (closed) {
+ QPointF p2 = QPointF(end[-2], end[-1]) * state->matrix;
+ calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
+ }
+
+ points += 2;
+ while (points < end) {
+ QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
+
+ if (!closed && drawCaps && points == end - 2)
+ caps |= CapEnd;
+
+ stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
+
+ p = p2;
+ points += 2;
+ caps = NoCaps;
+ }
+ if (path.hasImplicitClose())
+ stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
+ }
+
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps)
+{
+// qDebug() << ">>>> renderCubic" << p1 << p2 << p3 << p4 << capString(caps);
+ const int maxSubDivisions = 6;
+ PointF points[3*maxSubDivisions + 4];
+
+ points[3].x = p1.x();
+ points[3].y = p1.y();
+ points[2].x = p2.x();
+ points[2].y = p2.y();
+ points[1].x = p3.x();
+ points[1].y = p3.y();
+ points[0].x = p4.x();
+ points[0].y = p4.y();
+
+ PointF *p = points;
+ int level = maxSubDivisions;
+
+ renderCubicSubdivision(p, level, caps);
+}
+
+static void splitCubic(QCosmeticStroker::PointF *points)
+{
+ const qreal half = .5;
+ qreal a, b, c, d;
+
+ points[6].x = points[3].x;
+ c = points[1].x;
+ d = points[2].x;
+ points[1].x = a = ( points[0].x + c ) * half;
+ points[5].x = b = ( points[3].x + d ) * half;
+ c = ( c + d ) * half;
+ points[2].x = a = ( a + c ) * half;
+ points[4].x = b = ( b + c ) * half;
+ points[3].x = ( a + b ) * half;
+
+ points[6].y = points[3].y;
+ c = points[1].y;
+ d = points[2].y;
+ points[1].y = a = ( points[0].y + c ) * half;
+ points[5].y = b = ( points[3].y + d ) * half;
+ c = ( c + d ) * half;
+ points[2].y = a = ( a + c ) * half;
+ points[4].y = b = ( b + c ) * half;
+ points[3].y = ( a + b ) * half;
+}
+
+void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, int level, int caps)
+{
+ if (level) {
+ qreal dx = points[3].x - points[0].x;
+ qreal dy = points[3].y - points[0].y;
+ qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy));
+
+ if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
+ qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
+ splitCubic(points);
+
+ --level;
+ renderCubicSubdivision(points + 3, level, caps & CapBegin);
+ renderCubicSubdivision(points, level, caps & CapEnd);
+ return;
+ }
+ }
+
+ stroke(this, points[3].x, points[3].y, points[0].x, points[0].y, caps);
+}
+
+static inline int swapCaps(int caps)
+{
+ return ((caps & QCosmeticStroker::CapBegin) << 1) |
+ ((caps & QCosmeticStroker::CapEnd) >> 1);
+}
+
+// adjust line by half a pixel
+static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc)
+{
+ if (caps & QCosmeticStroker::CapBegin) {
+ x1 -= 32;
+ y -= yinc >> 1;
+ }
+ if (caps & QCosmeticStroker::CapEnd) {
+ x2 += 32;
+ }
+}
+
+/*
+ The hard part about this is dropout control and avoiding douple drawing of points when
+ the drawing shifts from horizontal to vertical or back.
+ */
+template<DrawPixel drawPixel, class Dasher>
+static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
+{
+ if (stroker->clipLine(rx1, ry1, rx2, ry2))
+ return;
+
+ static const int half = 32;
+ int x1 = toF26Dot6(rx1) + half;
+ int y1 = toF26Dot6(ry1) + half;
+ int x2 = toF26Dot6(rx2) + half;
+ int y2 = toF26Dot6(ry2) + half;
+
+ int dx = qAbs(x2 - x1);
+ int dy = qAbs(y2 - y1);
+
+ QCosmeticStroker::Point last = stroker->lastPixel;
+
+// qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64. << capString(caps);
+
+ if (dx < dy) {
+ // vertical
+
+ bool swapped = false;
+ if (y1 > y2) {
+ swapped = true;
+ qSwap(y1, y2);
+ qSwap(x1, x2);
+ caps = swapCaps(caps);
+ --x1; --x2; --y1; --y2;
+ }
+ int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
+ int x = x1 << 10;
+
+ capAdjust(caps, y1, y2, x, xinc);
+
+ int y = (y1+32) >> 6;
+ int ys = (y2+32) >> 6;
+
+ if (y != ys) {
+ x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
+
+ // calculate first and last pixel and perform dropout control
+ QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom;
+ QCosmeticStroker::Point first;
+ first.x = x >> 16;
+ first.y = y;
+ last.x = (x + (ys - y - 1)*xinc) >> 16;
+ last.y = ys - 1;
+ if (swapped) {
+ qSwap(first, last);
+ dir = QCosmeticStroker::BottomToTop;
+ }
+ bool axisAligned = qAbs(xinc) < (1 << 14);
+ if (stroker->lastPixel.x >= 0) {
+ if (first.x == stroker->lastPixel.x &&
+ first.y == stroker->lastPixel.y) {
+ // remove duplicated pixel
+ if (swapped) {
+ --ys;
+ } else {
+ ++y;
+ x += xinc;
+ }
+ } else if (stroker->lastDir != dir &&
+ (((axisAligned && stroker->lastAxisAligned) &&
+ stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
+ (qAbs(stroker->lastPixel.x - first.x) > 1 &&
+ qAbs(stroker->lastPixel.y - first.y) > 1))) {
+ // have a missing pixel, insert it
+ if (swapped) {
+ ++ys;
+ } else {
+ --y;
+ x -= xinc;
+ }
+ }
+ }
+ stroker->lastDir = dir;
+ stroker->lastAxisAligned = axisAligned;
+
+ Dasher dasher(stroker, swapped, y << 6, ys << 6);
+
+ do {
+ if (dasher.on())
+ drawPixel(stroker, x >> 16, y, 255);
+ dasher.adjust();
+ x += xinc;
+ } while (++y < ys);
+ }
+ } else {
+ // horizontal
+ if (!dx)
+ return;
+
+ bool swapped = false;
+ if (x1 > x2) {
+ swapped = true;
+ qSwap(x1, x2);
+ qSwap(y1, y2);
+ caps = swapCaps(caps);
+ --x1; --x2; --y1; --y2;
+ }
+ int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
+ int y = y1 << 10;
+
+ capAdjust(caps, x1, x2, y, yinc);
+
+ int x = (x1+32) >> 6;
+ int xs = (x2+32) >> 6;
+
+
+ if (x != xs) {
+ y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
+
+ // calculate first and last pixel to perform dropout control
+ QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
+ QCosmeticStroker::Point first;
+ first.x = x;
+ first.y = y >> 16;
+ last.x = xs - 1;
+ last.y = (y + (xs - x - 1)*yinc) >> 16;
+ if (swapped) {
+ qSwap(first, last);
+ dir = QCosmeticStroker::RightToLeft;
+ }
+ bool axisAligned = qAbs(yinc) < (1 << 14);
+ if (stroker->lastPixel.x >= 0) {
+ if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
+ // remove duplicated pixel
+ if (swapped) {
+ --xs;
+ } else {
+ ++x;
+ y += yinc;
+ }
+ } else if (stroker->lastDir != dir &&
+ (((axisAligned && stroker->lastAxisAligned) &&
+ stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
+ (qAbs(stroker->lastPixel.x - first.x) > 1 &&
+ qAbs(stroker->lastPixel.y - first.y) > 1))) {
+ // have a missing pixel, insert it
+ if (swapped) {
+ ++xs;
+ } else {
+ --x;
+ y -= yinc;
+ }
+ }
+ }
+ stroker->lastDir = dir;
+ stroker->lastAxisAligned = axisAligned;
+
+ Dasher dasher(stroker, swapped, x << 6, xs << 6);
+
+ do {
+ if (dasher.on())
+ drawPixel(stroker, x, y >> 16, 255);
+ dasher.adjust();
+ y += yinc;
+ } while (++x < xs);
+ }
+ }
+ stroker->lastPixel = last;
+}
+
+
+template<DrawPixel drawPixel, class Dasher>
+static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
+{
+ if (stroker->clipLine(rx1, ry1, rx2, ry2))
+ return;
+
+ int x1 = toF26Dot6(rx1);
+ int y1 = toF26Dot6(ry1);
+ int x2 = toF26Dot6(rx2);
+ int y2 = toF26Dot6(ry2);
+
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ if (qAbs(dx) < qAbs(dy)) {
+ // vertical
+
+ int xinc = F16Dot16FixedDiv(dx, dy);
+
+ bool swapped = false;
+ if (y1 > y2) {
+ qSwap(y1, y2);
+ qSwap(x1, x2);
+ swapped = true;
+ caps = swapCaps(caps);
+ }
+
+ int x = (x1 - 32) << 10;
+ x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
+
+ capAdjust(caps, y1, y2, x, xinc);
+
+ Dasher dasher(stroker, swapped, y1, y2);
+
+ int y = y1 >> 6;
+ int ys = y2 >> 6;
+
+ int alphaStart, alphaEnd;
+ if (y == ys) {
+ alphaStart = y2 - y1;
+ Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
+ alphaEnd = 0;
+ } else {
+ alphaStart = 64 - (y1 & 63);
+ alphaEnd = (y2 & 63);
+ }
+// qDebug() << "vertical" << x1/64. << y1/64. << x2/64. << y2/64.;
+// qDebug() << " x=" << x << "dx=" << dx << "xi=" << (x>>16) << "xsi=" << ((x+(ys-y)*dx)>>16) << "y=" << y << "ys=" << ys;
+
+ // draw first pixel
+ if (dasher.on()) {
+ uint alpha = (quint8)(x >> 8);
+ drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
+ drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
+ }
+ dasher.adjust();
+ x += xinc;
+ ++y;
+ if (y < ys) {
+ do {
+ if (dasher.on()) {
+ uint alpha = (quint8)(x >> 8);
+ drawPixel(stroker, x>>16, y, (255-alpha));
+ drawPixel(stroker, (x>>16) + 1, y, alpha);
+ }
+ dasher.adjust();
+ x += xinc;
+ } while (++y < ys);
+ }
+ // draw last pixel
+ if (alphaEnd && dasher.on()) {
+ uint alpha = (quint8)(x >> 8);
+ drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
+ drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
+ }
+ } else {
+ // horizontal
+ if (!dx)
+ return;
+
+ int yinc = F16Dot16FixedDiv(dy, dx);
+
+ bool swapped = false;
+ if (x1 > x2) {
+ qSwap(x1, x2);
+ qSwap(y1, y2);
+ swapped = true;
+ caps = swapCaps(caps);
+ }
+
+ int y = (y1 - 32) << 10;
+ y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
+
+ capAdjust(caps, x1, x2, y, yinc);
+
+ Dasher dasher(stroker, swapped, x1, x2);
+
+ int x = x1 >> 6;
+ int xs = x2 >> 6;
+
+// qDebug() << "horizontal" << x1/64. << y1/64. << x2/64. << y2/64.;
+// qDebug() << " y=" << y << "dy=" << dy << "x=" << x << "xs=" << xs << "yi=" << (y>>16) << "ysi=" << ((y+(xs-x)*dy)>>16);
+ int alphaStart, alphaEnd;
+ if (x == xs) {
+ alphaStart = x2 - x1;
+ Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
+ alphaEnd = 0;
+ } else {
+ alphaStart = 64 - (x1 & 63);
+ alphaEnd = (x2 & 63);
+ }
+
+ // draw first pixel
+ if (dasher.on()) {
+ uint alpha = (quint8)(y >> 8);
+ drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
+ drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
+ }
+ dasher.adjust();
+ y += yinc;
+ ++x;
+ // draw line
+ if (x < xs) {
+ do {
+ if (dasher.on()) {
+ uint alpha = (quint8)(y >> 8);
+ drawPixel(stroker, x, y>>16, (255-alpha));
+ drawPixel(stroker, x, (y>>16) + 1, alpha);
+ }
+ dasher.adjust();
+ y += yinc;
+ } while (++x < xs);
+ }
+ // draw last pixel
+ if (alphaEnd && dasher.on()) {
+ uint alpha = (quint8)(y >> 8);
+ drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
+ drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6);
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h
new file mode 100644
index 0000000..0aa71fc
--- /dev/null
+++ b/src/gui/painting/qcosmeticstroker_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOSMETICSTROKER_P_H
+#define QCOSMETICSTROKER_P_H
+
+#include <private/qdrawhelper_p.h>
+#include <private/qvectorpath_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <qpen.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QCosmeticStroker;
+
+
+typedef void (*StrokeLine)(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
+
+class QCosmeticStroker
+{
+public:
+ struct Point {
+ int x;
+ int y;
+ };
+ struct PointF {
+ qreal x;
+ qreal y;
+ };
+
+ enum Caps {
+ NoCaps = 0,
+ CapBegin = 0x1,
+ CapEnd = 0x2,
+ };
+
+ // used to avoid drop outs or duplicated points
+ enum Direction {
+ TopToBottom,
+ BottomToTop,
+ LeftToRight,
+ RightToLeft
+ };
+
+ QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr)
+ : state(s),
+ clip(dr),
+ pattern(0),
+ reversePattern(0),
+ patternSize(0),
+ patternLength(0),
+ patternOffset(0),
+ current_span(0),
+ lastDir(LeftToRight),
+ lastAxisAligned(false)
+ { setup(); }
+ ~QCosmeticStroker() { free(pattern); free(reversePattern); }
+ void drawLine(const QPointF &p1, const QPointF &p2);
+ void drawPath(const QVectorPath &path);
+ void drawPoints(const QPoint *points, int num);
+ void drawPoints(const QPointF *points, int num);
+
+
+ QRasterPaintEngineState *state;
+ QRect clip;
+ // clip bounds in real
+ qreal xmin, xmax;
+ qreal ymin, ymax;
+
+ StrokeLine stroke;
+ bool drawCaps;
+
+ int *pattern;
+ int *reversePattern;
+ int patternSize;
+ int patternLength;
+ int patternOffset;
+
+ enum { NSPANS = 255 };
+ QT_FT_Span spans[NSPANS];
+ int current_span;
+ ProcessSpans blend;
+
+ int opacity;
+
+ uint color;
+ uint *pixels;
+ int ppl;
+
+ Direction lastDir;
+ Point lastPixel;
+ bool lastAxisAligned;
+
+private:
+ void setup();
+
+ void renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps);
+ void renderCubicSubdivision(PointF *points, int level, int caps);
+ // used for closed subpaths
+ void calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2);
+
+public:
+ bool clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCOSMETICLINE_H
diff --git a/src/gui/painting/qgraphicssystemex_symbian.cpp b/src/gui/painting/qgraphicssystemex_symbian.cpp
index b53353b..4469704 100644
--- a/src/gui/painting/qgraphicssystemex_symbian.cpp
+++ b/src/gui/painting/qgraphicssystemex_symbian.cpp
@@ -44,10 +44,39 @@
#include "private/qbackingstore_p.h"
#include "private/qapplication_p.h"
-#include <QDebug>
+#include <e32property.h>
QT_BEGIN_NAMESPACE
+static bool bcm2727Initialized = false;
+static bool bcm2727 = false;
+
+bool QSymbianGraphicsSystemEx::hasBCM2727()
+{
+ if (bcm2727Initialized)
+ return bcm2727;
+
+ const TUid KIvePropertyCat = {0x2726beef};
+ enum TIvePropertyChipType {
+ EVCBCM2727B1 = 0x00000000,
+ EVCBCM2763A0 = 0x04000100,
+ EVCBCM2763B0 = 0x04000102,
+ EVCBCM2763C0 = 0x04000103,
+ EVCBCM2763C1 = 0x04000104,
+ EVCBCMUnknown = 0x7fffffff
+ };
+
+ TInt chipType = EVCBCMUnknown;
+ if (RProperty::Get(KIvePropertyCat, 0, chipType) == KErrNone) {
+ if (chipType == EVCBCM2727B1)
+ bcm2727 = true;
+ }
+
+ bcm2727Initialized = true;
+
+ return bcm2727;
+}
+
void QSymbianGraphicsSystemEx::releaseCachedGpuResources()
{
// Do nothing here
@@ -64,11 +93,6 @@ void QSymbianGraphicsSystemEx::releaseAllGpuResources()
}
}
-bool QSymbianGraphicsSystemEx::hasBCM2727()
-{
- return !QApplicationPrivate::instance()->useTranslucentEGLSurfaces;
-}
-
void QSymbianGraphicsSystemEx::forceToRaster(QWidget *window)
{
if (window && window->isWindow()) {
diff --git a/src/gui/painting/qgraphicssystemex_symbian_p.h b/src/gui/painting/qgraphicssystemex_symbian_p.h
index c1d1bdf..1f2a7c6 100644
--- a/src/gui/painting/qgraphicssystemex_symbian_p.h
+++ b/src/gui/painting/qgraphicssystemex_symbian_p.h
@@ -62,9 +62,10 @@ class QWidget;
class Q_GUI_EXPORT QSymbianGraphicsSystemEx : public QGraphicsSystemEx
{
public:
+ static bool hasBCM2727();
+
virtual void releaseCachedGpuResources();
virtual void releaseAllGpuResources();
- virtual bool hasBCM2727();
virtual void forceToRaster(QWidget *window);
};
diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp
index 7c17c1b..8b607b2 100644
--- a/src/gui/painting/qoutlinemapper.cpp
+++ b/src/gui/painting/qoutlinemapper.cpp
@@ -47,6 +47,8 @@
QT_BEGIN_NAMESPACE
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
#define qreal_to_fixed_26_6(f) (int(f * 64))
@@ -214,6 +216,13 @@ void QOutlineMapper::endOutline()
elements = m_elements_dev.data();
}
+ if (m_round_coords) {
+ // round coordinates to match outlines drawn with drawLine_midpoint_i
+ for (int i = 0; i < m_elements.size(); ++i)
+ elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
+ qFloor(elements[i].y() + aliasedCoordinateDelta));
+ }
+
controlPointRect = boundingRect(elements, element_count);
#ifdef QT_DEBUG_CONVERT
diff --git a/src/gui/painting/qoutlinemapper_p.h b/src/gui/painting/qoutlinemapper_p.h
index 1432d6f..388858c 100644
--- a/src/gui/painting/qoutlinemapper_p.h
+++ b/src/gui/painting/qoutlinemapper_p.h
@@ -95,7 +95,8 @@ public:
m_tags(0),
m_contours(0),
m_polygon_dev(0),
- m_in_clip_elements(false)
+ m_in_clip_elements(false),
+ m_round_coords(false)
{
}
@@ -201,6 +202,8 @@ public:
QT_FT_Outline *convertPath(const QPainterPath &path);
QT_FT_Outline *convertPath(const QVectorPath &path);
+ void setCoordinateRounding(bool coordinateRounding) { m_round_coords = coordinateRounding; }
+
inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? 0 : m_element_types.data(); }
public:
@@ -234,6 +237,9 @@ public:
bool m_valid;
bool m_in_clip_elements;
+
+private:
+ bool m_round_coords;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengine_mac_p.h b/src/gui/painting/qpaintengine_mac_p.h
index c87501e..2434011 100644
--- a/src/gui/painting/qpaintengine_mac_p.h
+++ b/src/gui/painting/qpaintengine_mac_p.h
@@ -121,6 +121,8 @@ public:
void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{ QPaintEngine::drawPolygon(points, pointCount, mode); }
+ bool supportsTransformations(qreal, const QTransform &) const { return true; };
+
protected:
friend class QMacPrintEngine;
friend class QMacPrintEnginePrivate;
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5ce94f8..30553b5 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -69,6 +69,7 @@
// #include <private/qrasterizer_p.h>
#include <private/qimage_p.h>
#include <private/qstatictext_p.h>
+#include <private/qcosmeticstroker_p.h>
#include "qmemrotate_p.h"
#include "qpaintengine_raster_p.h"
@@ -126,6 +127,9 @@ void dumpClip(int width, int height, const QClipData *clip);
// 4 pixels.
#define int_dim(pos, dim) (int(pos+dim) - int(pos))
+// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
#ifdef Q_WS_WIN
extern bool qt_cleartype_enabled;
#endif
@@ -156,16 +160,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);
@@ -789,14 +783,12 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
s->stroker = 0;
}
+ ensureState(); // needed because of tx_noshear...
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
+ && ((pen.isCosmetic() && penWidth <= 1)
+ || (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;
@@ -1513,6 +1505,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
#endif
Q_D(QRasterPaintEngine);
+ ensureState();
QRasterPaintEngineState *s = state();
// Fill
@@ -1541,32 +1534,14 @@ 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);
+ 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 +1556,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);
+ ensureState();
QRasterPaintEngineState *s = state();
- ensureState();
if (s->flags.tx_noshear) {
ensureBrush();
@@ -1605,59 +1580,17 @@ 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);
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,36 +1607,16 @@ 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.drawPath(path);
} else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
qreal width = s->lastPen.isCosmetic()
? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
@@ -1760,10 +1673,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
static inline QRect toNormalizedFillRect(const QRectF &rect)
{
- int x1 = qRound(rect.x());
- int y1 = qRound(rect.y());
- int x2 = qRound(rect.right());
- int y2 = qRound(rect.bottom());
+ int x1 = qRound(rect.x() + aliasedCoordinateDelta);
+ int y1 = qRound(rect.y() + aliasedCoordinateDelta);
+ int x2 = qRound(rect.right() + aliasedCoordinateDelta);
+ int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
if (x2 < x1)
qSwap(x1, x2);
@@ -1818,26 +1731,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();
@@ -2032,6 +1925,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 +1942,23 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
}
ensurePen();
- ensureBrush();
if (mode != PolylineMode) {
// Do the fill...
+ ensureBrush();
if (s->brushData.blend) {
+ d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
fillPolygon(points, pointCount, mode);
+ d->outlineMapper->setCoordinateRounding(false);
}
}
// 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.drawPath(vp);
+ } else {
QPaintEngineEx::stroke(vp, s->lastPen);
}
}
@@ -2090,13 +1987,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) {
@@ -2104,6 +1995,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
if (s->brushData.blend) {
// Compose polygon fill..,
ensureOutlineMapper();
+ d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
d->outlineMapper->moveTo(*points);
const QPoint *p = points;
@@ -2117,235 +2009,30 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
&s->brushData);
d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
+ d->outlineMapper->setCoordinateRounding(false);
}
}
// 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<qreal> fpoints(count);
-#ifdef Q_WS_MAC
- for (int i=0; i<count; i+=2) {
- fpoints[i] = ((int *) points)[i+1];
- fpoints[i+1] = ((int *) points)[i];
- }
-#else
- for (int i=0; i<count; ++i)
- fpoints[i] = ((int *) points)[i];
-#endif
- QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
- QPaintEngineEx::stroke(vp, s->lastPen);
+ int count = pointCount * 2;
+ QVarLengthArray<qreal> fpoints(count);
+ #ifdef Q_WS_MAC
+ for (int i=0; i<count; i+=2) {
+ fpoints[i] = ((int *) points)[i+1];
+ fpoints[i+1] = ((int *) points)[i];
}
- }
-}
-
-/*!
- \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; i<pointCount; ++i) {
-
- QPointF lp1 = points[i-1] * s->matrix;
- QPointF lp2 = points[i] * s->matrix;
-
- const QRectF brect(lp1, lp2);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- 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
+ for (int i=0; i<count; ++i)
+ fpoints[i] = ((int *) points)[i];
+ #endif
+ QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
+
+ if (s->flags.fast_pen) {
+ QCosmeticStroker stroker(s, d->deviceRect);
+ 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,
- 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);
- } 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; i<pointCount; ++i) {
- const QPoint lp1 = points[i-1] * s->matrix;
- 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; i<pointCount; ++i) {
- int x1 = points[i-1].x() * m11 + dx;
- int y1 = points[i-1].y() * m22 + dy;
- qreal w = m13*points[i-1].x() + m23*points[i-1].y() + 1.;
- w = 1/w;
- x1 = int(x1*w);
- y1 = int(y1*w);
- int x2 = points[i].x() * m11 + dx;
- int y2 = points[i].y() * m22 + dy;
- w = m13*points[i].x() + m23*points[i].y() + 1.;
- w = 1/w;
- x2 = int(x2*w);
- y2 = int(y2*w);
-
- 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,
- 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);
}
}
}
@@ -2579,7 +2266,10 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
int sr_b = qCeil(sr.bottom()) - 1;
if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
+ // as fillRect will apply the aliased coordinate delta we need to
+ // subtract it here as we don't use it for image drawing
QTransform old = s->matrix;
+ s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
// Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
QRgb color = img.pixel(sr_l, sr_t);
@@ -2723,9 +2413,11 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
+ const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
+
const QRectF &rect = r.normalized();
- const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
- 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 +2426,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
return;
}
#endif
+ const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
QPainterPath path;
path.addRect(r);
QTransform m = s->matrix;
s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
m.m21(), m.m22(), m.m23(),
- m.m31(), m.m32(), m.m33());
+ m.m31() - offs, m.m32() - offs, m.m33());
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
@@ -3167,7 +2860,15 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
} else
#endif
{
- QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
+ QFontEngineGlyphCache::Type glyphType;
+ if (fontEngine->glyphFormat >= 0) {
+ glyphType = QFontEngineGlyphCache::Type(fontEngine->glyphFormat);
+ } else if (s->matrix.type() > QTransform::TxTranslate
+ && d->glyphCacheType == QFontEngineGlyphCache::Raster_RGBMask) {
+ glyphType = QFontEngineGlyphCache::Raster_A8;
+ } else {
+ glyphType = d->glyphCacheType;
+ }
QImageTextureGlyphCache *cache =
static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
@@ -3191,6 +2892,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
rightShift = 3; // divide by 8
int margin = cache->glyphMargin();
+ const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
@@ -3201,7 +2903,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
continue;
int x = qFloor(positions[i].x) + c.baseLineX - margin;
- int y = qFloor(positions[i].y) - c.baseLineY - margin;
+ int y = qFloor(positions[i].y + offs) - 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,
@@ -3239,13 +2941,15 @@ void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
fe->setFontScale(matrix.m11());
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
+
for (int i=0; i<glyphs.size(); ++i) {
TOpenFontCharMetrics tmetrics;
const TUint8 *glyphBitmapBytes;
TSize glyphBitmapSize;
fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
- const int x = qFloor(positions[i].x + tmetrics.HorizBearingX());
- const int y = qFloor(positions[i].y - tmetrics.HorizBearingY());
+ const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
+ const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
}
@@ -3346,19 +3050,6 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
}
inline ProcessSpans
-QRasterPaintEnginePrivate::getPenFunc(const QRect &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->pen.widthF());
- return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
-}
-
-inline ProcessSpans
QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
const QSpanData *data) const
{
@@ -3379,8 +3070,13 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
ensurePen();
ensureState();
- drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
- textItem->fontEngine());
+ QFontEngine *fontEngine = textItem->fontEngine();
+ if (!supportsTransformations(fontEngine)) {
+ drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
+ fontEngine);
+ } else {
+ QPaintEngineEx::drawStaticTextItem(textItem);
+ }
}
/*!
@@ -3403,36 +3099,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
#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;
-
- // ### 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();
-
+ if (!supportsTransformations(ti.fontEngine)) {
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
@@ -3467,7 +3134,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
|| (fontEngine->type() == QFontEngine::Proxy
&& !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
)) {
- fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
+ fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
return;
}
#endif // Q_WS_QWS
@@ -3490,6 +3157,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
for(int i = 0; i < glyphs.size(); i++) {
QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
+ // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
qRound(positions[i].x + metrics.x),
qRound(positions[i].y + metrics.y),
@@ -3544,48 +3212,16 @@ 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<QT_FT_Span, 4096> 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.drawPoints(points, pointCount);
}
@@ -3595,48 +3231,16 @@ 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<QT_FT_Span, 4096> 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.drawPoints(points, pointCount);
}
/*!
@@ -3645,59 +3249,22 @@ 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);
for (int i=0; i<lineCount; ++i) {
- int dashOffset = int(s->lastPen.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 +3321,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 +3330,10 @@ 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);
for (int i=0; i<lineCount; ++i) {
- int dashOffset = int(s->lastPen.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 +3351,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
@@ -3870,6 +3420,37 @@ void QRasterPaintEngine::releaseDC(HDC) const
#endif
+bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
+{
+ const QTransform &m = state()->matrix;
+#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
+ QFontEngine::Type fontEngineType = fontEngine->type();
+ if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
+ || (m.type() <= QTransform::TxTranslate
+ && (fontEngineType == QFontEngine::TestFontEngine
+ || fontEngineType == QFontEngine::Box))) {
+ return true;
+ }
+#endif
+ return supportsTransformations(fontEngine->fontDef.pixelSize, m);
+}
+
+bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
+{
+#if defined(Q_WS_MAC)
+ // Mac font engines don't support scaling and rotation
+ if (m.type() > QTransform::TxTranslate)
+#else
+ if (m.type() >= QTransform::TxProject)
+#endif
+ return true;
+
+ if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
+ return true;
+
+ return false;
+}
+
/*!
\internal
*/
@@ -4821,7 +4402,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, &currentClip, 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)
@@ -5473,759 +5054,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<devRect.x2);
- Q_ASSERT(y<devRect.y2);
- Q_ASSERT(spans[current].y == y);
- spans[current].len++;
- }
- if (spans[current].len > 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<devRect.x2 && y<devRect.y2);
- Q_ASSERT(spans[NSPANS - 1 - current].y == y);
- spans[NSPANS - 1 - current].len++;
- }
- if (spans[NSPANS - 1 - current].len > 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<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;
- }
- } 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;
- if (y < devRect.y1 || x > x1)
- continue;
- Q_ASSERT(x>=devRect.x1 && x<devRect.x2 && y>=devRect.y1 && 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;
- }
- }
- }
-flush_and_return:
- if (current > 0)
- span_func(current, ordered ? spans : spans + (NSPANS - current), data);
-}
-
-static void offset_pattern(int offset, bool *inDash, int *dashIndex, int *currentOffset, const QVarLengthArray<qreal> &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<qreal> penPattern = pen->dashPattern();
- QVarLengthArray<qreal> pattern(penPattern.size());
-
- int patternLength = 0;
- for (int i = 0; i < penPattern.size(); ++i)
- patternLength += qMax<qreal>(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<qreal>(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<qreal>(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.
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index 8859df0..8774fda 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -196,9 +196,6 @@ public:
void stroke(const QVectorPath &path, const QPen &pen);
void fill(const QVectorPath &path, const QBrush &brush);
- void strokePolygonCosmetic(const QPoint *pts, int pointCount, PolygonDrawMode mode);
- void strokePolygonCosmetic(const QPointF *pt, int pointCount, PolygonDrawMode mode);
-
void clip(const QVectorPath &path, Qt::ClipOperation op);
void clip(const QRect &rect, Qt::ClipOperation op);
void clip(const QRegion &region, Qt::ClipOperation op);
@@ -249,6 +246,8 @@ public:
virtual void drawBufferSpan(const uint *buffer, int bufsize,
int x, int y, int length, uint const_alpha);
#endif
+ bool supportsTransformations(const QFontEngine *fontEngine) const;
+ bool supportsTransformations(qreal pixelSize, const QTransform &m) const;
protected:
QRasterPaintEngine(QRasterPaintEnginePrivate &d, QPaintDevice *);
@@ -328,7 +327,6 @@ public:
bool isUnclipped_normalized(const QRect &rect) const;
bool isUnclipped(const QRect &rect, int penWidth) const;
bool isUnclipped(const QRectF &rect, int penWidth) const;
- ProcessSpans getPenFunc(const QRect &rect, const QSpanData *data) const;
ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const;
ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const;
ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 30cf206..8510416 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -44,6 +44,8 @@
#include "qstroker_p.h"
#include "qbezier_p.h"
#include <private/qpainterpath_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qstatictext_p.h>
#include <qvarlengtharray.h>
#include <qdebug.h>
@@ -831,7 +833,7 @@ void QPaintEngineEx::drawEllipse(const QRectF &r)
int point_count = 0;
x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
- QVectorPath vp((qreal *) pts, point_count, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
+ QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
draw(vp);
}
@@ -1057,5 +1059,48 @@ Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
return p;
}
+void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem)
+{
+ QPainterPath path;
+#ifndef Q_WS_MAC
+ path.setFillRule(Qt::WindingFill);
+#endif
+
+ if (staticTextItem->numGlyphs == 0)
+ return;
+
+ QFontEngine *fontEngine = staticTextItem->fontEngine();
+ fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions,
+ staticTextItem->numGlyphs, &path, 0);
+ if (!path.isEmpty()) {
+ QPainterState *s = state();
+ QPainter::RenderHints oldHints = s->renderHints;
+ bool changedHints = false;
+ if (bool(oldHints & QPainter::TextAntialiasing)
+ && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
+ && !bool(oldHints & QPainter::Antialiasing)) {
+ s->renderHints |= QPainter::Antialiasing;
+ renderHintsChanged();
+ changedHints = true;
+ }
+
+ fill(qtVectorPathForPath(path), staticTextItem->color);
+
+ if (changedHints) {
+ s->renderHints = oldHints;
+ renderHintsChanged();
+ }
+ }
+}
+
+bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform &m) const
+{
+ Q_UNUSED(pixelSize);
+
+ if (!m.isAffine())
+ return true;
+
+ return false;
+}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h
index 9730033..c605685 100644
--- a/src/gui/painting/qpaintengineex_p.h
+++ b/src/gui/painting/qpaintengineex_p.h
@@ -202,7 +202,7 @@ public:
virtual void updateState(const QPaintEngineState &state);
- virtual void drawStaticTextItem(QStaticTextItem *) = 0;
+ virtual void drawStaticTextItem(QStaticTextItem *);
virtual void setState(QPainterState *s);
inline QPainterState *state() { return static_cast<QPainterState *>(QPaintEngine::state); }
@@ -227,6 +227,7 @@ public:
IsEmulationEngine = 0x02 // If set, this object is a QEmulationEngine.
};
virtual uint flags() const {return 0;}
+ virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const;
protected:
QPaintEngineEx(QPaintEngineExPrivate &data);
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 17b7451..5a566d1 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -152,14 +152,6 @@ static inline uint line_emulation(uint emulation)
| QPaintEngine_OpaqueBackground);
}
-static bool qt_paintengine_supports_transformations(QPaintEngine::Type type)
-{
- return type == QPaintEngine::OpenGL2
- || type == QPaintEngine::OpenVG
- || type == QPaintEngine::OpenGL
- || type == QPaintEngine::CoreGraphics;
-}
-
#ifndef QT_NO_DEBUG
static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false)
{
@@ -2868,6 +2860,9 @@ void QPainter::setClipRect(const QRect &rect, Qt::ClipOperation op)
return;
}
+ if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
+ op = Qt::ReplaceClip;
+
d->state->clipRegion = rect;
d->state->clipOperation = op;
if (op == Qt::NoClip || op == Qt::ReplaceClip)
@@ -2923,6 +2918,9 @@ void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
return;
}
+ if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
+ op = Qt::ReplaceClip;
+
d->state->clipRegion = r;
d->state->clipOperation = op;
if (op == Qt::NoClip || op == Qt::ReplaceClip)
@@ -3328,6 +3326,9 @@ void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
return;
}
+ if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
+ op = Qt::ReplaceClip;
+
d->state->clipPath = path;
d->state->clipOperation = op;
if (op == Qt::NoClip || op == Qt::ReplaceClip)
@@ -5809,35 +5810,37 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
if (!font.isValid())
return;
- QVector<quint32> glyphIndexes = glyphRun.glyphIndexes();
- QVector<QPointF> glyphPositions = glyphRun.positions();
+ QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
- int count = qMin(glyphIndexes.size(), glyphPositions.size());
- QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
+ const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
+ const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
- bool paintEngineSupportsTransformations =
- d->extended != 0
- ? qt_paintengine_supports_transformations(d->extended->type())
- : qt_paintengine_supports_transformations(d->engine->type());
+ int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
+ QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
- // If the matrix is not affine, the paint engine will fall back to
- // drawing the glyphs as paths, which in turn means we should not
- // preprocess the glyph positions
- if (!d->state->matrix.isAffine())
- paintEngineSupportsTransformations = true;
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
+ bool supportsTransformations;
+ if (d->extended != 0) {
+ supportsTransformations = d->extended->supportsTransformations(fontD->fontEngine->fontDef.pixelSize,
+ d->state->matrix);
+ } else {
+ supportsTransformations = d->engine->type() == QPaintEngine::CoreGraphics
+ || d->state->matrix.isAffine();
+ }
for (int i=0; i<count; ++i) {
- QPointF processedPosition = position + glyphPositions.at(i);
- if (!paintEngineSupportsTransformations)
+ QPointF processedPosition = position + glyphPositions[i];
+ if (!supportsTransformations)
processedPosition = d->state->transform().map(processedPosition);
fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
}
- d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphRun.overline(),
+ d->drawGlyphs(glyphIndexes, fixedPointPositions.data(), count, font, glyphRun.overline(),
glyphRun.underline(), glyphRun.strikeOut());
}
-void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount,
+void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positions,
+ int glyphCount,
const QRawFont &font, bool overline, bool underline,
bool strikeOut)
{
@@ -6004,11 +6007,12 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText
return;
}
- bool paintEngineSupportsTransformations = qt_paintengine_supports_transformations(d->extended->type());
- if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) {
+ bool supportsTransformations = d->extended->supportsTransformations(staticText_d->font.pixelSize(),
+ d->state->matrix);
+ if (supportsTransformations && !staticText_d->untransformedCoordinates) {
staticText_d->untransformedCoordinates = true;
staticText_d->needsRelayout = true;
- } else if (!paintEngineSupportsTransformations && staticText_d->untransformedCoordinates) {
+ } else if (!supportsTransformations && staticText_d->untransformedCoordinates) {
staticText_d->untransformedCoordinates = false;
staticText_d->needsRelayout = true;
}
@@ -6468,8 +6472,7 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
const qreal underlineOffset = fe->underlinePosition().toReal();
// deliberately ceil the offset to avoid the underline coming too close to
// the text above it.
- const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
- const qreal underlinePos = pos.y() + qCeil(underlineOffset) - aliasedCoordinateDelta;
+ const qreal underlinePos = pos.y() + qCeil(underlineOffset);
if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle));
diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h
index 35cdf86..79d4b4b 100644
--- a/src/gui/painting/qpainter_p.h
+++ b/src/gui/painting/qpainter_p.h
@@ -232,7 +232,7 @@ public:
void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation);
#if !defined(QT_NO_RAWFONT)
- void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
+ void drawGlyphs(const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
const QRawFont &font, bool overline = false, bool underline = false,
bool strikeOut = false);
#endif
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp
index 6c5edbc..1d3f581 100644
--- a/src/gui/painting/qrasterizer.cpp
+++ b/src/gui/painting/qrasterizer.cpp
@@ -62,8 +62,8 @@ typedef int Q16Dot16;
#define SPAN_BUFFER_SIZE 256
-#define COORD_ROUNDING 0 // 0: round up, 1: round down
-#define COORD_OFFSET 0 // 26.6, 32 is half a pixel
+#define COORD_ROUNDING 1 // 0: round up, 1: round down
+#define COORD_OFFSET 32 // 26.6, 32 is half a pixel
static inline QT_FT_Vector PointToVector(const QPointF &p)
{
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 53fefa4..fdba9c9 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -296,14 +296,10 @@ void QTextureGlyphCache::fillInPendingGlyphs()
QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const
{
#if defined(Q_WS_X11)
- if (m_transform.type() > QTransform::TxTranslate && m_current_fontengine->type() == QFontEngine::Freetype) {
+ if (m_type != Raster_RGBMask && m_transform.type() > QTransform::TxTranslate && m_current_fontengine->type() == QFontEngine::Freetype) {
QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_None;
QImage::Format imageFormat = QImage::Format_Invalid;
switch (m_type) {
- case Raster_RGBMask:
- format = QFontEngineFT::Format_A32;
- imageFormat = QImage::Format_RGB32;
- break;
case Raster_A8:
format = QFontEngineFT::Format_A8;
imageFormat = QImage::Format_Indexed8;
@@ -312,6 +308,10 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition
format = QFontEngineFT::Format_Mono;
imageFormat = QImage::Format_Mono;
break;
+ case Raster_RGBMask:
+ // impossible condition (see the if-clause above)
+ // this option is here only to silence a compiler warning
+ break;
};
QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine);
@@ -367,7 +367,9 @@ void QImageTextureGlyphCache::createTextureData(int width, int height)
int QImageTextureGlyphCache::glyphMargin() const
{
-#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) || defined(Q_WS_X11)
+#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA))
+ return 1;
+#elif defined(Q_WS_X11)
return 0;
#else
return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
@@ -386,7 +388,7 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
}
#endif
- if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
+ if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
m_image.format());
diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
index aecbf2b..1eb5e61 100644
--- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
+++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
@@ -171,10 +171,8 @@ void QUnifiedToolbarSurface::flush(QWidget *widget)
if (!d->image)
return;
- if (widget->d_func()->flushRequested) {
- // We call display: directly to avoid flickering in the toolbar.
- qt_mac_display(widget);
- }
+ if (widget->d_func()->flushRequested)
+ qt_mac_setNeedsDisplay(widget);
}
void QUnifiedToolbarSurface::prepareBuffer(QImage::Format format, QWidget *widget)
diff --git a/src/gui/painting/qwindowsurface_qws.cpp b/src/gui/painting/qwindowsurface_qws.cpp
index c52f864..7e8cf9b 100644
--- a/src/gui/painting/qwindowsurface_qws.cpp
+++ b/src/gui/painting/qwindowsurface_qws.cpp
@@ -806,6 +806,10 @@ QWSMemorySurface::QWSMemorySurface(QWidget *w)
QWSMemorySurface::~QWSMemorySurface()
{
+#ifndef QT_NO_QWS_MULTIPROCESS
+ if (memlock != QWSDisplay::Data::getClientLock())
+ delete memlock;
+#endif
}
@@ -852,9 +856,9 @@ void QWSMemorySurface::setLock(int lockId)
{
if (memlock && memlock->id() == lockId)
return;
- delete memlock;
+ if (memlock != QWSDisplay::Data::getClientLock())
+ delete memlock;
memlock = (lockId == -1 ? 0 : new QWSLock(lockId));
- return;
}
#endif // QT_NO_QWS_MULTIPROCESS
@@ -946,37 +950,39 @@ void QWSLocalMemSurface::setGeometry(const QRect &rect)
}
uchar *deleteLater = 0;
- // In case of a Hide event we need to delete the memory after sending the
- // event to the server in order to let the server animate the event.
- if (size.isEmpty()) {
- deleteLater = mem;
- mem = 0;
- }
if (img.size() != size) {
- delete[] mem;
if (size.isEmpty()) {
+ if (memsize) {
+ // In case of a Hide event we need to delete the memory after sending the
+ // event to the server in order to let the server animate the event.
+ deleteLater = mem;
+ memsize = 0;
+ }
mem = 0;
img = QImage();
} else {
const QImage::Format format = preferredImageFormat(win);
const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
- const int memsize = bpl * size.height();
- mem = new uchar[memsize];
+ const int imagesize = bpl * size.height();
+ if (memsize < imagesize) {
+ delete[] mem;
+ memsize = imagesize;
+ mem = new uchar[memsize];
+ }
img = QImage(mem, size.width(), size.height(), bpl, format);
setImageMetrics(img, win);
}
}
QWSWindowSurface::setGeometry(rect);
+
delete[] deleteLater;
}
QByteArray QWSLocalMemSurface::permanentState() const
{
- QByteArray array;
- array.resize(sizeof(uchar*) + 3 * sizeof(int) +
- sizeof(SurfaceFlags));
+ QByteArray array(sizeof(uchar*) + 3 * sizeof(int) + sizeof(SurfaceFlags), Qt::Uninitialized);
char *ptr = array.data();
@@ -997,6 +1003,11 @@ QByteArray QWSLocalMemSurface::permanentState() const
void QWSLocalMemSurface::setPermanentState(const QByteArray &data)
{
+ if (memsize) {
+ delete[] mem;
+ memsize = 0;
+ }
+
int width;
int height;
QImage::Format format;
@@ -1023,6 +1034,10 @@ void QWSLocalMemSurface::setPermanentState(const QByteArray &data)
void QWSLocalMemSurface::releaseSurface()
{
+ if (memsize) {
+ delete[] mem;
+ memsize = 0;
+ }
mem = 0;
img = QImage();
}
@@ -1064,17 +1079,15 @@ bool QWSSharedMemSurface::setMemory(int memId)
void QWSSharedMemSurface::setDirectRegion(const QRegion &r, int id)
{
QWSMemorySurface::setDirectRegion(r, id);
- if(mem.address())
+ if (mem.address())
*(uint *)mem.address() = id;
}
const QRegion QWSSharedMemSurface::directRegion() const
{
- QWSSharedMemory *cmem = const_cast<QWSSharedMemory *>(&mem);
- if (cmem->address() && ((int*)cmem->address())[0] == directRegionId())
+ if (mem.address() && *(uint *)mem.address() == uint(directRegionId())
return QWSMemorySurface::directRegion();
- else
- return QRegion();
+ return QRegion();
}
#endif
@@ -1117,8 +1130,6 @@ void QWSSharedMemSurface::setGeometry(const QRect &rect)
mem.detach();
img = QImage();
} else {
- mem.detach();
-
QWidget *win = window();
const QImage::Format format = preferredImageFormat(win);
const int bpl = nextMulOf4(bytesPerPixel(format) * size.width());
@@ -1127,9 +1138,12 @@ void QWSSharedMemSurface::setGeometry(const QRect &rect)
#else
const int imagesize = bpl * size.height();
#endif
- if (!mem.create(imagesize)) {
- perror("QWSSharedMemSurface::setGeometry allocating shared memory");
- qFatal("Error creating shared memory of size %d", imagesize);
+ if (mem.size() < imagesize) {
+ mem.detach();
+ if (!mem.create(imagesize)) {
+ perror("QWSSharedMemSurface::setGeometry allocating shared memory");
+ qFatal("Error creating shared memory of size %d", imagesize);
+ }
}
#ifdef QT_QWS_CLIENTBLIT
*((uint *)mem.address()) = 0;
@@ -1147,8 +1161,7 @@ void QWSSharedMemSurface::setGeometry(const QRect &rect)
QByteArray QWSSharedMemSurface::permanentState() const
{
- QByteArray array;
- array.resize(6 * sizeof(int));
+ QByteArray array(6 * sizeof(int), Qt::Uninitialized);
int *ptr = reinterpret_cast<int*>(array.data());
@@ -1222,8 +1235,8 @@ bool QWSOnScreenSurface::isValid() const
QByteArray QWSOnScreenSurface::permanentState() const
{
- QByteArray array;
- array.resize(sizeof(int));
+ QByteArray array(sizeof(int), Qt::Uninitialized);
+
int *ptr = reinterpret_cast<int*>(array.data());
ptr[0] = QApplication::desktop()->screenNumber(window());
return array;
@@ -1263,8 +1276,7 @@ QWSYellowSurface::~QWSYellowSurface()
QByteArray QWSYellowSurface::permanentState() const
{
- QByteArray array;
- array.resize(2 * sizeof(int));
+ QByteArray array(2 * sizeof(int), Qt::Uninitialized);
int *ptr = reinterpret_cast<int*>(array.data());
ptr[0] = surfaceSize.width();