/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
#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_OS_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"
+# include <qt_windows.h>
+#ifdef Q_OS_WIN64
+# include <malloc.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_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_OS_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))
return result == FE_FONTSMOOTHINGCLEARTYPE;
}
+/*!
+ \internal
+ */
bool QRasterPaintEngine::clearTypeFontsEnabled()
{
static const bool result = winClearTypeFontsEnabled();
#endif // Q_OS_WIN
-#ifdef Q_WS_MAC
-extern bool qt_applefontsmoothing_enabled;
-#endif
/********************************************************************************
d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
#if defined(Q_OS_WIN)
else if (clearTypeFontsEnabled())
-#elif defined (Q_WS_MAC)
- else if (qt_applefontsmoothing_enabled)
#else
else if (false)
#endif
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;
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)
}
/*!
+ \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() + 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);
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) {
- d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
+ if (s->brushData.blend)
fillPolygon(points, pointCount, mode);
- d->outlineMapper->setCoordinateRounding(false);
- }
}
// 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->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;
ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
&s->brushData);
d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
- d->outlineMapper->setCoordinateRounding(false);
}
}
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);
}
}
-// 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 {
// 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(),
}
#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.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;
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;
-
- if (neededFormat == QFontEngineFT::Format_None)
- neededFormat = QFontEngineFT::Format_A8;
-
- QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
- if (s->matrix.type() >= QTransform::TxScale) {
- if (s->matrix.isAffine())
- gset = fe->loadTransformedGlyphSet(s->matrix);
- else
- gset = 0;
- }
-
- if (!gset || gset->outline_drawing
- || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
- return false;
+ ? QFontEngine::Format_None
+ : QFontEngine::Format_A8;
- FT_Face lockedFace = 0;
-
- int depth;
- switch (neededFormat) {
- case QFontEngineFT::Format_Mono:
- depth = 1;
- break;
- case QFontEngineFT::Format_A8:
- depth = 8;
- break;
- case QFontEngineFT::Format_A32:
- depth = 32;
- break;
- default:
- Q_ASSERT(false);
- depth = 0;
- };
+ if (d_func()->mono_surface) // alphaPenBlt can handle mono, too
+ neededFormat = QFontEngine::Format_Mono;
for (int i = 0; i < numGlyphs; i++) {
- QFixed spp = fe->subPixelPositionForX(positions[i].x);
- QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
+ 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();
- const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
+ 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 + offs) + c.baseLineX - margin;
- int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
+ int x = qFloor(positions[i].x) + c.baseLineX - 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);
-
- 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() + aliasDelta);
- const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
- 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, 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 (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) {
+ if (!supportsTransformations(fontEngine)) {
drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
fontEngine);
+ } else if (state()->matrix.type() < QTransform::TxProject) {
+ bool invertible;
+ QTransform invMat = state()->matrix.inverted(&invertible);
+ if (!invertible)
+ return;
+
+ QPair<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();
+ ensureRasterState();
-#if defined (Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_QPA)
+ 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;
- }
+ } else if (matrix.type() < QTransform::TxProject) {
+ bool invertible;
+ QTransform invMat = matrix.inverted(&invertible);
+ if (!invertible)
+ return;
-#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_OS_WIN || Q_WS_MAC || Q_WS_QPA
- if (s->matrix.type() <= QTransform::TxTranslate
- || (s->matrix.type() == QTransform::TxScale
- && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
- drawGlyphsS60(p, ti);
- return;
- }
-#else // Q_OS_WIN || Q_WS_MAC || Q_WS_QPA
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
- QFontEngine *fontEngine = ti.fontEngine;
+ 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());
-#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
+ if (range.first >= range.second)
+ return;
- 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());
QPaintEngineEx::drawEllipse(rect);
}
-/*!
- \internal
-*/
-#ifdef Q_WS_MAC
-void QRasterPaintEngine::setCGContext(CGContextRef ctx)
-{
- Q_D(QRasterPaintEngine);
- d->cgContext = ctx;
-}
-
-/*!
- \internal
-*/
-CGContextRef QRasterPaintEngine::getCGContext() const
-{
- Q_D(const QRasterPaintEngine);
- return d->cgContext;
-}
-#endif
#ifdef Q_OS_WIN
/*!
#endif
-bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
+/*!
+ \internal
+*/
+bool QRasterPaintEngine::supportsTransformations(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);
+ return supportsTransformations(fontEngine, m);
}
-bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
+/*!
+ \internal
+*/
+bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, 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
+ if (fontEngine->supportsTransformations(m))
return true;
- return !shouldDrawCachedGlyphs(pixelSize, m);
+ return !shouldDrawCachedGlyphs(fontEngine, m);
}
/*!
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_OS_WIN64)
- rasterPoolBase =
- // We make use of setjmp and longjmp in qgrayraster.c which requires
- // 16-byte alignment, hence we hardcode this requirement here..
- (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
-#else
- unsigned char rasterPoolOnStack[rasterPoolInitialSize];
- rasterPoolBase = rasterPoolOnStack;
-#endif
- Q_CHECK_PTR(rasterPoolBase);
+ int rasterPoolSize = MINIMUM_POOL_SIZE;
+ uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
+ uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
+ uchar *rasterPoolOnHeap = 0;
qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
// Out of memory, reallocate some more and try again...
if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
- int new_size = rasterPoolSize * 2;
- if (new_size > 1024 * 1024) {
+ rasterPoolSize *= 2;
+ if (rasterPoolSize > 1024 * 1024) {
qWarning("QPainter: Rasterization of primitive failed");
break;
}
rendered_spans += q_gray_rendered_spans(*grayRaster.data());
-#if defined(Q_OS_WIN64)
- _aligned_free(rasterPoolBase);
-#else
- if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
- free(rasterPoolBase);
-#endif
+ free(rasterPoolOnHeap);
+ rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
- rasterPoolSize = new_size;
- rasterPoolBase =
-#if defined(Q_OS_WIN64)
- // We make use of setjmp and longjmp in qgrayraster.c which requires
- // 16-byte alignment, hence we hardcode this requirement here..
- (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
-#else
- (unsigned char *) malloc(rasterPoolSize);
-#endif
- Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
+ Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
+
+ rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
qt_ft_grays_raster.raster_done(*grayRaster.data());
qt_ft_grays_raster.raster_new(grayRaster.data());
}
}
-#if defined(Q_OS_WIN64)
- _aligned_free(rasterPoolBase);
-#else
- if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
- free(rasterPoolBase);
-#endif
+ free(rasterPoolOnHeap);
}
void QRasterPaintEnginePrivate::recalculateFastImages()
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();
/*!
\fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
\overload
-
- Draws the first \a pointCount points in the buffer \a points
-
- The default implementation converts the first \a pointCount QPoints in \a points
- to QPointFs and calls the floating point version of drawPoints.
+ \reimp
*/
-/*!
- \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
- \overload
-
- Reimplement this function to draw the largest ellipse that can be
- contained within rectangle \a rect.
-*/
#ifdef QT_DEBUG_DRAW
void dumpClip(int width, int height, const QClipData *clip)