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...
}
ensureRasterState(); // needed because of tx_noshear...
+ bool cosmetic = qt_pen_is_cosmetic(pen, s->renderHints);
s->flags.fast_pen = pen_style > Qt::NoPen
&& s->penData.blend
- && ((pen.isCosmetic() && penWidth <= 1)
- || (!pen.isCosmetic() && s->flags.tx_noshear && penWidth * s->txscale <= 1));
+ && ((cosmetic && penWidth <= 1)
+ || (!cosmetic && s->flags.tx_noshear && penWidth * s->txscale <= 1));
s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
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;
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)
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);
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() + aliasedCoordinateDelta);
- int y1 = qRound(rect.y() + aliasedCoordinateDelta);
- int x2 = qRound(rect.right() + aliasedCoordinateDelta);
- int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
+ QRasterPaintEngineState *s = state();
+
+ qreal delta = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
+
+ int x1 = qRound(rect.x() + delta);
+ int y1 = qRound(rect.y() + delta);
+ int x2 = qRound(rect.right() + delta);
+ int y2 = qRound(rect.bottom() + delta);
if (x2 < x1)
qSwap(x1, x2);
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->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
QPaintEngineEx::stroke(vp, s->lastPen);
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 {
// as fillRect will apply the aliased coordinate delta we need to
// subtract it here as we don't use it for image drawing
QTransform old = s->matrix;
- s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
+
+ if (s->flags.legacy_rounding)
+ s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
// Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
QRgb color = img.pixel(sr_l, sr_t);
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(),
if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
+ d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
- const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
+ const QPointF offs = s->flags.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF();
const QRectF &rect = r.normalized();
const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
return;
}
#endif
- const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
+ const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
QPainterPath path;
path.addRect(r);
QTransform m = s->matrix;
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);
alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(),
qFloor(positions[i].x) + offset.x(),
- qFloor(positions[i].y) + offset.y(),
+ qRound(positions[i].y) + offset.y(),
alphaMap->width(), alphaMap->height());
fontEngine->unlockAlphaMapForGlyph();
rightShift = 3; // divide by 8
int margin = fontEngine->glyphMargin(glyphType);
- const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
continue;
int x = qFloor(positions[i].x) + c.baseLineX - margin;
- int y = qFloor(positions[i].y + offs) - 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,
ensureRasterState();
QFontEngine *fontEngine = textItem->fontEngine();
- if (shouldDrawCachedGlyphs(fontEngine, state()->matrix)) {
+ if (!supportsTransformations(fontEngine)) {
drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
fontEngine);
} else if (state()->matrix.type() < QTransform::TxProject) {
}
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());
*/
bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const
{
- if (m.type() >= QTransform::TxProject)
+ if (fontEngine->supportsTransformations(m))
return true;
return !shouldDrawCachedGlyphs(fontEngine, m);
QRasterPaintEngineState *s = q->state();
rasterizer->setAntialiased(s->flags.antialiased);
+ rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
QRect clipRect(deviceRect);
ProcessSpans blend;
if (!s->flags.antialiased) {
rasterizer->setAntialiased(s->flags.antialiased);
+ rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
rasterizer->setClipRect(deviceRect);
rasterizer->initialize(callback, userData);
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