/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
#include <qpainterpath.h>
#include <qdebug.h>
#include <qhash.h>
-#include <qlabel.h>
#include <qbitmap.h>
#include <qmath.h>
-#if defined (Q_WS_X11)
-# include <private/qfontengine_ft_p.h>
-#endif
-
// #include <private/qdatabuffer_p.h>
// #include <private/qpainter_p.h>
#include <private/qmath_p.h>
// #include "qbezier_p.h"
#include "qoutlinemapper_p.h"
-#if defined(Q_WS_WIN)
-# include <qt_windows.h>
+#include <limits.h>
+
+#ifdef Q_OS_WIN
# include <qvarlengtharray.h>
# include <private/qfontengine_p.h>
-# if defined(Q_OS_WINCE)
-# include "qguifunctions_wince.h"
-# endif
-#elif defined(Q_WS_MAC)
-# include <private/qt_mac_p.h>
-# include <private/qpixmap_mac_p.h>
-# include <private/qpaintengine_mac_p.h>
-#elif defined(Q_WS_QWS)
-# if !defined(QT_NO_FREETYPE)
-# include <private/qfontengine_ft_p.h>
-# endif
-# if !defined(QT_NO_QWS_QPF2)
-# include <private/qfontengine_qpf_p.h>
+# include <qt_windows.h>
+#ifdef Q_OS_WIN64
+# include <malloc.h>
# endif
-# include <private/qabstractfontengine_p.h>
-#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
-# include <private/qfontengine_s60_p.h>
-#elif defined(Q_WS_QPA)
-# include <private/qfontengine_ft_p.h>
#endif
-#if defined(Q_WS_WIN64)
-# include <malloc.h>
-#endif
-#include <limits.h>
-
QT_BEGIN_NAMESPACE
+class QRectVectorPath : public QVectorPath {
+public:
+ inline void set(const QRect &r) {
+ qreal left = r.x();
+ qreal right = r.x() + r.width();
+ qreal top = r.y();
+ qreal bottom = r.y() + r.height();
+ pts[0] = left;
+ pts[1] = top;
+ pts[2] = right;
+ pts[3] = top;
+ pts[4] = right;
+ pts[5] = bottom;
+ pts[6] = left;
+ pts[7] = bottom;
+ }
+
+ inline void set(const QRectF &r) {
+ qreal left = r.x();
+ qreal right = r.x() + r.width();
+ qreal top = r.y();
+ qreal bottom = r.y() + r.height();
+ pts[0] = left;
+ pts[1] = top;
+ pts[2] = right;
+ pts[3] = top;
+ pts[4] = right;
+ pts[5] = bottom;
+ pts[6] = left;
+ pts[7] = bottom;
+ }
+ inline QRectVectorPath(const QRect &r)
+ : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
+ {
+ set(r);
+ }
+ inline QRectVectorPath(const QRectF &r)
+ : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
+ {
+ set(r);
+ }
+ inline QRectVectorPath()
+ : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
+ { }
+
+ qreal pts[8];
+};
+
Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
#define qreal_to_fixed_26_6(f) (int(f * 64))
// 4 pixels.
#define int_dim(pos, dim) (int(pos+dim) - int(pos))
-#ifdef Q_WS_WIN
-extern bool qt_cleartype_enabled;
-#endif
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
-#ifdef Q_WS_MAC
-extern bool qt_applefontsmoothing_enabled;
+#ifdef Q_OS_WIN
+
+static inline bool winClearTypeFontsEnabled()
+{
+ UINT result = 0;
+#if !defined(SPI_GETFONTSMOOTHINGTYPE) // MinGW
+# define SPI_GETFONTSMOOTHINGTYPE 0x200A
+# define FE_FONTSMOOTHINGCLEARTYPE 0x002
#endif
+ SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
+ return result == FE_FONTSMOOTHINGCLEARTYPE;
+}
+
+/*!
+ \internal
+ */
+bool QRasterPaintEngine::clearTypeFontsEnabled()
+{
+ static const bool result = winClearTypeFontsEnabled();
+ return result;
+}
+
+#endif // Q_OS_WIN
+
/********************************************************************************
static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
static void qt_span_clip(int count, const QSpan *spans, void *userData);
-static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
struct ClipData
{
LineDrawIncludeLastPixel
};
+static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
+ ProcessSpans pen_func, ProcessSpans brush_func,
+ QSpanData *pen_data, QSpanData *brush_data);
+
struct QRasterFloatPoint {
qreal x;
qreal y;
Q_D(QRasterPaintEngine);
-#ifdef Q_WS_WIN
+#ifdef Q_OS_WIN
d->hdc = 0;
#endif
case QInternal::Image:
format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
break;
-#ifdef Q_WS_QWS
- case QInternal::CustomRaster:
- d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
- break;
-#endif
default:
qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
d->device = 0;
if (device->devType() == QInternal::Pixmap) {
QPixmap *pixmap = static_cast<QPixmap *>(device);
- QPixmapData *pd = pixmap->pixmapData();
- if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
+ QPlatformPixmap *pd = pixmap->handle();
+ if (pd->classId() == QPlatformPixmap::RasterClass || pd->classId() == QPlatformPixmap::BlitterClass)
d->device = pd->buffer();
} else {
d->device = device;
}
#endif
-#if defined(Q_WS_WIN)
- d->isPlain45DegreeRotation = true;
-#endif
-
if (d->mono_surface)
d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
-#if defined(Q_WS_WIN)
- else if (qt_cleartype_enabled)
-#elif defined (Q_WS_MAC)
- else if (qt_applefontsmoothing_enabled)
+#if defined(Q_OS_WIN)
+ else if (clearTypeFontsEnabled())
#else
else if (false)
#endif
s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
ensureOutlineMapper();
-
-#ifdef Q_WS_WIN
- Q_D(QRasterPaintEngine);
- d->isPlain45DegreeRotation = false;
- if (txop >= QTransform::TxRotate) {
- d->isPlain45DegreeRotation =
- (qFuzzyIsNull(matrix.m11())
- && qFuzzyIsNull(matrix.m12() - qreal(1))
- && qFuzzyIsNull(matrix.m21() + qreal(1))
- && qFuzzyIsNull(matrix.m22())
- )
- ||
- (qFuzzyIsNull(matrix.m11() + qreal(1))
- && qFuzzyIsNull(matrix.m12())
- && qFuzzyIsNull(matrix.m21())
- && qFuzzyIsNull(matrix.m22() + qreal(1))
- )
- ||
- (qFuzzyIsNull(matrix.m11())
- && qFuzzyIsNull(matrix.m12() + qreal(1))
- && qFuzzyIsNull(matrix.m21() - qreal(1))
- && qFuzzyIsNull(matrix.m22())
- )
- ;
- }
-#endif
-
}
flags.fast_pen = true;
flags.antialiased = false;
flags.bilinear = false;
+ flags.legacy_rounding = false;
flags.fast_text = true;
flags.int_xform = true;
flags.tx_noshear = true;
} else if (pen_style != Qt::NoPen) {
if (!d->dashStroker)
d->dashStroker.reset(new QDashStroker(&d->basicStroker));
- if (pen.isCosmetic()) {
+ if (qt_pen_is_cosmetic(pen, s->renderHints)) {
d->dashStroker->setClipRect(d->deviceRect);
} else {
// ### I've seen this inverted devrect multiple places now...
s->stroker = 0;
}
- ensureState(); // needed because of tx_noshear...
+ ensureRasterState(); // needed because of tx_noshear...
+ bool cosmetic = qt_pen_is_cosmetic(pen, s->renderHints);
s->flags.fast_pen = pen_style > Qt::NoPen
&& s->penData.blend
- && ((pen.isCosmetic() && penWidth <= 1)
- || (s->flags.tx_noshear && penWidth * s->txscale <= 1));
+ && ((cosmetic && penWidth <= 1)
+ || (!cosmetic && s->flags.tx_noshear && penWidth * s->txscale <= 1));
s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
d->outlineMapper->setMatrix(state()->matrix);
}
-void QRasterPaintEngine::updateState()
+void QRasterPaintEngine::updateRasterState()
{
QRasterPaintEngineState *s = state();
s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
+ s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
if (was_aa != s->flags.antialiased)
s->strokeFlags |= DirtyHints;
}
}
-#ifdef Q_WS_QWS
-void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
-{
- rasterBuffer->prepare(device);
-}
-#endif
-
void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
const QImage &img,
SrcOverBlendFunc func,
exDeviceRect = deviceRect;
Q_Q(QRasterPaintEngine);
- q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
- q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
- q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
+ if (q->state()) {
+ q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
+ q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
+ q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
+ }
}
void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
const QPainterPath::ElementType *types = path.elements();
// There are some cases that are not supported by clip(QRect)
- if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
- || s->clip->hasRectClip || s->clip->hasRegionClip)) {
+ if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
if (s->matrix.type() <= QTransform::TxScale
&& ((path.shape() == QVectorPath::RectangleHint)
|| (isRect(points, path.elementCount())
newClip->fixup();
- if (op == Qt::UniteClip) {
- // merge clips
- QClipData *result = new QClipData(d->rasterBuffer->height());
- QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
- qt_merge_clip(current, newClip, result);
- result->fixup();
- delete newClip;
- if (!s->clip)
- delete current;
- newClip = result;
- }
-
if (s->flags.has_clip_ownership)
delete s->clip;
if (op == Qt::NoClip) {
qrasterpaintengine_state_setNoClip(s);
- } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
+ } else if (s->matrix.type() > QTransform::TxScale) {
QPaintEngineEx::clip(rect, op);
return;
if (op == Qt::NoClip) {
qrasterpaintengine_state_setNoClip(s);
} else if (s->matrix.type() > QTransform::TxScale
- || op == Qt::UniteClip
|| (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
|| (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
QPaintEngineEx::clip(region, op);
}
/*!
+ \fn const QClipData *QRasterPaintEngine::clipData() const
+
+ \internal
+*/
+
+
+/*!
\internal
*/
void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
#endif
Q_D(QRasterPaintEngine);
- ensureState();
+ ensureRasterState();
QRasterPaintEngineState *s = state();
// Fill
QRectVectorPath path;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
stroker.drawPath(path);
#endif
#ifdef QT_FAST_SPANS
Q_D(QRasterPaintEngine);
- ensureState();
+ ensureRasterState();
QRasterPaintEngineState *s = state();
QRectVectorPath path;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
stroker.drawPath(path);
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(path);
} else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
- qreal width = s->lastPen.isCosmetic()
+ qreal width = qt_pen_is_cosmetic(s->lastPen, s->renderHints)
? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
: qpen_widthf(s->lastPen) * s->txscale;
int dashIndex = 0;
QPaintEngineEx::stroke(path, pen);
}
-static inline QRect toNormalizedFillRect(const QRectF &rect)
+QRect QRasterPaintEngine::toNormalizedFillRect(const QRectF &rect)
{
- int x1 = qRound(rect.x());
- int y1 = qRound(rect.y());
- int x2 = qRound(rect.right());
- int y2 = qRound(rect.bottom());
+ QRasterPaintEngineState *s = state();
+
+ qreal delta = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
+
+ int x1 = qRound(rect.x() + delta);
+ int y1 = qRound(rect.y() + delta);
+ int x2 = qRound(rect.right() + delta);
+ int y2 = qRound(rect.bottom() + delta);
if (x2 < x1)
qSwap(x1, x2);
fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
return;
}
- ensureState();
+ ensureRasterState();
if (s->flags.tx_noshear) {
d->initializeRasterizer(&s->brushData);
// ### Is normalizing really necessary here?
return;
}
}
- ensureState();
+ ensureRasterState();
if (s->flags.tx_noshear) {
d->initializeRasterizer(data);
QRectF nr = r.normalized();
if (mode != PolylineMode) {
// Do the fill...
ensureBrush();
- if (s->brushData.blend) {
+ if (s->brushData.blend)
fillPolygon(points, pointCount, mode);
- }
}
// Do the outline...
QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
QPaintEngineEx::stroke(vp, s->lastPen);
if (s->penData.blend) {
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));
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
QPaintEngineEx::stroke(vp, s->lastPen);
qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
#endif
- QPixmapData *pd = pixmap.pixmapData();
- if (pd->classId() == QPixmapData::RasterClass) {
- const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
+ QPlatformPixmap *pd = pixmap.handle();
+ if (pd->classId() == QPlatformPixmap::RasterClass) {
+ const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
if (image.depth() == 1) {
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
#endif
- QPixmapData* pd = pixmap.pixmapData();
- if (pd->classId() == QPixmapData::RasterClass) {
- const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
+ QPlatformPixmap* pd = pixmap.handle();
+ if (pd->classId() == QPlatformPixmap::RasterClass) {
+ const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
if (image.depth() == 1) {
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
}
}
-// assumes that rect has positive width and height
-static inline const QRect toRect_normalized(const QRectF &rect)
-{
- const int x = qRound(rect.x());
- const int y = qRound(rect.y());
- const int w = int(rect.width() + qreal(0.5));
- const int h = int(rect.height() + qreal(0.5));
-
- return QRect(x, y, w, h);
-}
-
static inline int fast_ceil_positive(const qreal &v)
{
const int iv = int(v);
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
+ qreal scale = img.devicePixelRatio();
- if (s->matrix.type() > QTransform::TxTranslate) {
- drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
+ if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) {
+ drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
img,
QRectF(0, 0, img.width(), img.height()));
} else {
int sr_b = qCeil(sr.bottom()) - 1;
if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
+ // as fillRect will apply the aliased coordinate delta we need to
+ // subtract it here as we don't use it for image drawing
QTransform old = s->matrix;
+ if (s->flags.legacy_rounding)
+ s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
+
// Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
QRgb color = img.pixel(sr_l, sr_t);
switch (img.format()) {
return;
}
} else {
+ // Test for optimized high-dpi case: 2x source on 2x target. (Could be generalized to nX.)
+ bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
+ bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
+ if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
+ SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
+ if (func) {
+ QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
+ if (!clip) {
+ d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
+ return;
+ } else if (clip->hasRectClip) {
+ d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
+ return;
+ }
+ }
+ }
SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
if (func && (!clip || clip->hasRectClip)) {
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
}
#ifdef QT_FAST_SPANS
- ensureState();
+ ensureRasterState();
if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
+ d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
+
+ const QPointF offs = s->flags.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF();
const QRectF &rect = r.normalized();
- const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
- const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
+ const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
+ const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
if (s->flags.tx_noshear)
d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
return;
}
#endif
+ const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
QPainterPath path;
path.addRect(r);
QTransform m = s->matrix;
s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
m.m21(), m.m22(), m.m23(),
- m.m31(), m.m32(), m.m33());
+ m.m31() - offs, m.m32() - offs, m.m33());
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
QImage image;
- QPixmapData *pd = pixmap.pixmapData();
- if (pd->classId() == QPixmapData::RasterClass) {
- image = static_cast<QRasterPixmapData *>(pd)->image;
+ QPlatformPixmap *pd = pixmap.handle();
+ if (pd->classId() == QPlatformPixmap::RasterClass) {
+ image = static_cast<QRasterPlatformPixmap *>(pd)->image;
} else {
image = pixmap.toImage();
}
d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
#ifdef QT_FAST_SPANS
- ensureState();
+ ensureRasterState();
if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
+ d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
const QRectF &rect = r.normalized();
const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
/*!
\internal
+ */
+QRasterBuffer *QRasterPaintEngine::rasterBuffer()
+{
+ Q_D(QRasterPaintEngine);
+ return d->rasterBuffer.data();
+}
+
+/*!
+ \internal
*/
void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
{
blend(current, spans, &s->penData);
}
+/*!
+ \internal
+*/
bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
const QFixedPoint *positions, QFontEngine *fontEngine)
{
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
-#if !defined(QT_NO_FREETYPE)
- if (fontEngine->type() == QFontEngine::Freetype) {
- QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
- QFontEngineFT::GlyphFormat neededFormat =
+ if (fontEngine->hasInternalCaching()) {
+ QFontEngine::GlyphFormat neededFormat =
painter()->device()->devType() == QInternal::Widget
- ? fe->defaultGlyphFormat()
- : QFontEngineFT::Format_A8;
-
- if (d_func()->mono_surface
- || fe->isBitmapFont() // alphaPenBlt can handle mono, too
- )
- neededFormat = QFontEngineFT::Format_Mono;
+ ? QFontEngine::Format_None
+ : QFontEngine::Format_A8;
- if (neededFormat == QFontEngineFT::Format_None)
- neededFormat = QFontEngineFT::Format_A8;
-
- QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
- if (s->matrix.type() >= QTransform::TxScale) {
- if (s->matrix.isAffine())
- gset = fe->loadTransformedGlyphSet(s->matrix);
- else
- gset = 0;
- }
-
- if (!gset || gset->outline_drawing
- || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
- return false;
-
- FT_Face lockedFace = 0;
-
- int depth;
- switch (neededFormat) {
- case QFontEngineFT::Format_Mono:
- depth = 1;
- break;
- case QFontEngineFT::Format_A8:
- depth = 8;
- break;
- case QFontEngineFT::Format_A32:
- depth = 32;
- break;
- default:
- Q_ASSERT(false);
- depth = 0;
- };
+ if (d_func()->mono_surface) // alphaPenBlt can handle mono, too
+ neededFormat = QFontEngine::Format_Mono;
for (int i = 0; i < numGlyphs; i++) {
- QFixed spp = fe->subPixelPositionForX(positions[i].x);
- QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
+ QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
- if (!glyph || glyph->format != neededFormat) {
- if (!lockedFace)
- lockedFace = fe->lockFace();
- glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
- }
-
- if (!glyph || !glyph->data)
+ QPoint offset;
+ QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix,
+ &offset);
+ if (alphaMap == 0 || alphaMap->isNull())
continue;
- int pitch;
- switch (neededFormat) {
- case QFontEngineFT::Format_Mono:
- pitch = ((glyph->width + 31) & ~31) >> 3;
- break;
- case QFontEngineFT::Format_A8:
- pitch = (glyph->width + 3) & ~3;
- break;
- case QFontEngineFT::Format_A32:
- pitch = glyph->width * 4;
- break;
- default:
- Q_ASSERT(false);
- pitch = 0;
- };
-
- alphaPenBlt(glyph->data, pitch, depth,
- qFloor(positions[i].x) + glyph->x,
- qFloor(positions[i].y) - glyph->y,
- glyph->width, glyph->height);
+ alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(),
+ qFloor(positions[i].x) + offset.x(),
+ qRound(positions[i].y) + offset.y(),
+ alphaMap->width(), alphaMap->height());
+
+ fontEngine->unlockAlphaMapForGlyph();
}
- if (lockedFace)
- fe->unlockFace();
- } else
-#endif
- {
+
+ } else {
QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
QImageTextureGlyphCache *cache =
else if (depth == 1)
rightShift = 3; // divide by 8
- int margin = cache->glyphMargin();
+ int margin = fontEngine->glyphMargin(glyphType);
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
- QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
+ QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords[glyph];
if (c.isNull())
continue;
int x = qFloor(positions[i].x) + c.baseLineX - margin;
- int y = qFloor(positions[i].y) - c.baseLineY - margin;
+ int y = qRound(positions[i].y) - c.baseLineY - margin;
// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
// c.x, c.y,
return true;
}
-#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
-void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
-{
- Q_D(QRasterPaintEngine);
- QRasterPaintEngineState *s = state();
-
- QFontEngine *fontEngine = ti.fontEngine;
- if (fontEngine->type() != QFontEngine::S60FontEngine) {
- QPaintEngineEx::drawTextItem(p, ti);
- return;
- }
-
- QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
-
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = s->matrix;
- matrix.translate(p.x(), p.y());
- if (matrix.type() == QTransform::TxScale)
- fe->setFontScale(matrix.m11());
- ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-
- for (int i=0; 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());
- alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
- }
-
- if (matrix.type() == QTransform::TxScale)
- fe->setFontScale(1.0);
-
- return;
-}
-#endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
/*!
* Returns true if the rectangle is completely within the current clip
return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
}
+inline ProcessSpans
+QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
+ const QSpanData *data) const
+{
+ Q_Q(const QRasterPaintEngine);
+ const QRasterPaintEngineState *s = q->state();
+
+ if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
+ return data->blend;
+ const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
+ return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
+}
+
+static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
+ glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
+{
+ QFixed clipLeft = QFixed::fromReal(clip.left());
+ QFixed clipRight = QFixed::fromReal(clip.right());
+ QFixed clipTop = QFixed::fromReal(clip.top());
+ QFixed clipBottom = QFixed::fromReal(clip.bottom());
+
+ int first = 0;
+ while (first < numGlyphs) {
+ glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
+ QFixed left = metrics.x + positions[first].x;
+ QFixed top = metrics.y + positions[first].y;
+ QFixed right = left + metrics.width;
+ QFixed bottom = top + metrics.height;
+ if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
+ break;
+ ++first;
+ }
+ int last = numGlyphs - 1;
+ while (last > first) {
+ glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
+ QFixed left = metrics.x + positions[last].x;
+ QFixed top = metrics.y + positions[last].y;
+ QFixed right = left + metrics.width;
+ QFixed bottom = top + metrics.height;
+ if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
+ break;
+ --last;
+ }
+ return QPair<int, int>(first, last + 1);
+}
+
/*!
\reimp
*/
void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
{
+ if (textItem->numGlyphs == 0)
+ return;
+
ensurePen();
- ensureState();
+ ensureRasterState();
+
+ QFontEngine *fontEngine = textItem->fontEngine();
+ if (!supportsTransformations(fontEngine)) {
+ drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
+ fontEngine);
+ } else if (state()->matrix.type() < QTransform::TxProject) {
+ bool invertible;
+ QTransform invMat = state()->matrix.inverted(&invertible);
+ if (!invertible)
+ return;
- drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
- textItem->fontEngine());
+ QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+ textItem->fontEngine(), textItem->glyphs,
+ textItem->glyphPositions, textItem->numGlyphs);
+ QStaticTextItem copy = *textItem;
+ copy.glyphs += range.first;
+ copy.glyphPositions += range.first;
+ copy.numGlyphs = range.second - range.first;
+ QPaintEngineEx::drawStaticTextItem(©);
+ } else {
+ QPaintEngineEx::drawStaticTextItem(textItem);
+ }
}
/*!
void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
- QRasterPaintEngineState *s = state();
#ifdef QT_DEBUG_DRAW
Q_D(QRasterPaintEngine);
d->glyphCacheType);
#endif
+ if (ti.glyphs.numGlyphs == 0)
+ return;
ensurePen();
- ensureState();
-
-#if defined (Q_WS_WIN) || defined(Q_WS_MAC)
-
- bool drawCached = true;
-
- if (s->matrix.type() >= QTransform::TxProject)
- drawCached = false;
+ ensureRasterState();
- // 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();
+ QRasterPaintEngineState *s = state();
+ QTransform matrix = s->matrix;
+ if (!supportsTransformations(ti.fontEngine)) {
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = s->matrix;
matrix.translate(p.x(), p.y());
-
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
- return;
- }
-
-#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
- if (s->matrix.type() <= QTransform::TxTranslate
- || (s->matrix.type() == QTransform::TxScale
- && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
- drawGlyphsS60(p, ti);
- return;
- }
-#else // Q_WS_WIN || Q_WS_MAC
-
- QFontEngine *fontEngine = ti.fontEngine;
-
-#if defined(Q_WS_QWS)
- if (fontEngine->type() == QFontEngine::Box) {
- fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
- return;
- }
-
- if (s->matrix.type() < QTransform::TxScale
- && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
- || (fontEngine->type() == QFontEngine::Proxy
- && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
- )) {
- fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
- return;
- }
-#endif // Q_WS_QWS
-
-#ifdef Q_WS_QPA
- if (s->matrix.type() < QTransform::TxScale) {
+ } else if (matrix.type() < QTransform::TxProject) {
+ bool invertible;
+ QTransform invMat = matrix.inverted(&invertible);
+ if (!invertible)
+ return;
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = state()->transform();
- qreal _x = qFloor(p.x());
- qreal _y = qFloor(p.y());
- matrix.translate(_x, _y);
+ ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
+ ti.flags, glyphs, positions);
+ QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+ ti.fontEngine, glyphs.data(), positions.data(),
+ glyphs.size());
- fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
- if (glyphs.size() == 0)
+ if (range.first >= range.second)
return;
- for(int i = 0; i < glyphs.size(); i++) {
- QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
- glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
- alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
- qRound(positions[i].x + metrics.x),
- qRound(positions[i].y + metrics.y),
- img.width(), img.height());
- }
- return;
- }
-#endif //Q_WS_QPA
-
-#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
-
-#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
- if (fontEngine->type() == QFontEngine::QPF2) {
- QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
- if (renderingEngine)
- fontEngine = renderingEngine;
- }
-#endif
-
- if (fontEngine->type() != QFontEngine::Freetype) {
+ QStaticTextItem staticTextItem;
+ staticTextItem.color = s->pen.color();
+ staticTextItem.font = s->font;
+ staticTextItem.setFontEngine(ti.fontEngine);
+ staticTextItem.numGlyphs = range.second - range.first;
+ staticTextItem.glyphs = glyphs.data() + range.first;
+ staticTextItem.glyphPositions = positions.data() + range.first;
+ QPaintEngineEx::drawStaticTextItem(&staticTextItem);
+ } else {
QPaintEngineEx::drawTextItem(p, ti);
- return;
}
-
- QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
-
- QTransform matrix = s->matrix;
- matrix.translate(p.x(), p.y());
-
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
- if (glyphs.size() == 0)
- return;
-
- if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
- QPaintEngine::drawTextItem(p, ti);
-
- return;
-#endif
-#endif
-
- QPaintEngineEx::drawTextItem(p, ti);
}
/*!
}
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPoints(points, pointCount);
}
}
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPoints(points, pointCount);
}
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i=0; i<lineCount; ++i) {
const QLine &l = lines[i];
stroker.drawLine(l.p1(), l.p2());
return;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i=0; i<lineCount; ++i) {
QLineF line = lines[i];
stroker.drawLine(line.p1(), line.p2());
*/
void QRasterPaintEngine::drawEllipse(const QRectF &rect)
{
- QPaintEngineEx::drawEllipse(rect);
-}
-
-/*!
- \internal
-*/
-#ifdef Q_WS_MAC
-void QRasterPaintEngine::setCGContext(CGContextRef ctx)
-{
Q_D(QRasterPaintEngine);
- d->cgContext = ctx;
-}
+ QRasterPaintEngineState *s = state();
-/*!
- \internal
-*/
-CGContextRef QRasterPaintEngine::getCGContext() const
-{
- Q_D(const QRasterPaintEngine);
- return d->cgContext;
+ ensurePen();
+ if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
+ || (qpen_style(s->lastPen) == Qt::NoPen))
+ && !s->flags.antialiased
+ && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
+ && !rect.isEmpty()
+ && s->matrix.type() <= QTransform::TxScale) // no shear
+ {
+ ensureBrush();
+ const QRectF r = s->matrix.mapRect(rect);
+ ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
+ ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
+ const QRect brect = QRect(int(r.x()), int(r.y()),
+ int_dim(r.x(), r.width()),
+ int_dim(r.y(), r.height()));
+ if (brect == r) {
+ drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
+ &s->penData, &s->brushData);
+ return;
+ }
+ }
+ QPaintEngineEx::drawEllipse(rect);
}
-#endif
-#ifdef Q_WS_WIN
+
+#ifdef Q_OS_WIN
/*!
\internal
*/
/*!
\internal
*/
-QPoint QRasterPaintEngine::coordinateOffset() const
+bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const
{
- return QPoint(0, 0);
+ const QTransform &m = state()->matrix;
+ return supportsTransformations(fontEngine, m);
}
/*!
- Draws the given color \a spans with the specified \a color. The \a
- count parameter specifies the number of spans.
-
- The default implementation does nothing; reimplement this function
- to draw the given color \a spans with the specified \a color. Note
- that this function \e must be reimplemented if the framebuffer is
- not memory-mapped.
-
- \sa drawBufferSpan()
+ \internal
*/
-#if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
-void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
+bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const
{
- Q_UNUSED(spans);
- Q_UNUSED(count);
- Q_UNUSED(color);
- qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
- "a non memory-mapped device");
+ if (fontEngine->supportsTransformations(m))
+ return true;
+
+ return !shouldDrawCachedGlyphs(fontEngine, m);
}
/*!
- \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
-
- Draws the given \a buffer.
-
- The default implementation does nothing; reimplement this function
- to draw a buffer that contains more than one color. Note that this
- function \e must be reimplemented if the framebuffer is not
- memory-mapped.
-
- The \a size parameter specifies the total size of the given \a
- buffer, while the \a length parameter specifies the number of
- pixels to draw. The buffer's position is given by (\a x, \a
- y). The provided \a alpha value is added to each pixel in the
- buffer when drawing.
-
- \sa drawColorSpans()
+ \internal
*/
-void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
- int x, int y, int length, uint const_alpha)
+QPoint QRasterPaintEngine::coordinateOffset() const
{
- Q_UNUSED(buffer);
- Q_UNUSED(bufsize);
- Q_UNUSED(x);
- Q_UNUSED(y);
- Q_UNUSED(length);
- Q_UNUSED(const_alpha);
- qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
- "a non memory-mapped device");
+ return QPoint(0, 0);
}
-#endif // Q_WS_QWS
void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
{
spans[n].y = y;
spans[n].coverage = 255;
int len = 1;
- while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
+ while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
++src_x;
++len;
}
spans[n].y = y;
spans[n].coverage = 255;
int len = 1;
- while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
+ while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
++src_x;
++len;
}
return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
}
-static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
-{
- Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
-
- QVarLengthArray<short, 4096> buffer;
-
- QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
- QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
- result->initialize();
-
- for (int y = 0; y < c1->clipSpanHeight; ++y) {
- const QSpan *c1_spans = c1ClipLines[y].spans;
- int c1_count = c1ClipLines[y].count;
- const QSpan *c2_spans = c2ClipLines[y].spans;
- int c2_count = c2ClipLines[y].count;
-
- if (c1_count == 0 && c2_count == 0)
- continue;
- if (c1_count == 0) {
- result->appendSpans(c2_spans, c2_count);
- continue;
- } else if (c2_count == 0) {
- result->appendSpans(c1_spans, c1_count);
- continue;
- }
-
- // we need to merge the two
-
- // find required length
- int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
- c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
- buffer.resize(max);
- memset(buffer.data(), 0, buffer.size() * sizeof(short));
-
- // Fill with old spans.
- for (int i = 0; i < c1_count; ++i) {
- const QSpan *cs = c1_spans + i;
- for (int j=cs->x; j<cs->x + cs->len; ++j)
- buffer[j] = cs->coverage;
- }
-
- // Fill with new spans
- for (int i = 0; i < c2_count; ++i) {
- const QSpan *cs = c2_spans + i;
- for (int j = cs->x; j < cs->x + cs->len; ++j) {
- buffer[j] += cs->coverage;
- if (buffer[j] > 255)
- buffer[j] = 255;
- }
- }
-
- int x = 0;
- while (x<max) {
-
- // Skip to next span
- while (x < max && buffer[x] == 0) ++x;
- if (x >= max) break;
-
- int sx = x;
- int coverage = buffer[x];
-
- // Find length of span
- while (x < max && buffer[x] == coverage)
- ++x;
-
- result->appendSpan(sx, x - sx, y, coverage);
- }
- }
-}
-
void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
{
Q_Q(QRasterPaintEngine);
QRasterPaintEngineState *s = q->state();
rasterizer->setAntialiased(s->flags.antialiased);
+ rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
QRect clipRect(deviceRect);
ProcessSpans blend;
int q_gray_rendered_spans(QT_FT_Raster raster);
}
+static inline uchar *alignAddress(uchar *address, quintptr alignmentMask)
+{
+ return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
+}
+
void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
ProcessSpans callback,
void *userData, QRasterBuffer *)
if (!s->flags.antialiased) {
rasterizer->setAntialiased(s->flags.antialiased);
+ rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
rasterizer->setClipRect(deviceRect);
rasterizer->initialize(callback, userData);
// minimize memory reallocations. However if initial size for
// raster pool is changed for lower value, reallocations will
// occur normally.
- const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
- int rasterPoolSize = rasterPoolInitialSize;
- unsigned char *rasterPoolBase;
-#if defined(Q_WS_WIN64)
- rasterPoolBase =
- // We make use of setjmp and longjmp in qgrayraster.c which requires
- // 16-byte alignment, hence we hardcode this requirement here..
- (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
-#else
- unsigned char rasterPoolOnStack[rasterPoolInitialSize];
- rasterPoolBase = rasterPoolOnStack;
-#endif
- Q_CHECK_PTR(rasterPoolBase);
+ int rasterPoolSize = MINIMUM_POOL_SIZE;
+ uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
+ uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
+ uchar *rasterPoolOnHeap = 0;
qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
// Out of memory, reallocate some more and try again...
if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
- int new_size = rasterPoolSize * 2;
- if (new_size > 1024 * 1024) {
+ rasterPoolSize *= 2;
+ if (rasterPoolSize > 1024 * 1024) {
qWarning("QPainter: Rasterization of primitive failed");
break;
}
rendered_spans += q_gray_rendered_spans(*grayRaster.data());
-#if defined(Q_WS_WIN64)
- _aligned_free(rasterPoolBase);
-#else
- if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
- free(rasterPoolBase);
-#endif
+ free(rasterPoolOnHeap);
+ rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
- rasterPoolSize = new_size;
- rasterPoolBase =
-#if defined(Q_WS_WIN64)
- // We make use of setjmp and longjmp in qgrayraster.c which requires
- // 16-byte alignment, hence we hardcode this requirement here..
- (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
-#else
- (unsigned char *) malloc(rasterPoolSize);
-#endif
- Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
+ Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
+
+ rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
qt_ft_grays_raster.raster_done(*grayRaster.data());
qt_ft_grays_raster.raster_new(grayRaster.data());
}
}
-#if defined(Q_WS_WIN64)
- _aligned_free(rasterPoolBase);
-#else
- if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
- free(rasterPoolBase);
-#endif
+ free(rasterPoolOnHeap);
}
void QRasterPaintEnginePrivate::recalculateFastImages()
memset(m_buffer, val, m_height*bytes_per_line);
}
-
-#if defined(Q_WS_QWS)
-void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
-{
- m_buffer = reinterpret_cast<uchar*>(device->memory());
- m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
- m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
- bytes_per_pixel = device->depth() / 8;
- bytes_per_line = device->bytesPerLine();
- format = device->format();
-#ifndef QT_NO_RASTERCALLBACKS
- if (!m_buffer)
- drawHelper = qDrawHelperCallback + format;
- else
-#endif
- drawHelper = qDrawHelper + format;
-}
-
-int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
-{
- switch (m) {
- case PdmWidth:
- return widget->frameGeometry().width();
- case PdmHeight:
- return widget->frameGeometry().height();
- default:
- break;
- }
-
- return qt_paint_device_metric(widget, m);
-}
-
-int QCustomRasterPaintDevice::bytesPerLine() const
-{
- return (width() * depth() + 7) / 8;
-}
-
-#elif defined(Q_OS_SYMBIAN)
-
-void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
-{
-}
-
-#endif // Q_OS_SYMBIAN
-
-/*!
- \class QCustomRasterPaintDevice
- \preliminary
- \ingroup qws
- \since 4.2
-
- \brief The QCustomRasterPaintDevice class is provided to activate
- hardware accelerated paint engines in Qt for Embedded Linux.
-
- Note that this class is only available in \l{Qt for Embedded Linux}.
-
- In \l{Qt for Embedded Linux}, painting is a pure software
- implementation. But starting with Qt 4.2, it is
- possible to add an accelerated graphics driver to take advantage
- of available hardware resources.
-
- Hardware acceleration is accomplished by creating a custom screen
- driver, accelerating the copying from memory to the screen, and
- implementing a custom paint engine accelerating the various
- painting operations. Then a custom paint device (derived from the
- QCustomRasterPaintDevice class) and a custom window surface
- (derived from QWSWindowSurface) must be implemented to make
- \l{Qt for Embedded Linux} aware of the accelerated driver.
-
- See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
- documentation for details.
-
- \sa QRasterPaintEngine, QPaintDevice
-*/
-
-/*!
- \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
-
- Constructs a custom raster based paint device for the given
- top-level \a widget.
-*/
-
-/*!
- \fn int QCustomRasterPaintDevice::bytesPerLine() const
-
- Returns the number of bytes per line in the framebuffer. Note that
- this number might be larger than the framebuffer width.
-*/
-
-/*!
- \fn int QCustomRasterPaintDevice::devType() const
- \internal
-*/
-
-/*!
- \fn QImage::Format QCustomRasterPaintDevice::format() const
-
- Returns the format of the device's memory buffet.
-
- The default format is QImage::Format_ARGB32_Premultiplied. The
- only other valid format is QImage::Format_RGB16.
-*/
-
-/*!
- \fn void * QCustomRasterPaintDevice::memory () const
-
- Returns a pointer to the paint device's memory buffer, or 0 if no
- such buffer exists.
-*/
-
-/*!
- \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
- \reimp
-*/
-
-/*!
- \fn QSize QCustomRasterPaintDevice::size () const
- \internal
-*/
-
-
QClipData::QClipData(int height)
{
clipSpanHeight = height;
}
break;
- case Qt::UniteClip:
case Qt::ReplaceClip:
clipData->newClip->appendSpans(spans, count);
break;
void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
{
rasterBuffer = rb;
-#ifdef Q_WS_QWS
- rasterEngine = const_cast<QRasterPaintEngine *>(pe);
-#endif
type = None;
txop = 0;
bilinear = false;
unclipped_blend = rasterBuffer->drawHelper->blendGradient;
break;
case Texture:
-#ifdef Q_WS_QWS
-#ifndef QT_NO_RASTERCALLBACKS
- if (!rasterBuffer->buffer())
- unclipped_blend = qBlendTextureCallback;
- else
-#endif
- unclipped_blend = qBlendTexture;
-#else
unclipped_blend = qBlendTexture;
-#endif
if (!texture.imageData)
unclipped_blend = 0;
txop = inv.type();
bilinear = bilin;
- const bool affine = !m13 && !m23;
+ const bool affine = inv.isAffine();
fast_matrix = affine
&& m11 * m11 + m21 * m21 < 1e4
&& m12 * m12 + m22 * m22 < 1e4
adjustSpanMethods();
}
-extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
-
void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
{
const QImageData *d = const_cast<QImage *>(image)->data_ptr();
adjustSpanMethods();
}
-
/*!
- \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
- \overload
+ \internal
+ \a x and \a y is relative to the midpoint of \a rect.
+*/
+static inline void drawEllipsePoints(int x, int y, int length,
+ const QRect &rect,
+ const QRect &clip,
+ ProcessSpans pen_func, ProcessSpans brush_func,
+ QSpanData *pen_data, QSpanData *brush_data)
+{
+ if (length == 0)
+ return;
- Draws the first \a pointCount points in the buffer \a points
+ QT_FT_Span outline[4];
+ const int midx = rect.x() + (rect.width() + 1) / 2;
+ const int midy = rect.y() + (rect.height() + 1) / 2;
+
+ x = x + midx;
+ y = midy - y;
+
+ // topleft
+ outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
+ outline[0].len = qMin(length, x - outline[0].x);
+ outline[0].y = y;
+ outline[0].coverage = 255;
+
+ // topright
+ outline[1].x = x;
+ outline[1].len = length;
+ outline[1].y = y;
+ outline[1].coverage = 255;
+
+ // bottomleft
+ outline[2].x = outline[0].x;
+ outline[2].len = outline[0].len;
+ outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
+ outline[2].coverage = 255;
+
+ // bottomright
+ outline[3].x = x;
+ outline[3].len = length;
+ outline[3].y = outline[2].y;
+ outline[3].coverage = 255;
+
+ if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
+ QT_FT_Span fill[2];
+
+ // top fill
+ fill[0].x = outline[0].x + outline[0].len - 1;
+ fill[0].len = qMax(0, outline[1].x - fill[0].x);
+ fill[0].y = outline[1].y;
+ fill[0].coverage = 255;
+
+ // bottom fill
+ fill[1].x = outline[2].x + outline[2].len - 1;
+ fill[1].len = qMax(0, outline[3].x - fill[1].x);
+ fill[1].y = outline[3].y;
+ fill[1].coverage = 255;
+
+ int n = (fill[0].y >= fill[1].y ? 1 : 2);
+ n = qt_intersect_spans(fill, n, clip);
+ if (n > 0)
+ brush_func(n, fill, brush_data);
+ }
+ if (pen_func) {
+ int n = (outline[1].y >= outline[2].y ? 2 : 4);
+ n = qt_intersect_spans(outline, n, clip);
+ if (n > 0)
+ pen_func(n, outline, pen_data);
+ }
+}
- The default implementation converts the first \a pointCount QPoints in \a points
- to QPointFs and calls the floating point version of drawPoints.
+/*!
+ \internal
+ Draws an ellipse using the integer point midpoint algorithm.
*/
+static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
+ ProcessSpans pen_func, ProcessSpans brush_func,
+ QSpanData *pen_data, QSpanData *brush_data)
+{
+ const qreal a = qreal(rect.width()) / 2;
+ const qreal b = qreal(rect.height()) / 2;
+ qreal d = b*b - (a*a*b) + 0.25*a*a;
+
+ int x = 0;
+ int y = (rect.height() + 1) / 2;
+ int startx = x;
+
+ // region 1
+ while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
+ if (d < 0) { // select E
+ d += b*b*(2*x + 3);
+ ++x;
+ } else { // select SE
+ d += b*b*(2*x + 3) + a*a*(-2*y + 2);
+ drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
+ pen_func, brush_func, pen_data, brush_data);
+ startx = ++x;
+ --y;
+ }
+ }
+ drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
+ pen_func, brush_func, pen_data, brush_data);
+
+ // region 2
+ d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
+ const int miny = rect.height() & 0x1;
+ while (y > miny) {
+ if (d < 0) { // select SE
+ d += b*b*(2*x + 2) + a*a*(-2*y + 3);
+ ++x;
+ } else { // select S
+ d += a*a*(-2*y + 3);
+ }
+ --y;
+ drawEllipsePoints(x, y, 1, rect, clip,
+ pen_func, brush_func, pen_data, brush_data);
+ }
+}
/*!
- \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
+ \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
\overload
-
- Reimplement this function to draw the largest ellipse that can be
- contained within rectangle \a rect.
+ \reimp
*/
+
#ifdef QT_DEBUG_DRAW
void dumpClip(int width, int height, const QClipData *clip)
{