diff options
Diffstat (limited to 'src/gui')
41 files changed, 1711 insertions, 105 deletions
diff --git a/src/gui/dialogs/qprintdialog_qws.cpp b/src/gui/dialogs/qprintdialog_qws.cpp index 6b531a2..1336c04 100644 --- a/src/gui/dialogs/qprintdialog_qws.cpp +++ b/src/gui/dialogs/qprintdialog_qws.cpp @@ -163,7 +163,7 @@ void QPrintDialogPrivate::_q_okClicked() printer->setPaperSize(pageSize); printer->setPageOrder(pageOrder2); printer->setColorMode(colorMode2); - printer->setNumCopies(numCopies); + printer->setCopyCount(numCopies); switch ((rangeCombo->itemData(rangeCombo->currentIndex())).toInt()){ case (int)QPrintDialog::AllPages: @@ -479,8 +479,8 @@ void QPrintDialogPrivate::setPrinter(QPrinter *p, bool pickUpSettings) printGray->setChecked(true); // number of copies - copies->setValue(p->numCopies()); - _q_setNumCopies(p->numCopies()); + copies->setValue(p->copyCount()); + _q_setNumCopies(p->copyCount()); } if (p) { diff --git a/src/gui/dialogs/qprintdialog_unix.cpp b/src/gui/dialogs/qprintdialog_unix.cpp index 23f5831..2d169cf 100644 --- a/src/gui/dialogs/qprintdialog_unix.cpp +++ b/src/gui/dialogs/qprintdialog_unix.cpp @@ -72,8 +72,6 @@ QT_BEGIN_NAMESPACE -extern int qt_printerRealNumCopies(QPaintEngine *); - class QOptionTreeItem; class QPPDOptionsModel; @@ -439,7 +437,7 @@ void QPrintDialogPrivate::applyPrinterProperties(QPrinter *p) case QPrinter::DuplexShortSide: options.duplexShort->setChecked(true); break; } - options.copies->setValue(qt_printerRealNumCopies(p->paintEngine())); + options.copies->setValue(p->copyCount()); options.collate->setChecked(p->collateCopies()); options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst); top->d->applyPrinterProperties(p); @@ -510,7 +508,7 @@ void QPrintDialogPrivate::setupPrinter() } // copies - p->setNumCopies(options.copies->value()); + p->setCopyCount(options.copies->value()); p->setCollateCopies(options.collate->isChecked()); top->d->setupPrinter(); diff --git a/src/gui/embedded/directfb.pri b/src/gui/embedded/directfb.pri index bd1d947..d6d77b4 100644 --- a/src/gui/embedded/directfb.pri +++ b/src/gui/embedded/directfb.pri @@ -15,7 +15,7 @@ #DEFINES += QT_DIRECTFB_TIMING #DEFINES += QT_NO_DIRECTFB_OPAQUE_DETECTION #DEFINES += QT_NO_DIRECTFB_STRETCHBLIT -#DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT +#DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT|DRAW_STATICTEXT #DEFINES += \"QT_DIRECTFB_WARN_ON_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\" #DEFINES += \"QT_DIRECTFB_DISABLE_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\" diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index dd0c047..ca20101 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3178,8 +3178,9 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim */ void QGraphicsItem::clearFocus() { - // Pass focus to the closest parent focus scope. - if (!d_ptr->inDestructor) { + // Pass focus to the closest parent focus scope when clearing focus + // from a focus scope. + if (!d_ptr->inDestructor && (d_ptr->flags & ItemIsFocusScope)) { QGraphicsItem *p = d_ptr->parent; while (p) { if (p->flags() & ItemIsFocusScope) { diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index b67be55..8d75fdd 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -96,6 +96,7 @@ SOURCES += \ unix:LIBS_PRIVATE += -lpng win32:LIBS += libpng.lib } else { + DEFINES *= QT_USE_BUNDLED_LIBPNG !isEqual(QT_ARCH, i386):!isEqual(QT_ARCH, x86_64):DEFINES += PNG_NO_ASSEMBLER_CODE INCLUDEPATH += ../3rdparty/libpng ../3rdparty/zlib SOURCES += ../3rdparty/libpng/png.c \ @@ -112,8 +113,7 @@ SOURCES += \ ../3rdparty/libpng/pngwio.c \ ../3rdparty/libpng/pngwrite.c \ ../3rdparty/libpng/pngwtran.c \ - ../3rdparty/libpng/pngwutil.c \ - ../3rdparty/libpng/pnggccrd.c + ../3rdparty/libpng/pngwutil.c } } else { DEFINES *= QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 336be91..4ec2ae2 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -122,15 +122,19 @@ extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp static void initResources() { #if defined(Q_WS_WINCE) + Q_INIT_RESOURCE_EXTERN(qstyle_wince) Q_INIT_RESOURCE(qstyle_wince); #elif defined(Q_OS_SYMBIAN) + Q_INIT_RESOURCE_EXTERN(qstyle_s60) Q_INIT_RESOURCE(qstyle_s60); #else + Q_INIT_RESOURCE_EXTERN(qstyle) Q_INIT_RESOURCE(qstyle); #endif - + Q_INIT_RESOURCE_EXTERN(qmessagebox) Q_INIT_RESOURCE(qmessagebox); #if !defined(QT_NO_PRINTDIALOG) + Q_INIT_RESOURCE_EXTERN(qprintdialog) Q_INIT_RESOURCE(qprintdialog); #endif diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index bbffda1..ea7fe4f 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -112,6 +112,11 @@ QPolygonF QBezier::toPolygon() const return polygon; } +QBezier QBezier::mapBy(const QTransform &transform) const +{ + return QBezier::fromPoints(transform.map(pt1()), transform.map(pt2()), transform.map(pt3()), transform.map(pt4())); +} + //0.5 is really low static const qreal flatness = 0.5; @@ -140,6 +145,25 @@ static inline void flattenBezierWithoutInflections(QBezier &bez, } } +QBezier QBezier::getSubRange(qreal t0, qreal t1) const +{ + QBezier result; + QBezier temp; + + // cut at t1 + if (qFuzzyIsNull(t1 - qreal(1.))) { + result = *this; + } else { + temp = *this; + temp.parameterSplitLeft(t1, &result); + } + + // cut at t0 + if (!qFuzzyIsNull(t0)) + result.parameterSplitLeft(t0 / t1, &temp); + + return result; +} static inline int quadraticRoots(qreal a, qreal b, qreal c, qreal *x1, qreal *x2) @@ -1018,13 +1042,19 @@ int QBezier::stationaryYPoints(qreal &t0, qreal &t1) const const qreal b = 2 * y1 - 4 * y2 + 2 * y3; const qreal c = -y1 + y2; - qreal reciprocal = b * b - 4 * a * c; + if (qFuzzyIsNull(a)) { + if (qFuzzyIsNull(b)) + return 0; - QList<qreal> result; + t0 = -c / b; + return t0 > 0 && t0 < 1; + } + + qreal reciprocal = b * b - 4 * a * c; if (qFuzzyIsNull(reciprocal)) { t0 = -b / (2 * a); - return 1; + return t0 > 0 && t0 < 1; } else if (reciprocal > 0) { qreal temp = qSqrt(reciprocal); diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 3409bc7..f015ea8 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -59,6 +59,7 @@ #include "QtCore/qvector.h" #include "QtCore/qlist.h" #include "QtCore/qpair.h" +#include "QtGui/qtransform.h" QT_BEGIN_NAMESPACE @@ -96,6 +97,8 @@ public: QPointF pt3() const { return QPointF(x3, y3); } QPointF pt4() const { return QPointF(x4, y4); } + QBezier mapBy(const QTransform &transform) const; + inline QPointF midPoint() const; inline QLineF midTangent() const; @@ -104,6 +107,7 @@ public: inline void parameterSplitLeft(qreal t, QBezier *left); inline void split(QBezier *firstHalf, QBezier *secondHalf) const; + int shifted(QBezier *curveSegments, int maxSegmets, qreal offset, float threshold) const; @@ -117,6 +121,8 @@ public: static bool findIntersections(const QBezier &a, const QBezier &b, QVector<QPair<qreal, qreal> > *t); + QBezier getSubRange(qreal t0, qreal t1) const; + qreal x1, y1, x2, y2, x3, y3, x4, y4; }; diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp index fd42736..0510b10 100644 --- a/src/gui/painting/qemulationpaintengine.cpp +++ b/src/gui/painting/qemulationpaintengine.cpp @@ -205,6 +205,11 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text real_engine->drawTextItem(p, textItem); } +void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item) +{ + real_engine->drawStaticTextItem(item); +} + void QEmulationPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) { if (state()->bgMode == Qt::OpaqueMode && pixmap.isQBitmap()) diff --git a/src/gui/painting/qemulationpaintengine_p.h b/src/gui/painting/qemulationpaintengine_p.h index 0ed641b..5835f10 100644 --- a/src/gui/painting/qemulationpaintengine_p.h +++ b/src/gui/painting/qemulationpaintengine_p.h @@ -78,6 +78,7 @@ public: virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void drawStaticTextItem(QStaticTextItem *item); virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags); diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 2344c04..39b76c8 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -45,6 +45,8 @@ #include <private/qfontengine_p.h> #include <private/qemulationpaintengine_p.h> #include <private/qimage_p.h> +#include <qstatictext.h> +#include <private/qstatictext_p.h> #include <QDebug> @@ -306,6 +308,8 @@ public: Q_Q(QPaintBufferEngine); q->buffer->addCommand(QPaintBufferPrivate::Cmd_SystemStateChanged, QVariant(systemClip)); } + + QTransform last; }; @@ -492,6 +496,32 @@ void QPaintBufferEngine::renderHintsChanged() void QPaintBufferEngine::transformChanged() { + Q_D(QPaintBufferEngine); + const QTransform &transform = state()->matrix; + + QTransform delta; + + bool invertible = false; + if (transform.type() <= QTransform::TxScale && transform.type() == d->last.type()) + delta = transform * d->last.inverted(&invertible); + + d->last = transform; + + if (invertible && delta.type() == QTransform::TxNone) + return; + + if (invertible && delta.type() == QTransform::TxTranslate) { +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBufferEngine: transformChanged (translate only) " << state()->matrix; +#endif + QPaintBufferCommand *cmd = + buffer->addCommand(QPaintBufferPrivate::Cmd_Translate); + + qreal data[] = { delta.dx(), delta.dy() }; + cmd->extra = buffer->addData((qreal *) data, 2); + return; + } + // ### accumulate, like in QBrush case... if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetTransform) { @@ -960,6 +990,18 @@ void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con buffer->updateBoundingRect(r); } +void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) +{ + QString text = QString(staticTextItem->chars, staticTextItem->numChars); + + QStaticText staticText(text); + staticText.prepare(state()->matrix, staticTextItem->font); + + QVariantList variants; + variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText); + buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants)); +} + void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) { #ifdef QPAINTBUFFER_DEBUG_DRAW @@ -999,6 +1041,7 @@ void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) void QPaintBufferEngine::setState(QPainterState *s) { + Q_D(QPaintBufferEngine); if (m_begin_detected) { #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: setState: begin, ignoring."; @@ -1017,6 +1060,8 @@ void QPaintBufferEngine::setState(QPainterState *s) buffer->addCommand(QPaintBufferPrivate::Cmd_Restore); } + d->last = s->matrix; + QPaintEngineEx::setState(s); } @@ -1138,6 +1183,15 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) painter->setTransform(xform * m_world_matrix); break; } + case QPaintBufferPrivate::Cmd_Translate: { + QPointF delta(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << " -> Cmd_Translate, offset: " << cmd.offset << delta; +#endif + painter->translate(delta.x(), delta.y()); + return; + } + case QPaintBufferPrivate::Cmd_SetCompositionMode: { QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra; #ifdef QPAINTBUFFER_DEBUG_DRAW @@ -1425,6 +1479,19 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) #endif painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } + + case QPaintBufferPrivate::Cmd_DrawStaticText: { + + QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>()); + + QFont font(variants.at(0).value<QFont>()); + QStaticText text(variants.at(0).value<QStaticText>()); + + painter->setFont(font); + painter->drawStaticText(QPointF(0, 0), text); + + break; + } case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); @@ -1770,8 +1837,28 @@ struct QPaintBufferCacheEntry QVariant::Type type; quint64 cacheKey; }; + +struct QPaintBufferCacheEntryV2 +{ + enum Type { + ImageKey, + PixmapKey + }; + + struct Flags { + uint type : 8; + uint key : 24; + }; + + union { + Flags flags; + uint bits; + }; +}; + QT_END_NAMESPACE Q_DECLARE_METATYPE(QPaintBufferCacheEntry) +Q_DECLARE_METATYPE(QPaintBufferCacheEntryV2) QT_BEGIN_NAMESPACE QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntry &entry) @@ -1784,10 +1871,22 @@ QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntry &entry) return stream >> entry.type >> entry.cacheKey; } +QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntryV2 &entry) +{ + return stream << entry.bits; +} + +QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntryV2 &entry) +{ + return stream >> entry.bits; +} + static int qRegisterPaintBufferMetaTypes() { qRegisterMetaType<QPaintBufferCacheEntry>(); qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntry>("QPaintBufferCacheEntry"); + qRegisterMetaType<QPaintBufferCacheEntryV2>(); + qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntryV2>("QPaintBufferCacheEntryV2"); return 0; // something } @@ -1796,6 +1895,9 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterPaintBufferMetaTypes) QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer) { + QHash<qint64, uint> pixmapKeys; + QHash<qint64, uint> imageKeys; + QHash<qint64, QPixmap> pixmaps; QHash<qint64, QImage> images; @@ -1804,19 +1906,33 @@ QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer) const QVariant &v = variants.at(i); if (v.type() == QVariant::Image) { const QImage image(v.value<QImage>()); - images[image.cacheKey()] = image; - QPaintBufferCacheEntry entry; - entry.type = QVariant::Image; - entry.cacheKey = image.cacheKey(); + QPaintBufferCacheEntryV2 entry; + entry.flags.type = QPaintBufferCacheEntryV2::ImageKey; + + QHash<qint64, uint>::iterator it = imageKeys.find(image.cacheKey()); + if (it != imageKeys.end()) { + entry.flags.key = *it; + } else { + imageKeys[image.cacheKey()] = entry.flags.key = images.size(); + images[images.size()] = image; + } + variants[i] = QVariant::fromValue(entry); } else if (v.type() == QVariant::Pixmap) { const QPixmap pixmap(v.value<QPixmap>()); - pixmaps[pixmap.cacheKey()] = pixmap; - QPaintBufferCacheEntry entry; - entry.type = QVariant::Pixmap; - entry.cacheKey = pixmap.cacheKey(); + QPaintBufferCacheEntryV2 entry; + entry.flags.type = QPaintBufferCacheEntryV2::PixmapKey; + + QHash<qint64, uint>::iterator it = pixmapKeys.find(pixmap.cacheKey()); + if (it != pixmapKeys.end()) { + entry.flags.key = *it; + } else { + pixmapKeys[pixmap.cacheKey()] = entry.flags.key = pixmaps.size(); + pixmaps[pixmaps.size()] = pixmap; + } + variants[i] = QVariant::fromValue(entry); } } @@ -1858,6 +1974,15 @@ QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer) variants[i] = QVariant(images.value(entry.cacheKey)); else variants[i] = QVariant(pixmaps.value(entry.cacheKey)); + } else if (v.canConvert<QPaintBufferCacheEntryV2>()) { + QPaintBufferCacheEntryV2 entry = v.value<QPaintBufferCacheEntryV2>(); + + if (entry.flags.type == QPaintBufferCacheEntryV2::ImageKey) + variants[i] = QVariant(images.value(entry.flags.key)); + else if (entry.flags.type == QPaintBufferCacheEntryV2::PixmapKey) + variants[i] = QVariant(pixmaps.value(entry.flags.key)); + else + qWarning() << "operator<<(QDataStream &stream, QPaintBuffer &buffer): unrecognized cache entry type:" << entry.flags.type; } } diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h index 79d7b35..0fde290 100644 --- a/src/gui/painting/qpaintbuffer_p.h +++ b/src/gui/painting/qpaintbuffer_p.h @@ -183,6 +183,10 @@ public: Cmd_DrawTiledPixmap, Cmd_SystemStateChanged, + Cmd_Translate, + Cmd_DrawStaticText, + + // new commands must be added above this line Cmd_LastCommand }; @@ -394,6 +398,7 @@ public: virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); virtual void drawTextItem(const QPointF &pos, const QTextItem &ti); + virtual void drawStaticTextItem(QStaticTextItem *staticTextItem); virtual void setState(QPainterState *s); virtual uint flags() const {return QPaintEngineEx::DoNotEmulate;} diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 3c2cc8c..60265c5 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -67,6 +67,7 @@ // #include <private/qpolygonclipper_p.h> // #include <private/qrasterizer_p.h> #include <private/qimage_p.h> +#include <private/qstatictext_p.h> #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" @@ -3002,27 +3003,22 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx blend(current, spans, &s->penData); } -void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti) +void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *positions, QFontEngine *fontEngine) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - 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); - - QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType; + QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; QImageTextureGlyphCache *cache = - (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(0, glyphType, s->matrix); + static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix)); if (!cache) { cache = new QImageTextureGlyphCache(glyphType, s->matrix); - ti.fontEngine->setGlyphCache(0, cache); + fontEngine->setGlyphCache(0, cache); } - cache->populate(ti, glyphs, positions); + cache->populate(fontEngine, numGlyphs, glyphs, positions); const QImage &image = cache->image(); int bpl = image.bytesPerLine(); @@ -3040,7 +3036,7 @@ void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt & const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); - for (int i=0; i<glyphs.size(); ++i) { + for (int i=0; i<numGlyphs; ++i) { const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]); int x = qFloor(positions[i].x + offs) + c.baseLineX - margin; int y = qFloor(positions[i].y + offs) - c.baseLineY - margin; @@ -3217,6 +3213,15 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; } +void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) +{ + ensurePen(); + ensureState(); + + drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, + textItem->fontEngine); +} + /*! \reimp */ @@ -3265,7 +3270,17 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte drawCached = false; #endif if (drawCached) { - drawCachedGlyphs(p, ti); + QRasterPaintEngineState *s = state(); + + 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; } diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index a1c73cc..55eb82e 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -203,6 +203,8 @@ public: void clip(const QRect &rect, Qt::ClipOperation op); void clip(const QRegion ®ion, Qt::ClipOperation op); + void drawStaticTextItem(QStaticTextItem *textItem); + enum ClipType { RectClip, ComplexClip @@ -257,7 +259,8 @@ private: void fillRect(const QRectF &rect, QSpanData *data); void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); - void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti); + void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, + QFontEngine *fontEngine); #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti); diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index fccd1dc..90c4f9f 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -70,6 +70,7 @@ QT_MODULE(Gui) class QPainterState; class QPaintEngineExPrivate; +class QStaticTextItem; struct StrokeHandler; struct QIntRect { @@ -200,6 +201,8 @@ public: virtual void updateState(const QPaintEngineState &state); + virtual void drawStaticTextItem(QStaticTextItem *) = 0; + virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast<QPainterState *>(QPaintEngine::state); } inline const QPainterState *state() const { return static_cast<const QPainterState *>(QPaintEngine::state); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 075c457..e69512d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -69,6 +69,8 @@ #include <private/qwidget_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qmath_p.h> +#include <qstatictext.h> +#include <private/qstatictext_p.h> QT_BEGIN_NAMESPACE @@ -5698,6 +5700,23 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR } /*! + + \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) + + \since 4.7 + + \overload +*/ + +/*! + \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) + + \since 4.7 + + \overload +*/ + +/*! \fn void QPainter::drawText(const QPointF &position, const QString &text) Draws the given \a text with the currently defined text direction, @@ -5720,6 +5739,124 @@ void QPainter::drawText(const QPointF &p, const QString &str) } /*! + \since 4.7 + + Draws the given \a staticText at the given \a position. + + The text will be drawn using the font and the transformation set on the painter. If the + font and/or transformation set on the painter are different from the ones used to initialize + the layout of the QStaticText, then the layout will have to be recalculated. Use + QStaticText::prepare() to initialize \a staticText with the font and transformation with which + it will later be drawn. + + If \a position is not the same as when \a staticText was initialized, or when it was last drawn, + then there will be a slight overhead when translating the text to its new position. + + \note If the painter's transformation is not affine, then \a staticText will be drawn using regular + calls to drawText(), losing any potential performance improvement. + + \sa QStaticText +*/ +void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) +{ + Q_D(QPainter); + if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen) + return; + + QStaticTextPrivate *staticText_d = + const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText)); + + // If we don't have an extended paint engine, or if the painter is projected, + // we go through standard code path + if (d->extended == 0 || !d->state->matrix.isAffine()) { + staticText_d->paintText(position, this); + return; + } + + // Don't recalculate entire layout because of translation, rather add the dx and dy + // into the position to move each text item the correct distance. + QPointF transformedPosition = position * d->state->matrix; + QTransform matrix = d->state->matrix; + + // The translation has been applied to transformedPosition. Remove translation + // component from matrix. + if (d->state->matrix.isTranslating()) { + qreal m11 = d->state->matrix.m11(); + qreal m12 = d->state->matrix.m12(); + qreal m13 = d->state->matrix.m13(); + qreal m21 = d->state->matrix.m21(); + qreal m22 = d->state->matrix.m22(); + qreal m23 = d->state->matrix.m23(); + qreal m33 = d->state->matrix.m33(); + + d->state->matrix.setMatrix(m11, m12, m13, + m21, m22, m23, + 0.0, 0.0, m33); + } + + // If the transform is not identical to the text transform, + // we have to relayout the text (for other transformations than plain translation) + bool staticTextNeedsReinit = false; + if (staticText_d->matrix != d->state->matrix) { + staticText_d->matrix = d->state->matrix; + staticTextNeedsReinit = true; + } + + bool restoreWhenFinished = false; + if (staticText_d->needsClipRect) { + save(); + setClipRect(QRectF(position, staticText_d->maximumSize)); + + restoreWhenFinished = true; + } + + if (font() != staticText_d->font) { + staticText_d->font = font(); + staticTextNeedsReinit = true; + } + + // Recreate the layout of the static text because the matrix or font has changed + if (staticTextNeedsReinit) + staticText_d->init(); + + if (transformedPosition != staticText_d->position) { // Translate to actual position + QFixed fx = QFixed::fromReal(transformedPosition.x()); + QFixed fy = QFixed::fromReal(transformedPosition.y()); + QFixed oldX = QFixed::fromReal(staticText_d->position.x()); + QFixed oldY = QFixed::fromReal(staticText_d->position.y()); + for (int item=0; item<staticText_d->itemCount;++item) { + QStaticTextItem *textItem = staticText_d->items + item; + for (int i=0; i<textItem->numGlyphs; ++i) { + textItem->glyphPositions[i].x += fx - oldX; + textItem->glyphPositions[i].y += fy - oldY; + } + textItem->userDataNeedsUpdate = true; + } + + staticText_d->position = transformedPosition; + } + + QPen oldPen = d->state->pen; + QColor currentColor = oldPen.color(); + for (int i=0; i<staticText_d->itemCount; ++i) { + QStaticTextItem *item = staticText_d->items + i; + if (currentColor != item->color) { + setPen(item->color); + currentColor = item->color; + } + d->extended->drawStaticTextItem(item); + } + if (currentColor != oldPen.color()) + setPen(oldPen); + + if (restoreWhenFinished) + restore(); + + if (matrix.isTranslating()) + d->state->matrix = matrix; +} + +/*! \internal */ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding) diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index ffddcba..e9fd532 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -78,6 +78,7 @@ class QPolygon; class QTextItem; class QMatrix; class QTransform; +class QStaticText; class QPainterPrivateDeleter; @@ -369,6 +370,10 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; + void drawStaticText(const QPointF &p, const QStaticText &staticText); + inline void drawStaticText(const QPoint &p, const QStaticText &staticText); + inline void drawStaticText(int x, int y, const QStaticText &staticText); + void drawText(const QPointF &p, const QString &s); inline void drawText(const QPoint &p, const QString &s); inline void drawText(int x, int y, const QString &s); @@ -896,6 +901,16 @@ inline void QPainter::drawImage(int x, int y, const QImage &image, int sx, int s drawImage(QRectF(x, y, -1, -1), image, QRectF(sx, sy, sw, sh), flags); } +inline void QPainter::drawStaticText(const QPoint &p, const QStaticText &staticText) +{ + drawStaticText(QPointF(p), staticText); +} + +inline void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) +{ + drawStaticText(QPointF(x, y), staticText); +} + inline void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti) { drawTextItem(QPointF(p), ti); diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp index bc81514..949a820 100644 --- a/src/gui/painting/qpathclipper.cpp +++ b/src/gui/painting/qpathclipper.cpp @@ -1705,6 +1705,9 @@ QPainterPath QPathClipper::clip(Operation operation) if (subjectPath == clipPath) return op == BoolSub ? QPainterPath() : subjectPath; + bool subjectIsRect = pathToRect(subjectPath, 0); + bool clipIsRect = pathToRect(clipPath, 0); + const QRectF clipBounds = clipPath.boundingRect(); const QRectF subjectBounds = subjectPath.boundingRect(); @@ -1732,8 +1735,7 @@ QPainterPath QPathClipper::clip(Operation operation) } if (clipBounds.contains(subjectBounds)) { - QRectF clipRect; - if (pathToRect(clipPath, &clipRect) && clipRect.contains(subjectBounds)) { + if (clipIsRect) { switch (op) { case BoolSub: return QPainterPath(); @@ -1746,17 +1748,16 @@ QPainterPath QPathClipper::clip(Operation operation) } } } else if (subjectBounds.contains(clipBounds)) { - QRectF subjectRect; - if (pathToRect(subjectPath, &subjectRect) && subjectRect.contains(clipBounds)) { + if (subjectIsRect) { switch (op) { case BoolSub: if (clipPath.fillRule() == Qt::OddEvenFill) { QPainterPath result = clipPath; - result.addRect(subjectRect); + result.addRect(subjectBounds); return result; } else { QPainterPath result = clipPath.simplified(); - result.addRect(subjectRect); + result.addRect(subjectBounds); return result; } break; @@ -1769,6 +1770,13 @@ QPainterPath QPathClipper::clip(Operation operation) } } } + + if (op == BoolAnd) { + if (subjectIsRect) + return intersect(clipPath, subjectBounds); + else if (clipIsRect) + return intersect(subjectPath, clipBounds); + } } QWingedEdge list(subjectPath, clipPath); @@ -2052,4 +2060,243 @@ bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode m return false; } +namespace { + +QList<QPainterPath> toSubpaths(const QPainterPath &path) +{ + + QList<QPainterPath> subpaths; + if (path.isEmpty()) + return subpaths; + + QPainterPath current; + for (int i = 0; i < path.elementCount(); ++i) { + const QPainterPath::Element &e = path.elementAt(i); + switch (e.type) { + case QPainterPath::MoveToElement: + if (current.elementCount() > 1) + subpaths += current; + current = QPainterPath(); + current.moveTo(e); + break; + case QPainterPath::LineToElement: + current.lineTo(e); + break; + case QPainterPath::CurveToElement: { + current.cubicTo(e, path.elementAt(i + 1), path.elementAt(i + 2)); + i+=2; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(!"toSubpaths(), bad element type"); + break; + } + } + + if (current.elementCount() > 1) + subpaths << current; + + return subpaths; +} + +enum Edge +{ + Left, Top, Right, Bottom +}; + +static bool isVertical(Edge edge) +{ + return edge == Left || edge == Right; +} + +template <Edge edge> +bool compare(const QPointF &p, qreal t) +{ + switch (edge) + { + case Left: + return p.x() < t; + case Right: + return p.x() > t; + case Top: + return p.y() < t; + default: + return p.y() > t; + } +} + +template <Edge edge> +QPointF intersectLine(const QPointF &a, const QPointF &b, qreal t) +{ + QLineF line(a, b); + switch (edge) { + case Left: // fall-through + case Right: + return line.pointAt((t - a.x()) / (b.x() - a.x())); + default: + return line.pointAt((t - a.y()) / (b.y() - a.y())); + } +} + +void addLine(QPainterPath &path, const QLineF &line) +{ + if (path.elementCount() > 0) + path.lineTo(line.p1()); + else + path.moveTo(line.p1()); + + path.lineTo(line.p2()); +} + +template <Edge edge> +void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result) +{ + bool outA = compare<edge>(a, t); + bool outB = compare<edge>(b, t); + if (outA && outB) + return; + + if (outA) + addLine(result, QLineF(intersectLine<edge>(a, b, t), b)); + else if(outB) + addLine(result, QLineF(a, intersectLine<edge>(a, b, t))); + else + addLine(result, QLineF(a, b)); +} + +void addBezier(QPainterPath &path, const QBezier &bezier) +{ + if (path.elementCount() > 0) + path.lineTo(bezier.pt1()); + else + path.moveTo(bezier.pt1()); + + path.cubicTo(bezier.pt2(), bezier.pt3(), bezier.pt4()); +} + +template <Edge edge> +void clipBezier(const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, qreal t, QPainterPath &result) +{ + QBezier bezier = QBezier::fromPoints(a, b, c, d); + + bool outA = compare<edge>(a, t); + bool outB = compare<edge>(b, t); + bool outC = compare<edge>(c, t); + bool outD = compare<edge>(d, t); + + int outCount = int(outA) + int(outB) + int(outC) + int(outD); + + if (outCount == 4) + return; + + if (outCount == 0) { + addBezier(result, bezier); + return; + } + + QTransform flip = isVertical(edge) ? QTransform(0, 1, 1, 0, 0, 0) : QTransform(); + QBezier unflipped = bezier; + QBezier flipped = bezier.mapBy(flip); + + qreal t0 = 0, t1 = 1; + int stationary = flipped.stationaryYPoints(t0, t1); + + qreal segments[4]; + QPointF points[4]; + points[0] = unflipped.pt1(); + segments[0] = 0; + + int segmentCount = 0; + if (stationary > 0) { + ++segmentCount; + segments[segmentCount] = t0; + points[segmentCount] = unflipped.pointAt(t0); + } + if (stationary > 1) { + ++segmentCount; + segments[segmentCount] = t1; + points[segmentCount] = unflipped.pointAt(t1); + } + ++segmentCount; + segments[segmentCount] = 1; + points[segmentCount] = unflipped.pt4(); + + qreal lastIntersection = 0; + for (int i = 0; i < segmentCount; ++i) { + outA = compare<edge>(points[i], t); + outB = compare<edge>(points[i+1], t); + + if (outA != outB) { + qreal intersection = flipped.tForY(segments[i], segments[i+1], t); + + if (outB) + addBezier(result, unflipped.getSubRange(lastIntersection, intersection)); + + lastIntersection = intersection; + } + } + + if (!outB) + addBezier(result, unflipped.getSubRange(lastIntersection, 1)); +} + +// clips a single subpath against a single edge +template <Edge edge> +QPainterPath clip(const QPainterPath &path, qreal t) +{ + QPainterPath result; + for (int i = 1; i < path.elementCount(); ++i) { + const QPainterPath::Element &element = path.elementAt(i); + Q_ASSERT(!element.isMoveTo()); + if (element.isLineTo()) { + clipLine<edge>(path.elementAt(i-1), path.elementAt(i), t, result); + } else { + clipBezier<edge>(path.elementAt(i-1), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), t, result); + i += 2; + } + } + + int last = path.elementCount() - 1; + if (QPointF(path.elementAt(last)) != QPointF(path.elementAt(0))) + clipLine<edge>(path.elementAt(last), path.elementAt(0), t, result); + + return result; +} + +QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect) +{ + QList<QPainterPath> subpaths = toSubpaths(path); + + QPainterPath result; + result.setFillRule(path.fillRule()); + for (int i = 0; i < subpaths.size(); ++i) { + QPainterPath subPath = subpaths.at(i); + QRectF bounds = subPath.boundingRect(); + if (bounds.intersects(rect)) { + if (bounds.left() < rect.left()) + subPath = clip<Left>(subPath, rect.left()); + if (bounds.right() > rect.right()) + subPath = clip<Right>(subPath, rect.right()); + + bounds = subPath.boundingRect(); + + if (bounds.top() < rect.top()) + subPath = clip<Top>(subPath, rect.top()); + if (bounds.bottom() > rect.bottom()) + subPath = clip<Bottom>(subPath, rect.bottom()); + + if (subPath.elementCount() > 1) + result.addPath(subPath); + } + } + return result; +} + +} + +QPainterPath QPathClipper::intersect(const QPainterPath &path, const QRectF &rect) +{ + return intersectPath(path, rect); +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h index b900862..b42dc1d 100644 --- a/src/gui/painting/qpathclipper_p.h +++ b/src/gui/painting/qpathclipper_p.h @@ -87,6 +87,7 @@ public: bool contains(); static bool pathToRect(const QPainterPath &path, QRectF *rect = 0); + static QPainterPath intersect(const QPainterPath &path, const QRectF &rect); private: Q_DISABLE_COPY(QPathClipper) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index dd516b1..dcf745f 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -1415,6 +1415,7 @@ void QPdfBaseEngine::setProperty(PrintEnginePropertyKey key, const QVariant &val case PPK_FullPage: d->fullPage = value.toBool(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: d->copies = value.toInt(); break; @@ -1504,6 +1505,17 @@ QVariant QPdfBaseEngine::property(PrintEnginePropertyKey key) const case PPK_FullPage: ret = d->fullPage; break; + case PPK_CopyCount: + ret = d->copies; + break; + case PPK_SupportsMultipleCopies: +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + if (QCUPSSupport::isAvailable()) + ret = true; + else +#endif + ret = false; + break; case PPK_NumberOfCopies: #if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) if (QCUPSSupport::isAvailable()) diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index f79c5cc..9c4d05d 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -216,8 +216,6 @@ public: private: void updateClipPath(const QPainterPath & path, Qt::ClipOperation op); - - friend int qt_printerRealNumCopies(QPaintEngine *); }; class QPdfBaseEnginePrivate : public QAlphaPaintEnginePrivate diff --git a/src/gui/painting/qprintengine.h b/src/gui/painting/qprintengine.h index 35715fb..71ff954 100644 --- a/src/gui/painting/qprintengine.h +++ b/src/gui/painting/qprintengine.h @@ -86,6 +86,8 @@ public: PPK_PaperSources, PPK_CustomPaperSize, PPK_PageMargins, + PPK_CopyCount, + PPK_SupportsMultipleCopies, PPK_PaperSize = PPK_PageSize, PPK_CustomBase = 0xff00 diff --git a/src/gui/painting/qprintengine_mac.mm b/src/gui/painting/qprintengine_mac.mm index 7195c63..3d5d1d5 100644 --- a/src/gui/painting/qprintengine_mac.mm +++ b/src/gui/painting/qprintengine_mac.mm @@ -685,6 +685,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va case PPK_FullPage: d->fullPage = value.toBool(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: PMSetCopies(d->settings, value.toInt(), false); break; @@ -787,6 +788,15 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const case PPK_NumberOfCopies: ret = 1; break; + case PPK_CopyCount: { + UInt32 copies = 1; + PMGetCopies(d->settings, &copies); + ret = (uint) copies; + break; + } + case PPK_SupportsMultipleCopies: + ret = true; + break; case PPK_Orientation: PMOrientation orientation; PMGetOrientation(d->format, &orientation); diff --git a/src/gui/painting/qprintengine_qws.cpp b/src/gui/painting/qprintengine_qws.cpp index 2d355b8..396d712 100644 --- a/src/gui/painting/qprintengine_qws.cpp +++ b/src/gui/painting/qprintengine_qws.cpp @@ -268,9 +268,13 @@ QVariant QtopiaPrintEngine::property(PrintEnginePropertyKey key) const case PPK_FullPage: ret = d->fullPage; break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: ret = d->numCopies; break; + case PPK_SupportsMultipleCopies: + ret = false; + break; case PPK_Orientation: ret = d->orientation; break; @@ -329,6 +333,7 @@ void QtopiaPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & case PPK_FullPage: d->fullPage = value.toBool(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: d->numCopies = value.toInt(); break; diff --git a/src/gui/painting/qprintengine_win.cpp b/src/gui/painting/qprintengine_win.cpp index 374bfa0..d029b1e 100644 --- a/src/gui/painting/qprintengine_win.cpp +++ b/src/gui/painting/qprintengine_win.cpp @@ -1240,6 +1240,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & d->updateOrigin(); break; + case PPK_CopyCount: // fallthrough case PPK_NumberOfCopies: if (!d->devMode) break; @@ -1406,6 +1407,14 @@ QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const value = d->fullPage; break; + case PPK_CopyCount: + value = d->num_copies; + break; + + case PPK_SupportsMultipleCopies: + value = true; + break; + case PPK_NumberOfCopies: value = 1; break; diff --git a/src/gui/painting/qprintengine_win_p.h b/src/gui/painting/qprintengine_win_p.h index a3271cb..d435831 100644 --- a/src/gui/painting/qprintengine_win_p.h +++ b/src/gui/painting/qprintengine_win_p.h @@ -108,7 +108,6 @@ public: private: friend class QPrintDialog; friend class QPageSetupDialog; - friend int qt_printerRealNumCopies(QPaintEngine *); }; class QWin32PrintEnginePrivate : public QAlphaPaintEnginePrivate diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index 4d2b50a..edf224d 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -158,27 +158,6 @@ QSizeF qt_printerPaperSize(QPrinter::Orientation orientation, (qt_paperSizes[paperSize][height_index] * 72 / 25.4) / multiplier); } - -// returns the actual num copies set on a printer, not -// the number that is documented in QPrinter::numCopies() -int qt_printerRealNumCopies(QPaintEngine *engine) -{ - int numCopies = 1; - if (engine->type() == QPaintEngine::PostScript - || engine->type() == QPaintEngine::Pdf) - { - QPdfBaseEngine *base = static_cast<QPdfBaseEngine *>(engine); - numCopies = base->d_func()->copies; - } -#ifdef Q_WS_WIN - else if (engine->type() == QPaintEngine::Windows) { - QWin32PrintEngine *base = static_cast<QWin32PrintEngine *>(engine); - numCopies = base->d_func()->num_copies; - } -#endif - return numCopies; -} - void QPrinterPrivate::createDefaultEngines() { QPrinter::OutputFormat realOutputFormat = outputFormat; @@ -302,7 +281,7 @@ void QPrinterPrivate::addToManualSetList(QPrintEngine::PrintEnginePropertyKey ke printer to provide, in dots per inch (DPI). \i setFullPage() tells QPrinter whether you want to deal with the full page or just with the part the printer can draw on. - \i setNumCopies() tells QPrinter how many copies of the document + \i setCopyCount() tells QPrinter how many copies of the document it should print. \endlist @@ -748,7 +727,6 @@ void QPrinter::setOutputFormat(OutputFormat format) d->outputFormat = format; QPrintEngine *oldPrintEngine = d->printEngine; - QPaintEngine *oldPaintEngine = d->paintEngine; // same as the above - shouldn't be deleted const bool def_engine = d->use_default_engine; d->printEngine = 0; @@ -761,7 +739,7 @@ void QPrinter::setOutputFormat(OutputFormat format) // PPK_NumberOfCopies need special treatmeant since it in most cases // will return 1, disregarding the actual value that was set if (key == QPrintEngine::PPK_NumberOfCopies) - prop = QVariant(qt_printerRealNumCopies(oldPaintEngine)); + prop = QVariant(copyCount()); else prop = oldPrintEngine->property(key); if (prop.isValid()) @@ -1263,6 +1241,7 @@ QPrinter::ColorMode QPrinter::colorMode() const /*! + \obsolete Returns the number of copies to be printed. The default value is 1. On Windows, Mac OS X and X11 systems that support CUPS, this will always @@ -1275,6 +1254,8 @@ QPrinter::ColorMode QPrinter::colorMode() const buffering up the copies and in those cases the application must make an explicit call to the print code for each copy. + Use copyCount() in conjunction with supportsMultipleCopies() instead. + \sa setNumCopies(), actualNumCopies() */ @@ -1286,6 +1267,7 @@ int QPrinter::numCopies() const /*! + \obsolete \since 4.6 Returns the number of copies that will be printed. The default @@ -1294,22 +1276,26 @@ int QPrinter::numCopies() const This function always returns the actual value specified in the print dialog or using setNumCopies(). + Use copyCount() instead. + \sa setNumCopies(), numCopies() */ int QPrinter::actualNumCopies() const { - Q_D(const QPrinter); - return qt_printerRealNumCopies(d->paintEngine); + return copyCount(); } /*! + \obsolete Sets the number of copies to be printed to \a numCopies. The printer driver reads this setting and prints the specified number of copies. + Use setCopyCount() instead. + \sa numCopies() */ @@ -1321,6 +1307,58 @@ void QPrinter::setNumCopies(int numCopies) d->addToManualSetList(QPrintEngine::PPK_NumberOfCopies); } +/*! + \since 4.7 + + Sets the number of copies to be printed to \a count. + + The printer driver reads this setting and prints the specified number of + copies. + + \sa copyCount(), supportsMultipleCopies() +*/ + +void QPrinter::setCopyCount(int count) +{ + Q_D(QPrinter); + ABORT_IF_ACTIVE("QPrinter::setCopyCount;"); + d->printEngine->setProperty(QPrintEngine::PPK_CopyCount, count); + d->addToManualSetList(QPrintEngine::PPK_CopyCount); +} + +/*! + \since 4.7 + + Returns the number of copies that will be printed. The default value is 1. + + \sa setCopyCount(), supportsMultipleCopies() +*/ + +int QPrinter::copyCount() const +{ + Q_D(const QPrinter); + return d->printEngine->property(QPrintEngine::PPK_CopyCount).toInt(); +} + +/*! + \since 4.7 + + Returns true if the printer supports printing multiple copies of the same + document in one job; otherwise false is returned. + + On most systems this function will return true. However, on X11 systems + that do not support CUPS, this function will return false. That means the + application has to handle the number of copies by printing the same + document the required number of times. + + \sa setCopyCount(), copyCount() +*/ + +bool QPrinter::supportsMultipleCopies() const +{ + Q_D(const QPrinter); + return d->printEngine->property(QPrintEngine::PPK_SupportsMultipleCopies).toBool(); +} /*! \since 4.1 @@ -2262,8 +2300,8 @@ bool QPrinter::isOptionEnabled( PrinterOption option ) const \value PPK_FullPage A boolean describing if the printer should be full page or not. - \value PPK_NumberOfCopies An integer specifying the number of - copies + \value PPK_NumberOfCopies Obsolete. An integer specifying the number of + copies. Use PPK_CopyCount instead. \value PPK_Orientation Specifies a QPrinter::Orientation value. @@ -2310,6 +2348,11 @@ bool QPrinter::isOptionEnabled( PrinterOption option ) const \value PPK_PageMargins A QList<QVariant> containing the left, top, right and bottom margin values. + \value PPK_CopyCount An integer specifying the number of copies to print. + + \value PPK_SupportsMultipleCopies A boolean value indicating whether or not + the printer supports printing multiple copies in one job. + \value PPK_CustomBase Basis for extension. */ diff --git a/src/gui/painting/qprinter.h b/src/gui/painting/qprinter.h index 5aa891e..6636179 100644 --- a/src/gui/painting/qprinter.h +++ b/src/gui/painting/qprinter.h @@ -199,6 +199,10 @@ public: int actualNumCopies() const; + void setCopyCount(int); + int copyCount() const; + bool supportsMultipleCopies() const; + void setPaperSource(PaperSource); PaperSource paperSource() const; diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 7b7f325..cf3957b 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -55,29 +55,42 @@ QT_BEGIN_NAMESPACE // #define CACHE_DEBUG -void QTextureGlyphCache::populate(const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &) +// returns the highest number closest to v, which is a power of 2 +// NB! assumes 32 bit ints +int qt_next_power_of_two(int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + ++v; + return v; +} + +void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *) { #ifdef CACHE_DEBUG printf("Populating with '%s'\n", QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data()); qDebug() << " -> current transformation: " << m_transform; #endif - m_current_textitem = &ti; + m_current_fontengine = fontEngine; const int margin = glyphMargin(); QHash<glyph_t, Coord> listItemCoordinates; int rowHeight = 0; // check each glyph for its metrics and get the required rowHeight. - for (int i=0; i < glyphs.size(); ++i) { + for (int i=0; i < numGlyphs; ++i) { const glyph_t glyph = glyphs[i]; if (coords.contains(glyph)) continue; if (listItemCoordinates.contains(glyph)) continue; - glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyph, m_transform); + glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform); #ifdef CACHE_DEBUG printf("'%c' (%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f, ti.ascent=%.2f, ti.descent=%.2f\n", @@ -116,7 +129,7 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, rowHeight += margin * 2; if (isNull()) - createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, rowHeight); + createCache(QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH, qt_next_power_of_two(rowHeight)); // now actually use the coords and paint the wanted glyps into cache. QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin(); @@ -129,13 +142,9 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, m_cy = m_h; } if (m_cy + c.h > m_h) { - int new_height; - if (m_cx == 0) { // add a whole row - new_height = m_h + rowHeight; - m_cy = m_h; - } else { // just extend row - new_height = m_cy + rowHeight; - } + int new_height = m_h*2; + while (new_height < m_cy + c.h) + new_height *= 2; // if no room in the current texture - realloc a larger texture resizeTextureData(m_w, new_height); m_h = new_height; @@ -182,7 +191,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const break; }; - QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_textitem->fontEngine); + QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine); QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform); if (gset && ft->loadGlyphs(gset, &g, 1, format)) { @@ -194,9 +203,9 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const } else #endif if (m_type == QFontEngineGlyphCache::Raster_RGBMask) - return m_current_textitem->fontEngine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform); + return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform); else - return m_current_textitem->fontEngine->alphaMapForGlyph(g, m_transform); + return m_current_fontengine->alphaMapForGlyph(g, m_transform); return QImage(); } diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index d347e61..803e71b 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -76,7 +76,9 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache { public: QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) - : QFontEngineGlyphCache(matrix, type), m_w(0), m_h(0), m_cx(0), m_cy(0) { } + : QFontEngineGlyphCache(matrix, type), m_current_fontengine(0), + m_w(0), m_h(0), m_cx(0), m_cy(0) + { } virtual ~QTextureGlyphCache() { } @@ -90,9 +92,8 @@ public: int baseLineY; }; - void populate(const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &positions); + void populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *positions); virtual void createTextureData(int width, int height) = 0; virtual void resizeTextureData(int width, int height) = 0; @@ -113,7 +114,7 @@ public: QImage textureMapForGlyph(glyph_t g) const; protected: - const QTextItemInt *m_current_textitem; + QFontEngine *m_current_fontengine; int m_w; // image width int m_h; // image height diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp new file mode 100644 index 0000000..a7138b9 --- /dev/null +++ b/src/gui/text/qstatictext.cpp @@ -0,0 +1,616 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstatictext.h" +#include "qstatictext_p.h" +#include <private/qtextengine_p.h> +#include <private/qfontengine_p.h> + +#include <QtGui/qapplication.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QStaticText + \brief The QStaticText class enables optimized drawing of text when the text and its layout + is updated rarely. + \since 4.7 + + \ingroup multimedia + \ingroup text + \mainclass + + QStaticText provides a way to cache layout data for a block of text so that it can be drawn + more efficiently than by using QPainter::drawText() in which the layout information is + recalculated with every call. + + The class primarily provides an optimization for cases where the text, its font and the + transformations on the painter are static over several paint events. If the text or its layout + is changed for every iteration, QPainter::drawText() is the more efficient alternative, since + the static text's layout would have to be recalculated to take the new state into consideration. + + Translating the painter will not cause the layout of the text to be recalculated, but will cause + a very small performance impact on drawStaticText(). Altering any other parts of the painter's + transformation or the painter's font will cause the layout of the static text to be + recalculated. This should be avoided as often as possible to maximize the performance + benefit of using QStaticText. + + In addition, only affine transformations are supported by drawStaticText(). Calling + drawStaticText() on a projected painter will perform slightly worse than using the regular + drawText() call, so this should be avoided. + + \code + class MyWidget: public QWidget + { + public: + MyWidget(QWidget *parent = 0) : QWidget(parent), m_staticText("This is static text") + + protected: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.drawStaticText(0, 0, m_staticText); + } + + private: + QStaticText m_staticText; + }; + \endcode + + The QStaticText class can be used to mimic the behavior of QPainter::drawText() to a specific + point with no boundaries, and also when QPainter::drawText() is called with a bounding + rectangle. + + If a bounding rectangle is not required, create a QStaticText object without setting a maximum + size. The text will then occupy a single line. + + If you set a maximum size on the QStaticText object, this will bound the text. The text will + be formatted so that no line exceeds the given width. When the object is painted, it will + be clipped at the given size. The position of the text is decided by the argument + passed to QPainter::drawStaticText() and can change from call to call with a minimal impact + on performance. + + QStaticText will attempt to guess the format of the input text using Qt::mightBeRichText(). + To force QStaticText to display its contents as either plain text or rich text, use the + function QStaticText::setTextFormat() and pass in, respectively, Qt::PlainText and + Qt::RichText. + + \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument +*/ + +/*! + \enum QStaticText::PerformanceHint + + This enum the different performance hints that can be set on the QStaticText. These hints + can be used to indicate that the QStaticText should use additional caches, if possible, + to improve performance at the expense of memory. In particular, setting the performance hint + AggressiveCaching on the QStaticText will improve performance when using the OpenGL graphics + system or when drawing to a QGLWidget. + + \value ModerateCaching Do basic caching for high performance at a low memory cost. + \value AggressiveCaching Use additional caching when available. This may improve performance + at a higher memory cost. +*/ + +/*! + Constructs an empty QStaticText +*/ +QStaticText::QStaticText() + : data(new QStaticTextPrivate) +{ +} + +/*! + Constructs a QStaticText object with the given \a text and bounded by the given \a size. + + If an invalid size is passed for \a size the text will be unbounded. +*/ +QStaticText::QStaticText(const QString &text, const QSizeF &size) + : data(new QStaticTextPrivate) +{ + data->text = text; + data->maximumSize = size; + data->init(); +} + +/*! + Constructs a QStaticText object which is a copy of \a other. +*/ +QStaticText::QStaticText(const QStaticText &other) +{ + data = other.data; +} + +/*! + Destroys the QStaticText. +*/ +QStaticText::~QStaticText() +{ + Q_ASSERT(!data || data->ref >= 1); +} + +/*! + \internal +*/ +void QStaticText::detach() +{ + if (data->ref != 1) + data.detach(); +} + +/*! + Prepares the QStaticText object for being painted with the given \a matrix and the given + \a font to avoid overhead when the actual drawStaticText() call is made. + + When drawStaticText() is called, the layout of the QStaticText will be recalculated if the + painter's font or matrix is different from the one used for the currently cached layout. By + default, QStaticText will use a default constructed QFont and an identity matrix to create + its layout. + + To avoid the overhead of creating the layout the first time you draw the QStaticText with + a painter whose matrix or font are different from the defaults, you can use the prepare() + function and pass in the matrix and font you expect to use when drawing the text. + + \sa QPainter::setFont(), QPainter::setMatrix() +*/ +void QStaticText::prepare(const QTransform &matrix, const QFont &font) +{ + data->matrix = matrix; + data->font = font; + data->init(); +} + + +/*! + Assigns \a other to this QStaticText. +*/ +QStaticText &QStaticText::operator=(const QStaticText &other) +{ + data = other.data; + return *this; +} + +/*! + Compares \a other to this QStaticText. Returns true if the texts, fonts and maximum sizes + are equal. +*/ +bool QStaticText::operator==(const QStaticText &other) const +{ + return (data == other.data + || (data->text == other.data->text + && data->font == other.data->font + && data->maximumSize == other.data->maximumSize)); +} + +/*! + Compares \a other to this QStaticText. Returns true if the texts, fonts or maximum sizes + are different. +*/ +bool QStaticText::operator!=(const QStaticText &other) const +{ + return !(*this == other); +} + +/*! + Sets the text of the QStaticText to \a text. + + \note This function will cause the layout of the text to be recalculated. + + \sa text() +*/ +void QStaticText::setText(const QString &text) +{ + detach(); + data->text = text; + data->init(); +} + +/*! + Sets the text format of the QStaticText to \a textFormat. If \a textFormat is set to + Qt::AutoText (the default), the format of the text will try to be determined using the + function Qt::mightBeRichText(). If the text format is Qt::PlainText, then the text will be + displayed as is, whereas it will be interpreted as HTML if the format is Qt::RichText. HTML tags + that alter the font of the text, its color, or its layout are supported by QStaticText. + + \note This function will cause the layout of the text to be recalculated. + + \sa textFormat(), setText(), text() +*/ +void QStaticText::setTextFormat(Qt::TextFormat textFormat) +{ + detach(); + data->textFormat = textFormat; + data->init(); +} + +/*! + Returns the text format of the QStaticText. + + \sa setTextFormat(), setText(), text() +*/ +Qt::TextFormat QStaticText::textFormat() const +{ + return Qt::TextFormat(data->textFormat); +} + +/*! + Returns the text of the QStaticText. + + \sa setText() +*/ +QString QStaticText::text() const +{ + return data->text; +} + +/*! + Sets the performance hint of the QStaticText. This hint can be used to customize how much + caching is done internally to improve performance. + + The default is QStaticText::ModerateCaching. + + \note This function will cause the layout of the text to be recalculated. + + \sa performanceHint() +*/ +void QStaticText::setPerformanceHint(PerformanceHint performanceHint) +{ + if ((performanceHint == ModerateCaching && !data->useBackendOptimizations) + || (performanceHint == AggressiveCaching && data->useBackendOptimizations)) { + return; + } + detach(); + data->useBackendOptimizations = (performanceHint == AggressiveCaching); + data->init(); +} + +/*! + Returns which performance hint is set for the QStaticText. + + \sa setPerformanceHint() +*/ +QStaticText::PerformanceHint QStaticText::performanceHint() const +{ + return data->useBackendOptimizations ? AggressiveCaching : ModerateCaching; +} + +/*! + Sets the maximum size of the QStaticText to \a size. + + \note This function will cause the layout of the text to be recalculated. + + \sa maximumSize(), size() +*/ +void QStaticText::setMaximumSize(const QSizeF &size) +{ + detach(); + data->maximumSize = size; + data->init(); +} + +/*! + Returns the maximum size of the QStaticText. + + \sa setMaximumSize() +*/ +QSizeF QStaticText::maximumSize() const +{ + return data->maximumSize; +} + +/*! + Returns the size of the bounding rect for this QStaticText. + + \sa maximumSize() +*/ +QSizeF QStaticText::size() const +{ + return data->actualSize; +} + +QStaticTextPrivate::QStaticTextPrivate() + : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + useBackendOptimizations(false), textFormat(Qt::AutoText) +{ + ref = 1; +} + +QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) + : text(other.text), font(other.font), maximumSize(other.maximumSize), matrix(other.matrix), + items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + useBackendOptimizations(false), textFormat(other.textFormat) +{ + ref = 1; +} + +QStaticTextPrivate::~QStaticTextPrivate() +{ + delete[] items; + delete[] glyphPool; + delete[] positionPool; +} + +QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) +{ + return q->data.data(); +} + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +namespace { + + class DrawTextItemRecorder: public QPaintEngine + { + public: + DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items, + int expectedGlyphCount, QFixedPoint *positionPool, glyph_t *glyphPool) + : m_items(items), + m_itemCount(0), m_glyphCount(0), + m_expectedItemCount(expectedItemCount), + m_expectedGlyphCount(expectedGlyphCount), + m_glyphPool(glyphPool), + m_positionPool(positionPool) + { + } + + virtual void drawTextItem(const QPointF &position, const QTextItem &textItem) + { + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + + m_itemCount++; + m_glyphCount += ti.glyphs.numGlyphs; + if (m_items == 0) + return; + + Q_ASSERT(m_itemCount <= m_expectedItemCount); + Q_ASSERT(m_glyphCount <= m_expectedGlyphCount); + + QStaticTextItem *currentItem = (m_items + (m_itemCount - 1)); + currentItem->fontEngine = ti.fontEngine; + currentItem->font = ti.font(); + currentItem->chars = ti.chars; + currentItem->numChars = ti.num_chars; + currentItem->numGlyphs = ti.glyphs.numGlyphs; + currentItem->glyphs = m_glyphPool; + currentItem->glyphPositions = m_positionPool; + currentItem->color = state->pen().color(); + + QTransform matrix = state->transform(); + matrix.translate(position.x(), position.y()); + + QVarLengthArray<glyph_t> glyphs; + QVarLengthArray<QFixedPoint> positions; + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + int size = glyphs.size(); + Q_ASSERT(size == ti.glyphs.numGlyphs); + Q_ASSERT(size == positions.size()); + + memmove(currentItem->glyphs, glyphs.constData(), sizeof(glyph_t) * size); + memmove(currentItem->glyphPositions, positions.constData(), sizeof(QFixedPoint) * size); + + m_glyphPool += size; + m_positionPool += size; + } + + + virtual bool begin(QPaintDevice *) { return true; } + virtual bool end() { return true; } + virtual void updateState(const QPaintEngineState &) {} + virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {} + virtual Type type() const + { + return User; + } + + int itemCount() const + { + return m_itemCount; + } + + int glyphCount() const + { + return m_glyphCount; + } + + private: + QStaticTextItem *m_items; + int m_itemCount; + int m_glyphCount; + int m_expectedItemCount; + int m_expectedGlyphCount; + + glyph_t *m_glyphPool; + QFixedPoint *m_positionPool; + }; + + class DrawTextItemDevice: public QPaintDevice + { + public: + DrawTextItemDevice(int expectedItemCount = -1, QStaticTextItem *items = 0, + int expectedGlyphCount = -1, QFixedPoint *positionPool = 0, + glyph_t *glyphPool = 0) + { + m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items, + expectedGlyphCount, positionPool, glyphPool); + } + + ~DrawTextItemDevice() + { + delete m_paintEngine; + } + + int metric(PaintDeviceMetric m) const + { + int val; + switch (m) { + case PdmWidth: + case PdmHeight: + case PdmWidthMM: + case PdmHeightMM: + val = 0; + break; + case PdmDpiX: + case PdmPhysicalDpiX: + val = qt_defaultDpiX(); + break; + case PdmDpiY: + case PdmPhysicalDpiY: + val = qt_defaultDpiY(); + break; + case PdmNumColors: + val = 16777216; + break; + case PdmDepth: + val = 24; + break; + default: + val = 0; + qWarning("DrawTextItemDevice::metric: Invalid metric command"); + } + return val; + } + + virtual QPaintEngine *paintEngine() const + { + return m_paintEngine; + } + + int itemCount() const + { + return m_paintEngine->itemCount(); + } + + int glyphCount() const + { + return m_paintEngine->glyphCount(); + } + + private: + DrawTextItemRecorder *m_paintEngine; + }; +} + +void QStaticTextPrivate::paintText(const QPointF &pos, QPainter *p) +{ + bool preferRichText = textFormat == Qt::RichText + || (textFormat == Qt::AutoText && Qt::mightBeRichText(text)); + + if (!preferRichText) { + if (maximumSize.isValid()) { + QRectF boundingRect; + p->drawText(QRectF(pos, maximumSize), Qt::TextWordWrap, text, &boundingRect); + + actualSize = boundingRect.size(); + needsClipRect = boundingRect.width() > maximumSize.width() + || boundingRect.height() > maximumSize.height(); + } else { + p->drawText(pos, text); + needsClipRect = false; + + QFontMetrics fm(font); + actualSize = fm.boundingRect(text).size(); + } + } else { + QTextDocument document; + document.setDefaultFont(font); + document.setHtml(text); + + QRectF rect = maximumSize.isValid() ? QRectF(pos, maximumSize) : QRectF(); + document.adjustSize(); + p->save(); + p->translate(pos); + document.drawContents(p, rect); + p->restore(); + actualSize = document.size(); + needsClipRect = maximumSize.isValid() + && (actualSize.width() > maximumSize.width() + || actualSize.height() > maximumSize.height()); + } +} + +void QStaticTextPrivate::init() +{ + delete[] items; + delete[] glyphPool; + delete[] positionPool; + + position = QPointF(0, 0); + + // Draw once to count number of items and glyphs, so that we can use as little memory + // as possible to store the data + DrawTextItemDevice counterDevice; + { + QPainter painter(&counterDevice); + painter.setFont(font); + painter.setTransform(matrix); + + paintText(QPointF(0, 0), &painter); + + } + + itemCount = counterDevice.itemCount(); + items = new QStaticTextItem[itemCount]; + + if (useBackendOptimizations) { + for (int i=0; i<itemCount; ++i) + items[i].useBackendOptimizations = true; + } + + + int glyphCount = counterDevice.glyphCount(); + glyphPool = new glyph_t[glyphCount]; + positionPool = new QFixedPoint[glyphCount]; + + // Draw again to actually record the items and glyphs + DrawTextItemDevice recorderDevice(itemCount, items, glyphCount, positionPool, glyphPool); + { + QPainter painter(&recorderDevice); + painter.setFont(font); + painter.setTransform(matrix); + + paintText(QPointF(0, 0), &painter); + } + +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h new file mode 100644 index 0000000..1e59944 --- /dev/null +++ b/src/gui/text/qstatictext.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATICTEXT_H +#define QSTATICTEXT_H + +#include <QtCore/qsize.h> +#include <QtCore/qstring.h> +#include <QtCore/qmetatype.h> + +#include <QtGui/qtransform.h> +#include <QtGui/qfont.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStaticTextPrivate; +class Q_GUI_EXPORT QStaticText +{ +public: + enum PerformanceHint { + ModerateCaching, + AggressiveCaching + }; + + QStaticText(); + QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); + QStaticText(const QStaticText &other); + ~QStaticText(); + + void setText(const QString &text); + QString text() const; + + void setTextFormat(Qt::TextFormat textFormat); + Qt::TextFormat textFormat() const; + + void setMaximumSize(const QSizeF &maximumSize); + QSizeF maximumSize() const; + + QSizeF size() const; + + void prepare(const QTransform &matrix, const QFont &font); + + void setPerformanceHint(PerformanceHint performanceHint); + PerformanceHint performanceHint() const; + + QStaticText &operator=(const QStaticText &); + bool operator==(const QStaticText &) const; + bool operator!=(const QStaticText &) const; + +private: + void detach(); + + QExplicitlySharedDataPointer<QStaticTextPrivate> data; + friend class QStaticTextPrivate; +}; + +Q_DECLARE_METATYPE(QStaticText) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSTATICTEXT_H diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h new file mode 100644 index 0000000..e758244 --- /dev/null +++ b/src/gui/text/qstatictext_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATICTEXT_P_H +#define QSTATICTEXT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include <private/qtextureglyphcache_p.h> +#include <QtGui/qcolor.h> + +QT_BEGIN_NAMESPACE + +class QStaticTextUserData +{ +public: + enum Type { + NoUserData, + OpenGLUserData + }; + + QStaticTextUserData(Type t) : type(t) {} + virtual ~QStaticTextUserData() {} + + Type type; +}; + +class Q_GUI_EXPORT QStaticTextItem +{ +public: + QStaticTextItem() : chars(0), numChars(0), fontEngine(0), userData(0), + useBackendOptimizations(false), userDataNeedsUpdate(0) {} + ~QStaticTextItem() { delete userData; } + + void setUserData(QStaticTextUserData *newUserData) + { + if (userData == newUserData) + return; + + delete userData; + userData = newUserData; + } + + QFixedPoint *glyphPositions; // 8 bytes per glyph + glyph_t *glyphs; // 4 bytes per glyph + const QChar *chars; // 2 bytes per glyph + // ================= + // 14 bytes per glyph + + // 12 bytes for pointers + int numGlyphs; // 4 bytes per item + int numChars; // 4 bytes per item + QFontEngine *fontEngine; // 4 bytes per item + QFont font; // 8 bytes per item + QColor color; // 10 bytes per item + QStaticTextUserData *userData; // 8 bytes per item + char useBackendOptimizations : 1; // 1 byte per item + char userDataNeedsUpdate : 1; // + // ================ + // 51 bytes per item +}; + +class QStaticText; +class Q_AUTOTEST_EXPORT QStaticTextPrivate +{ +public: + QStaticTextPrivate(); + QStaticTextPrivate(const QStaticTextPrivate &other); + ~QStaticTextPrivate(); + + void init(); + void paintText(const QPointF &pos, QPainter *p); + + QAtomicInt ref; // 4 bytes per text + + QString text; // 4 bytes per text + QFont font; // 8 bytes per text + QSizeF maximumSize; // 16 bytes per text + QSizeF actualSize; // 16 bytes per text + QPointF position; // 16 bytes per text + + QTransform matrix; // 80 bytes per text + QStaticTextItem *items; // 4 bytes per text + int itemCount; // 4 bytes per text + glyph_t *glyphPool; // 4 bytes per text + QFixedPoint *positionPool; // 4 bytes per text + + unsigned char needsClipRect : 1; // 1 byte per text + unsigned char useBackendOptimizations : 1; + unsigned char textFormat : 2; + // ================ + // 171 bytes per text + + static QStaticTextPrivate *get(const QStaticText *q); +}; + +QT_END_NAMESPACE + +#endif // QSTATICTEXT_P_H diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index c81d538..c91df3c 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -1145,7 +1145,7 @@ void QTextCursor::setPosition(int pos, MoveMode m) Returns the absolute position of the cursor within the document. The cursor is positioned between characters. - \sa setPosition() movePosition() anchor() + \sa setPosition() movePosition() anchor() positionInBlock() */ int QTextCursor::position() const { @@ -1155,6 +1155,22 @@ int QTextCursor::position() const } /*! + \since 4.7 + Returns the relative position of the cursor within the block. + The cursor is positioned between characters. + + This is equivalent to \c{ position() - block().position()}. + + \sa position() +*/ +int QTextCursor::positionInBlock() const +{ + if (!d || !d->priv) + return 0; + return d->position - d->block().position(); +} + +/*! Returns the anchor position; this is the same as position() unless there is a selection in which case position() marks one end of the selection and anchor() marks the other end. Just like the cursor @@ -2414,9 +2430,17 @@ int QTextCursor::blockNumber() const return d->block().blockNumber(); } + /*! \since 4.2 Returns the position of the cursor within its containing line. + + Note that this is the column number relative to a wrapped line, + not relative to the block (i.e. the paragraph). + + You probably want to call positionInBlock() instead. + + \sa positionInBlock() */ int QTextCursor::columnNumber() const { diff --git a/src/gui/text/qtextcursor.h b/src/gui/text/qtextcursor.h index 38bc39d..3e968a3 100644 --- a/src/gui/text/qtextcursor.h +++ b/src/gui/text/qtextcursor.h @@ -89,6 +89,7 @@ public: void setPosition(int pos, MoveMode mode = MoveAnchor); int position() const; + int positionInBlock() const; int anchor() const; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index e1cfa9c..9a1b70c 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -1774,9 +1774,9 @@ void QTextDocument::print(QPrinter *printer) const int pageCopies; if (printer->collateCopies() == true){ docCopies = 1; - pageCopies = printer->numCopies(); + pageCopies = printer->supportsMultipleCopies() ? 1 : printer->copyCount(); } else { - docCopies = printer->numCopies(); + docCopies = printer->supportsMultipleCopies() ? 1 : printer->copyCount(); pageCopies = 1; } diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index b7615a4..9ec3142 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -37,7 +37,9 @@ HEADERS += \ text/qtexttable_p.h \ text/qzipreader_p.h \ text/qzipwriter_p.h \ - text/qtextodfwriter_p.h + text/qtextodfwriter_p.h \ + text/qstatictext_p.h \ + text/qstatictext.h SOURCES += \ text/qfont.cpp \ @@ -66,7 +68,8 @@ SOURCES += \ text/qsyntaxhighlighter.cpp \ text/qcssparser.cpp \ text/qzip.cpp \ - text/qtextodfwriter.cpp + text/qtextodfwriter.cpp \ + text/qstatictext.cpp win32 { SOURCES += \ diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp index adc4fc1..65b998f 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -415,11 +415,11 @@ QString QDesktopServices::storageLocation(StandardLocation type) //return QDir::homePath(); break; break; case DataLocation: - CEikonEnv::Static()->FsSession().PrivatePath(path); + qt_s60GetRFs().PrivatePath(path); path.Insert(0, writableExeDrive().Name()); break; case CacheLocation: - CEikonEnv::Static()->FsSession().PrivatePath(path); + qt_s60GetRFs().PrivatePath(path); path.Insert(0, writableExeDrive().Name()); path.Append(KCacheSubDir); break; diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index fdace46..54189de 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -1010,7 +1010,7 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect if (!floating && parent) { QMainWindowLayout *mwlayout = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout()); - if (!mwlayout || mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea) + if (mwlayout && mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea) return; // this dockwidget can't be redocked } diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index 0d798b7..ef9fac3 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -1320,6 +1320,26 @@ QTextCursor QPlainTextEdit::textCursor() const return d->control->textCursor(); } +/*! + Returns the reference of the anchor at position \a pos, or an + empty string if no anchor exists at that point. + + \since 4.7 + */ +QString QPlainTextEdit::anchorAt(const QPoint &pos) const +{ + Q_D(const QPlainTextEdit); + int cursorPos = d->control->hitTest(pos + QPoint(d->horizontalOffset(), + d->verticalOffset()), + Qt::ExactHit); + if (cursorPos < 0) + return QString(); + + QTextDocumentPrivate *pieceTable = document()->docHandle(); + QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); + QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format); + return fmt.anchorHref(); +} /*! Undoes the last operation. diff --git a/src/gui/widgets/qplaintextedit.h b/src/gui/widgets/qplaintextedit.h index 15cf0967..106ae6d 100644 --- a/src/gui/widgets/qplaintextedit.h +++ b/src/gui/widgets/qplaintextedit.h @@ -159,6 +159,8 @@ public: QRect cursorRect(const QTextCursor &cursor) const; QRect cursorRect() const; + QString anchorAt(const QPoint &pos) const; + bool overwriteMode() const; void setOverwriteMode(bool overwrite); |