diff options
35 files changed, 720 insertions, 401 deletions
diff --git a/dist/changes-4.6.0 b/dist/changes-4.6.0 index a257c91b18..7ca724cf81 100644 --- a/dist/changes-4.6.0 +++ b/dist/changes-4.6.0 @@ -631,6 +631,40 @@ Qt Plugins * [258526] Rotate the image if the tiff file contains an orientation tag. * [254317] Add support for mono and indexed format + - QPlainTextEdit + * Fixed crash when clicking on a text edit which was smaller than the + height of the font used. + + - QPrinter + * [QTBUG-4497] Removed redundant SetPen command in the postscript code + when reusing a QPrinter object. + + - QTextLayout + * [QTBUG-4468] Count tabs as multiple characters when applying a fixed + column width. + * [176401] Take into account the negative right bearing of the last + character in an item of text if the glyph extends beyond its ascent. + + - QTextDocument + * [207189] Support setting font size using short hand syntax in the + CSS "font" property. + * [201228] Remove implicit margin on bullet lists when exporting to + HTML. + * [240086] Fixed bug which caused floating objects which span several + pages to float into the second page of the document even when it's + the only existing object, causing the document to contain a blank + first page. + * [240325] Even when wrap mode is set to Qt::TextWordWrap, the layout + would sometimes break outside word boundaries when floating objects + affected the width available to the text. This has been fixed. + + - QFontEngine + * [QTBUG-2354] Support certain 'Microsoft' platform symbol fonts which + also contain a regular unicode table for exactly the symbol range of + code points. + + - QFontMetrics + * [176401] Account for right bearing in bounding rect. **************************************************************************** * Platform Specific Changes * @@ -818,6 +852,19 @@ Qt for Embedded Linux - Compilation fixes for OpenGL/ES 1.0 and OpenGL/ES 1.1 Common Lite. + - Phonon on Windows + * Now much more reliable when reading a file through a QIODevice. + * If Video Mixing Renderer 9 is not available, falls back to software + rendering. + * Fixed a flicker issue when switching source with a transition time of 0 + + - [QTBUG-3620] Fixed bug on X11 that caused bitmap fonts to become so small + it was unreadable when printed or presented in a print preview widget. + + - [QTBUG-4445] Fixed bug on Windows that caused problems when printing + text where several characters were represented by a single glyph, e.g. + a double 't' with the Calibri font. + - EGL and OpenGL/ES * Protect the use of version-specific EGL symbols with #ifdef's. * Make sure an EGL context is current when resolving GL extensions. diff --git a/examples/effects/lighting/lighting.cpp b/examples/effects/lighting/lighting.cpp index 7026b66bac..51fa9f8f7c 100644 --- a/examples/effects/lighting/lighting.cpp +++ b/examples/effects/lighting/lighting.cpp @@ -94,7 +94,7 @@ void Lighting::setupScene() else item = new QGraphicsRectItem(0, 0, 50, 50); - item->setPen(QPen(Qt::black)); + item->setPen(QPen(Qt::black, 1)); item->setBrush(QBrush(Qt::white)); QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect; effect->setBlurRadius(8); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h b/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h index 2a407d4932..188b68faa8 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/wtf/Platform.h @@ -98,6 +98,10 @@ /* regardless of operating environment */ #if defined(_AIX) #define WTF_PLATFORM_AIX 1 +/* 64-bit mode on AIX */ +#ifdef __64BIT__ +#define WTF_PLATFORM_AIX64 1 +#endif #endif /* PLATFORM(HPUX) */ @@ -708,6 +712,8 @@ #define WTF_USE_JSVALUE64 1 #elif (PLATFORM(IA64) && !PLATFORM(IA64_32)) || PLATFORM(SPARC64) #define WTF_USE_JSVALUE64 1 +#elif PLATFORM(AIX64) +#define WTF_USE_JSVALUE64 1 #elif PLATFORM(ARM) || PLATFORM(PPC64) #define WTF_USE_JSVALUE32 1 #elif PLATFORM(WIN_OS) && COMPILER(MINGW) diff --git a/src/gui/dialogs/qprintdialog_unix.cpp b/src/gui/dialogs/qprintdialog_unix.cpp index 6fc270d688..9d6cd552a2 100644 --- a/src/gui/dialogs/qprintdialog_unix.cpp +++ b/src/gui/dialogs/qprintdialog_unix.cpp @@ -835,9 +835,6 @@ void QUnixPrintWidgetPrivate::setOptionsPane(QPrintDialogPrivate *pane) void QUnixPrintWidgetPrivate::_q_btnBrowseClicked() { - const int prevPrinter = widget.printers->currentIndex(); - widget.printers->setCurrentIndex(widget.printers->count() - 2); // the pdf one - QString filename = widget.filename->text(); #ifndef QT_NO_FILEDIALOG filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename, @@ -849,9 +846,11 @@ void QUnixPrintWidgetPrivate::_q_btnBrowseClicked() widget.filename->setText(filename); if (filename.endsWith(QString::fromLatin1(".ps"), Qt::CaseInsensitive)) widget.printers->setCurrentIndex(widget.printers->count() - 1); // the postscript one + else if (filename.endsWith(QString::fromLatin1(".pdf"), Qt::CaseInsensitive)) + widget.printers->setCurrentIndex(widget.printers->count() - 2); // the pdf one + else if (widget.printers->currentIndex() != widget.printers->count() - 1) // if ps is not selected, pdf is default + widget.printers->setCurrentIndex(widget.printers->count() - 2); // the pdf one } - else - widget.printers->setCurrentIndex(prevPrinter); } void QUnixPrintWidgetPrivate::applyPrinterProperties(QPrinter *p) diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index 39291d31a3..c0e48903ac 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -62,6 +62,7 @@ QEglContext::QEglContext() , currentSurface(EGL_NO_SURFACE) , current(false) , ownsContext(true) + , sharing(false) { } @@ -174,6 +175,7 @@ bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties if (apiType == QEgl::OpenGL) contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); #endif + sharing = false; if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) shareContext = 0; if (shareContext) { @@ -181,6 +183,8 @@ bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); shareContext = 0; + } else { + sharing = true; } } if (ctx == EGL_NO_CONTEXT) { diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index 16b5b169c3..51bdbbe128 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -81,6 +81,7 @@ public: bool isValid() const; bool isCurrent() const; + bool isSharing() const { return sharing; } QEgl::API api() const { return apiType; } void setApi(QEgl::API api) { apiType = api; } @@ -132,6 +133,7 @@ private: EGLSurface currentSurface; bool current; bool ownsContext; + bool sharing; static EGLDisplay getDisplay(QPaintDevice *device); diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index c0b840ae24..3723500cd9 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -1064,9 +1064,7 @@ void QPixmapDropShadowFilter::setOffset(const QPointF &offset) QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const { Q_D(const QPixmapDropShadowFilter); - qreal delta = d->radius + 1; - return rect.adjusted(-2, -2, 2, 2).united( - rect.translated(d->offset).adjusted(-delta, -delta, delta, delta)); + return rect.united(rect.translated(d->offset).adjusted(-d->radius, -d->radius, d->radius, d->radius)); } /*! @@ -1089,19 +1087,24 @@ void QPixmapDropShadowFilter::draw(QPainter *p, return; } - QImage tmp = src.isNull() ? px.toImage() : px.copy(src.toAlignedRect()).toImage(); + QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied); + tmp.fill(0); + QPainter tmpPainter(&tmp); + tmpPainter.setCompositionMode(QPainter::CompositionMode_Source); + tmpPainter.drawPixmap(d->offset, px); + tmpPainter.end(); // blur the alpha channel tmp = blurred(tmp, tmp.rect(), qRound(d->radius), true); // blacken the image... - QPainter tmpPainter(&tmp); + tmpPainter.begin(&tmp); tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); - tmpPainter.fillRect(0, 0, tmp.width(), tmp.height(), d->color); + tmpPainter.fillRect(tmp.rect(), d->color); tmpPainter.end(); // draw the blurred drop shadow... - p->drawImage(pos + d->offset, tmp); + p->drawImage(pos, tmp); // Draw the actual pixmap... p->drawPixmap(pos, px, src); diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp index ab2dc33023..51d6195ed8 100644 --- a/src/gui/painting/qpathclipper.cpp +++ b/src/gui/painting/qpathclipper.cpp @@ -1650,7 +1650,7 @@ static void clear(QWingedEdge& list, int edge, QPathEdge::Traversal traversal) template <typename InputIterator> InputIterator qFuzzyFind(InputIterator first, InputIterator last, qreal val) { - while (first != last && !qFuzzyCompare(qreal(*first), qreal(val))) + while (first != last && !QT_PREPEND_NAMESPACE(qFuzzyCompare)(qreal(*first), qreal(val))) ++first; return first; } diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 9d1d9659cd..63dec2b053 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -3867,23 +3867,28 @@ QRegion::QRegion(const QRect &r, RegionType t) QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) { if (a.count() > 2) { - d = new QRegionData; - d->ref = 1; + QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(), + fillRule == Qt::WindingFill ? WindingRule : EvenOddRule); + if (qt_rgn) { + d = new QRegionData; + d->ref = 1; #if defined(Q_WS_X11) - d->rgn = 0; - d->xrectangles = 0; + d->rgn = 0; + d->xrectangles = 0; #elif defined(Q_WS_WIN) - d->rgn = 0; + d->rgn = 0; #endif - d->qt_rgn = PolygonRegion(a.constData(), a.size(), - fillRule == Qt::WindingFill ? WindingRule : EvenOddRule); + d->qt_rgn = qt_rgn; + } else { + d = &shared_empty; + d->ref.ref(); + } } else { d = &shared_empty; d->ref.ref(); } } - QRegion::QRegion(const QRegion &r) { d = r.d; diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h index 2f8a74611d..438b291c0a 100644 --- a/src/gui/text/qabstracttextdocumentlayout.h +++ b/src/gui/text/qabstracttextdocumentlayout.h @@ -122,6 +122,7 @@ protected: QTextCharFormat format(int pos); private: + friend class QTextControl; friend class QTextDocument; friend class QTextDocumentPrivate; friend class QTextEngine; diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 4041717605..293eac76ac 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -755,9 +755,8 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph load_flags = FT_LOAD_NO_BITMAP; // apply our matrix to this, but note that the metrics will not be affected by this. - FT_Matrix matrix = freetype->matrix; FT_Face face = lockFace(); - matrix = this->matrix; + FT_Matrix matrix = this->matrix; FT_Matrix_Multiply(&set->transformationMatrix, &matrix); FT_Set_Transform(face, &matrix, 0); freetype->matrix = matrix; diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 2bfe33c56d..be79773518 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -55,6 +55,7 @@ #include <qstyle.h> #include <qtimer.h> #include "private/qtextdocumentlayout_p.h" +#include "private/qabstracttextdocumentlayout_p.h" #include "private/qtextedit_p.h" #include "qtextdocument.h" #include "private/qtextdocument_p.h" @@ -126,6 +127,7 @@ QTextControlPrivate::QTextControlPrivate() #endif isEnabled(true), hadSelectionOnMousePress(false), + ignoreUnusedNavigationEvents(false), openExternalLinks(false) {} @@ -264,19 +266,25 @@ bool QTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e) cursor.setVisualNavigation(visualNavigation); q->ensureCursorVisible(); + bool ignoreNavigationEvents = ignoreUnusedNavigationEvents; + bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down; + +#ifdef QT_KEYPAD_NAVIGATION + ignoreNavigationEvents = ignoreNavigationEvents || QApplication::keypadNavigationEnabled(); + isNavigationEvent = isNavigationEvent || + (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional + && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right)); +#else + isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right; +#endif + if (moved) { if (cursor.position() != oldCursorPos) emit q->cursorPositionChanged(); emit q->microFocusChanged(); - } -#ifdef QT_KEYPAD_NAVIGATION - else if (QApplication::keypadNavigationEnabled() - && ((e->key() == Qt::Key_Up || e->key() == Qt::Key_Down) - || QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional - && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))) { + } else if (ignoreNavigationEvents && isNavigationEvent) { return false; } -#endif selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor)); @@ -2263,6 +2271,18 @@ bool QTextControl::openExternalLinks() const return d->openExternalLinks; } +bool QTextControl::ignoreUnusedNavigationEvents() const +{ + Q_D(const QTextControl); + return d->ignoreUnusedNavigationEvents; +} + +void QTextControl::setIgnoreUnusedNavigationEvents(bool ignore) +{ + Q_D(QTextControl); + d->ignoreUnusedNavigationEvents = ignore; +} + void QTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode) { Q_D(QTextControl); @@ -2319,6 +2339,9 @@ void QTextControl::print(QPrinter *printer) const tempDoc->setUseDesignMetrics(doc->useDesignMetrics()); QTextCursor(tempDoc).insertFragment(d->cursor.selection()); doc = tempDoc; + + // copy the custom object handlers + doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers; } doc->print(printer); delete tempDoc; diff --git a/src/gui/text/qtextcontrol_p.h b/src/gui/text/qtextcontrol_p.h index 263af3194e..bc8e063f76 100644 --- a/src/gui/text/qtextcontrol_p.h +++ b/src/gui/text/qtextcontrol_p.h @@ -95,6 +95,7 @@ class Q_GUI_EXPORT QTextControl : public QObject Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth) Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags WRITE setTextInteractionFlags) Q_PROPERTY(bool openExternalLinks READ openExternalLinks WRITE setOpenExternalLinks) + Q_PROPERTY(bool ignoreUnusedNavigationEvents READ ignoreUnusedNavigationEvents WRITE setIgnoreUnusedNavigationEvents) public: explicit QTextControl(QObject *parent = 0); explicit QTextControl(const QString &text, QObject *parent = 0); @@ -163,6 +164,9 @@ public: void setOpenExternalLinks(bool open); bool openExternalLinks() const; + void setIgnoreUnusedNavigationEvents(bool ignore); + bool ignoreUnusedNavigationEvents() const; + void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor); bool canPaste() const; diff --git a/src/gui/text/qtextcontrol_p_p.h b/src/gui/text/qtextcontrol_p_p.h index 66459f6443..c2305122b2 100644 --- a/src/gui/text/qtextcontrol_p_p.h +++ b/src/gui/text/qtextcontrol_p_p.h @@ -206,6 +206,7 @@ public: QString anchorOnMousePress; bool hadSelectionOnMousePress; + bool ignoreUnusedNavigationEvents; bool openExternalLinks; QString linkToCopy; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 1aad385cc3..048325c036 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -64,6 +64,7 @@ #include "qtextdocument_p.h" #include <private/qprinter_p.h> +#include <private/qabstracttextdocumentlayout_p.h> #include <limits.h> @@ -1722,6 +1723,9 @@ void QTextDocument::print(QPrinter *printer) const QAbstractTextDocumentLayout *layout = doc->documentLayout(); layout->setPaintDevice(p.device()); + // copy the custom object handlers + layout->d_func()->handlers = documentLayout()->d_func()->handlers; + int dpiy = p.device()->logicalDpiY(); int margin = 0; if (printer->fullPage() && !printer->d_func()->hasCustomPageMargins) { diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 73434b1fa4..2604879e5e 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -1448,13 +1448,13 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p painter->fillRect(r, brush); break; case QTextListFormat::ListCircle: - painter->drawEllipse(r); + painter->setPen(QPen(brush, 0)); + painter->drawEllipse(r.translated(0.5, 0.5)); // pixel align for sharper rendering break; case QTextListFormat::ListDisc: painter->setBrush(brush); painter->setPen(Qt::NoPen); painter->drawEllipse(r); - painter->setBrush(Qt::NoBrush); break; case QTextListFormat::ListStyleUndefined: break; diff --git a/src/opengl/qgl_qws.cpp b/src/opengl/qgl_qws.cpp index 5e59975c34..a189c20fed 100644 --- a/src/opengl/qgl_qws.cpp +++ b/src/opengl/qgl_qws.cpp @@ -206,6 +206,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) d->eglContext = 0; return false; } + d->sharing = d->eglContext->isSharing(); + if (d->sharing && shareContext) + const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; #if defined(EGL_VERSION_1_1) if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) diff --git a/src/opengl/qgl_wince.cpp b/src/opengl/qgl_wince.cpp index fea2d3af80..2553110102 100644 --- a/src/opengl/qgl_wince.cpp +++ b/src/opengl/qgl_wince.cpp @@ -166,6 +166,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) d->eglContext = 0; return false; } + d->sharing = d->eglContext->isSharing(); + if (d->sharing && shareContext) + const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; #if defined(EGL_VERSION_1_1) if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 9b202976f7..b51c23998c 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -115,6 +115,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) d->eglContext = 0; return false; } + d->sharing = d->eglContext->isSharing(); + if (d->sharing && shareContext) + const_cast<QGLContext *>(shareContext)->d_func()->sharing = true; #if defined(EGL_VERSION_1_1) if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index fcb0ea2ca5..c478630554 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -989,7 +989,7 @@ bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, // ensure GL_LINEAR filtering is used painter->setRenderHint(QPainter::SmoothPixmapTransform); filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), src.rect().translated(0, fbo->height() - src.height())); + engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRectF(0, fbo->height() - targetRect.height(), targetRect.width(), targetRect.height())); filter->removeFromPainter(painter); painter->restore(); diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index f552c7b58a..f6fac88bac 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -89,10 +89,10 @@ public: // Return the VGImage form of this pixmap, creating it if necessary. // This assumes that there is a VG context current. - VGImage toVGImage(); + virtual VGImage toVGImage(); // Return the VGImage form for a specific opacity setting. - VGImage toVGImage(qreal opacity); + virtual VGImage toVGImage(qreal opacity); QSize size() const { return QSize(w, h); } @@ -108,7 +108,7 @@ protected: void cleanup(); #endif -private: +protected: VGImage vgImage; VGImage vgImageOpacity; qreal cachedOpacity; diff --git a/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp b/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp index 8756ecbd27..fb6f5ea7d2 100644 --- a/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp +++ b/src/plugins/graphicssystems/trace/qgraphicssystem_trace.cpp @@ -82,6 +82,7 @@ QTraceWindowSurface::~QTraceWindowSurface() QFile outputFile(QString(QLatin1String("qtgraphics-%0.trace")).arg(winId)); if (outputFile.open(QIODevice::WriteOnly)) { QDataStream out(&outputFile); + out.writeBytes("qttrace", 7); out << *buffer << updates; } delete buffer; diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 6b2f885bbb..54bbcda26b 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -196,52 +196,52 @@ inline QRgb *QImageSmoothScaler::scanLine(const int line, const QImage *src) QImage QImageSmoothScaler::scale() { - long SCALE; - long HALFSCALE; - QRgb *xelrow = 0; - QRgb *tempxelrow = 0; - QRgb *xP; - QRgb *nxP; - int row, rowsread; - int col, needtoreadrow; - uchar maxval = 255; - qreal xscale, yscale; - long sxscale, syscale; - long fracrowtofill, fracrowleft; - long *as; - long *rs; - long *gs; - long *bs; - int rowswritten = 0; - QImage dst; + long SCALE; + long HALFSCALE; + QRgb *xelrow = 0; + QRgb *tempxelrow = 0; + QRgb *xP; + QRgb *nxP; + int row, rowsread; + int col, needtoreadrow; + uchar maxval = 255; + qreal xscale, yscale; + long sxscale, syscale; + long fracrowtofill, fracrowleft; + long *as; + long *rs; + long *gs; + long *bs; + int rowswritten = 0; + QImage dst; if (d->cols > 4096) { - SCALE = 4096; - HALFSCALE = 2048; + SCALE = 4096; + HALFSCALE = 2048; } else { - int fac = 4096; - while (d->cols * fac > 4096) { - fac /= 2; - } + int fac = 4096; + while (d->cols * fac > 4096) + fac /= 2; - SCALE = fac * d->cols; - HALFSCALE = fac * d->cols / 2; + SCALE = fac * d->cols; + HALFSCALE = fac * d->cols / 2; } - xscale = (qreal) d->newcols / (qreal) d->cols; - yscale = (qreal) d->newrows / (qreal) d->rows; + xscale = (qreal)d->newcols / (qreal)d->cols; + yscale = (qreal)d->newrows / (qreal)d->rows; sxscale = (long)(xscale * SCALE); syscale = (long)(yscale * SCALE); - if ( d->newrows != d->rows ) /* shortcut Y scaling if possible */ - tempxelrow = new QRgb[d->cols]; + // shortcut Y scaling if possible + if (d->newrows != d->rows) + tempxelrow = new QRgb[d->cols]; - if ( d->hasAlpha ) { - as = new long[d->cols]; - for ( col = 0; col < d->cols; ++col ) - as[col] = HALFSCALE; + if (d->hasAlpha) { + as = new long[d->cols]; + for (col = 0; col < d->cols; ++col) + as[col] = HALFSCALE; } else { - as = 0; + as = 0; } rs = new long[d->cols]; gs = new long[d->cols]; @@ -249,205 +249,217 @@ QImage QImageSmoothScaler::scale() rowsread = 0; fracrowleft = syscale; needtoreadrow = 1; - for ( col = 0; col < d->cols; ++col ) - rs[col] = gs[col] = bs[col] = HALFSCALE; + for (col = 0; col < d->cols; ++col) + rs[col] = gs[col] = bs[col] = HALFSCALE; fracrowtofill = SCALE; - dst = QImage( d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32 ); - - for ( row = 0; row < d->newrows; ++row ) { - /* First scale Y from xelrow into tempxelrow. */ - if ( d->newrows == d->rows ) { - /* shortcut Y scaling if possible */ - tempxelrow = xelrow = scanLine(rowsread++, d->src); - } else { - while ( fracrowleft < fracrowtofill ) { - if ( needtoreadrow && rowsread < d->rows ) { - xelrow = scanLine(rowsread++, d->src); - } - for ( col = 0, xP = xelrow; col < d->cols; ++col, ++xP ) { - if (as) { - as[col] += fracrowleft * qAlpha( *xP ); - rs[col] += fracrowleft * qRed( *xP ) * qAlpha( *xP ) / 255; - gs[col] += fracrowleft * qGreen( *xP ) * qAlpha( *xP ) / 255; - bs[col] += fracrowleft * qBlue( *xP ) * qAlpha( *xP ) / 255; - } else { - rs[col] += fracrowleft * qRed( *xP ); - gs[col] += fracrowleft * qGreen( *xP ); - bs[col] += fracrowleft * qBlue( *xP ); - } - } - fracrowtofill -= fracrowleft; - fracrowleft = syscale; - needtoreadrow = 1; - } - /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */ - if ( needtoreadrow && rowsread < d->rows) { - xelrow = scanLine(rowsread++, d->src); - needtoreadrow = 0; - } - for ( col = 0, xP = xelrow, nxP = tempxelrow; - col < d->cols; ++col, ++xP, ++nxP ) - { - register long a, r, g, b; - - if ( as ) { - r = rs[col] + fracrowtofill * qRed( *xP ) * qAlpha( *xP ) / 255; - g = gs[col] + fracrowtofill * qGreen( *xP ) * qAlpha( *xP ) / 255; - b = bs[col] + fracrowtofill * qBlue( *xP ) * qAlpha( *xP ) / 255; - a = as[col] + fracrowtofill * qAlpha( *xP ); - if ( a ) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r = rs[col] + fracrowtofill * qRed( *xP ); - g = gs[col] + fracrowtofill * qGreen( *xP ); - b = bs[col] + fracrowtofill * qBlue( *xP ); - a = 0; // unwarn - } - r /= SCALE; - if ( r > maxval ) r = maxval; - g /= SCALE; - if ( g > maxval ) g = maxval; - b /= SCALE; - if ( b > maxval ) b = maxval; - if ( as ) { - a /= SCALE; - if ( a > maxval ) a = maxval; - *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); - as[col] = HALFSCALE; - } else { - *nxP = qRgb( (int)r, (int)g, (int)b ); - } - rs[col] = gs[col] = bs[col] = HALFSCALE; - } - fracrowleft -= fracrowtofill; - if ( fracrowleft == 0 ) { - fracrowleft = syscale; - needtoreadrow = 1; - } - fracrowtofill = SCALE; - } + dst = QImage(d->newcols, d->newrows, d->hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); - /* Now scale X from tempxelrow into dst and write it out. */ - if ( d->newcols == d->cols ) { - /* shortcut X scaling if possible */ - memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols*4); - } else { - register long a, r, g, b; - register long fraccoltofill, fraccolleft = 0; - register int needcol; - - nxP = (QRgb*)dst.scanLine(rowswritten++); - fraccoltofill = SCALE; - a = r = g = b = HALFSCALE; - needcol = 0; - for ( col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP ) { - fraccolleft = sxscale; - while ( fraccolleft >= fraccoltofill ) { - if ( needcol ) { - ++nxP; - a = r = g = b = HALFSCALE; - } - if ( as ) { - r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255; - g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255; - b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255; - a += fraccoltofill * qAlpha( *xP ); - if ( a ) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r += fraccoltofill * qRed( *xP ); - g += fraccoltofill * qGreen( *xP ); - b += fraccoltofill * qBlue( *xP ); - } - r /= SCALE; - if ( r > maxval ) r = maxval; - g /= SCALE; - if ( g > maxval ) g = maxval; - b /= SCALE; - if ( b > maxval ) b = maxval; - if (as) { - a /= SCALE; - if ( a > maxval ) a = maxval; - *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); - } else { - *nxP = qRgb( (int)r, (int)g, (int)b ); - } - fraccolleft -= fraccoltofill; - fraccoltofill = SCALE; - needcol = 1; - } - if ( fraccolleft > 0 ) { - if ( needcol ) { - ++nxP; - a = r = g = b = HALFSCALE; - needcol = 0; - } - if (as) { - a += fraccolleft * qAlpha( *xP ); - r += fraccolleft * qRed( *xP ) * qAlpha( *xP ) / 255; - g += fraccolleft * qGreen( *xP ) * qAlpha( *xP ) / 255; - b += fraccolleft * qBlue( *xP ) * qAlpha( *xP ) / 255; - } else { - r += fraccolleft * qRed( *xP ); - g += fraccolleft * qGreen( *xP ); - b += fraccolleft * qBlue( *xP ); - } - fraccoltofill -= fraccolleft; - } - } - if ( fraccoltofill > 0 ) { - --xP; - if (as) { - a += fraccolleft * qAlpha( *xP ); - r += fraccoltofill * qRed( *xP ) * qAlpha( *xP ) / 255; - g += fraccoltofill * qGreen( *xP ) * qAlpha( *xP ) / 255; - b += fraccoltofill * qBlue( *xP ) * qAlpha( *xP ) / 255; - if ( a ) { - r = r * 255 / a * SCALE; - g = g * 255 / a * SCALE; - b = b * 255 / a * SCALE; - } - } else { - r += fraccoltofill * qRed( *xP ); - g += fraccoltofill * qGreen( *xP ); - b += fraccoltofill * qBlue( *xP ); - } - } - if ( ! needcol ) { - r /= SCALE; - if ( r > maxval ) r = maxval; - g /= SCALE; - if ( g > maxval ) g = maxval; - b /= SCALE; - if ( b > maxval ) b = maxval; - if (as) { - a /= SCALE; - if ( a > maxval ) a = maxval; - *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); - } else { - *nxP = qRgb( (int)r, (int)g, (int)b ); - } - } - } + for (row = 0; row < d->newrows; ++row) { + // First scale Y from xelrow into tempxelrow. + if (d->newrows == d->rows) { + // shortcut Y scaling if possible + tempxelrow = xelrow = scanLine(rowsread++, d->src); + } else { + while (fracrowleft < fracrowtofill) { + if (needtoreadrow && rowsread < d->rows) + xelrow = scanLine(rowsread++, d->src); + for (col = 0, xP = xelrow; col < d->cols; ++col, ++xP) { + if (as) { + as[col] += fracrowleft * qAlpha(*xP); + rs[col] += fracrowleft * qRed(*xP) * qAlpha(*xP) / 255; + gs[col] += fracrowleft * qGreen(*xP) * qAlpha(*xP) / 255; + bs[col] += fracrowleft * qBlue(*xP) * qAlpha(*xP) / 255; + } else { + rs[col] += fracrowleft * qRed(*xP); + gs[col] += fracrowleft * qGreen(*xP); + bs[col] += fracrowleft * qBlue(*xP); + } + } + fracrowtofill -= fracrowleft; + fracrowleft = syscale; + needtoreadrow = 1; + } + // Now fracrowleft is >= fracrowtofill, so we can produce a row. + if (needtoreadrow && rowsread < d->rows) { + xelrow = scanLine(rowsread++, d->src); + needtoreadrow = 0; + } + for (col = 0, xP = xelrow, nxP = tempxelrow; col < d->cols; ++col, ++xP, ++nxP) { + register long a, r, g, b; + + if (as) { + r = rs[col] + fracrowtofill * qRed(*xP) * qAlpha(*xP) / 255; + g = gs[col] + fracrowtofill * qGreen(*xP) * qAlpha(*xP) / 255; + b = bs[col] + fracrowtofill * qBlue(*xP) * qAlpha(*xP) / 255; + a = as[col] + fracrowtofill * qAlpha(*xP); + if (a) { + r = r * 255 / a * SCALE; + g = g * 255 / a * SCALE; + b = b * 255 / a * SCALE; + } + } else { + r = rs[col] + fracrowtofill * qRed(*xP); + g = gs[col] + fracrowtofill * qGreen(*xP); + b = bs[col] + fracrowtofill * qBlue(*xP); + a = 0; // unwarn + } + r /= SCALE; + if (r > maxval) + r = maxval; + g /= SCALE; + if (g > maxval) + g = maxval; + b /= SCALE; + if (b > maxval) + b = maxval; + if (as) { + a /= SCALE; + if (a > maxval) + a = maxval; + *nxP = qRgba((int)r, (int)g, (int)b, (int)a); + as[col] = HALFSCALE; + } else { + *nxP = qRgb((int)r, (int)g, (int)b); + } + rs[col] = gs[col] = bs[col] = HALFSCALE; + } + fracrowleft -= fracrowtofill; + if (fracrowleft == 0) { + fracrowleft = syscale; + needtoreadrow = 1; + } + fracrowtofill = SCALE; + } + + // Now scale X from tempxelrow into dst and write it out. + if (d->newcols == d->cols) { + // shortcut X scaling if possible + memcpy(dst.scanLine(rowswritten++), tempxelrow, d->newcols * 4); + } else { + register long a, r, g, b; + register long fraccoltofill, fraccolleft = 0; + register int needcol; + + nxP = (QRgb *)dst.scanLine(rowswritten++); + QRgb *nxPEnd = nxP + d->newcols; + fraccoltofill = SCALE; + a = r = g = b = HALFSCALE; + needcol = 0; + for (col = 0, xP = tempxelrow; col < d->cols; ++col, ++xP) { + fraccolleft = sxscale; + while (fraccolleft >= fraccoltofill) { + if (needcol) { + ++nxP; + a = r = g = b = HALFSCALE; + } + if (as) { + r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; + g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; + b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; + a += fraccoltofill * qAlpha(*xP); + if (a) { + r = r * 255 / a * SCALE; + g = g * 255 / a * SCALE; + b = b * 255 / a * SCALE; + } + } else { + r += fraccoltofill * qRed(*xP); + g += fraccoltofill * qGreen(*xP); + b += fraccoltofill * qBlue(*xP); + } + r /= SCALE; + if (r > maxval) + r = maxval; + g /= SCALE; + if (g > maxval) + g = maxval; + b /= SCALE; + if (b > maxval) + b = maxval; + if (as) { + a /= SCALE; + if (a > maxval) + a = maxval; + *nxP = qRgba((int)r, (int)g, (int)b, (int)a); + } else { + *nxP = qRgb((int)r, (int)g, (int)b); + } + fraccolleft -= fraccoltofill; + fraccoltofill = SCALE; + needcol = 1; + } + if (fraccolleft > 0) { + if (needcol) { + ++nxP; + a = r = g = b = HALFSCALE; + needcol = 0; + } + if (as) { + a += fraccolleft * qAlpha(*xP); + r += fraccolleft * qRed(*xP) * qAlpha(*xP) / 255; + g += fraccolleft * qGreen(*xP) * qAlpha(*xP) / 255; + b += fraccolleft * qBlue(*xP) * qAlpha(*xP) / 255; + } else { + r += fraccolleft * qRed(*xP); + g += fraccolleft * qGreen(*xP); + b += fraccolleft * qBlue(*xP); + } + fraccoltofill -= fraccolleft; + } + } + if (fraccoltofill > 0) { + --xP; + if (as) { + a += fraccolleft * qAlpha(*xP); + r += fraccoltofill * qRed(*xP) * qAlpha(*xP) / 255; + g += fraccoltofill * qGreen(*xP) * qAlpha(*xP) / 255; + b += fraccoltofill * qBlue(*xP) * qAlpha(*xP) / 255; + if (a) { + r = r * 255 / a * SCALE; + g = g * 255 / a * SCALE; + b = b * 255 / a * SCALE; + } + } else { + r += fraccoltofill * qRed(*xP); + g += fraccoltofill * qGreen(*xP); + b += fraccoltofill * qBlue(*xP); + } + } + if (nxP < nxPEnd) { + r /= SCALE; + if (r > maxval) + r = maxval; + g /= SCALE; + if (g > maxval) + g = maxval; + b /= SCALE; + if (b > maxval) + b = maxval; + if (as) { + a /= SCALE; + if (a > maxval) + a = maxval; + *nxP = qRgba((int)r, (int)g, (int)b, (int)a); + } else { + *nxP = qRgb((int)r, (int)g, (int)b); + } + while (++nxP != nxPEnd) + nxP[0] = nxP[-1]; + } + } } - if ( d->newrows != d->rows && tempxelrow )// Robust, tempxelrow might be 0 1 day - delete [] tempxelrow; - if ( as ) // Avoid purify complaint - delete [] as; - if ( rs ) // Robust, rs might be 0 one day - delete [] rs; - if ( gs ) // Robust, gs might be 0 one day - delete [] gs; - if ( bs ) // Robust, bs might be 0 one day - delete [] bs; + if (d->newrows != d->rows && tempxelrow)// Robust, tempxelrow might be 0 1 day + delete [] tempxelrow; + if (as) // Avoid purify complaint + delete [] as; + if (rs) // Robust, rs might be 0 one day + delete [] rs; + if (gs) // Robust, gs might be 0 one day + delete [] gs; + if (bs) // Robust, bs might be 0 one day + delete [] bs; return dst; } diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 3669be708f..9538745293 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -192,7 +192,14 @@ bool QTiffHandler::read(QImage *image) return false; } - if (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) { + uint16 bitPerSample; + if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) { + TIFFClose(tiff); + return false; + } + + bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE; + if (grayscale && bitPerSample == 1) { if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono) *image = QImage(width, height, QImage::Format_Mono); QVector<QRgb> colortable(2); @@ -208,42 +215,43 @@ bool QTiffHandler::read(QImage *image) if (!image->isNull()) { for (uint32 y=0; y<height; ++y) { if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) { - TIFFClose(tiff); - return false; + TIFFClose(tiff); + return false; } } } } else { - uint16 bitPerSample; - if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) { - TIFFClose(tiff); - return false; - } - if (photometric == PHOTOMETRIC_PALETTE && bitPerSample == 8) { + if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) { if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8) *image = QImage(width, height, QImage::Format_Indexed8); if (!image->isNull()) { - // create the color table const uint16 tableSize = 256; - uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { - TIFFClose(tiff); - return false; - } - QVector<QRgb> qtColorTable(tableSize); - for (int i = 0; i<tableSize ;++i) { - const int red = redTable[i] / 257; - const int green = greenTable[i] / 257; - const int blue = blueTable[i] / 257; - qtColorTable[i] = qRgb(red, green, blue); + if (grayscale) { + for (int i = 0; i<tableSize; ++i) { + const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i); + qtColorTable[i] = qRgb(c, c, c); + } + } else { + // create the color table + uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); + uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); + uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); + if (!redTable || !greenTable || !blueTable) { + TIFFClose(tiff); + return false; + } + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { + TIFFClose(tiff); + return false; + } + for (int i = 0; i<tableSize ;++i) { + const int red = redTable[i] / 257; + const int green = greenTable[i] / 257; + const int blue = blueTable[i] / 257; + qtColorTable[i] = qRgb(red, green, blue); + } } image->setColorTable(qtColorTable); @@ -371,6 +379,20 @@ bool QTiffHandler::read(QImage *image) return true; } +static bool checkGrayscale(const QVector<QRgb> &colorTable) +{ + if (colorTable.size() != 256) + return false; + + const bool increasing = (colorTable.at(0) == 0xff000000); + for (int i = 0; i < 256; ++i) { + if (increasing && colorTable.at(i) != qRgb(i, i, i) + || !increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i)) + return false; + } + return true; +} + bool QTiffHandler::write(const QImage &image) { if (!device()->isWritable()) @@ -425,7 +447,8 @@ bool QTiffHandler::write(const QImage &image) if (image.colorTable().at(0) == 0xffffffff) photometric = PHOTOMETRIC_MINISWHITE; if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)) { + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) { TIFFClose(tiff); return false; } @@ -450,43 +473,55 @@ bool QTiffHandler::write(const QImage &image) } TIFFClose(tiff); } else if (format == QImage::Format_Indexed8) { - if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) - || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) - || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { - TIFFClose(tiff); - return false; - } - //// write the color table - // allocate the color tables - uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { - TIFFClose(tiff); - return false; - } - - // set the color table const QVector<QRgb> colorTable = image.colorTable(); + bool isGrayscale = checkGrayscale(colorTable); + if (isGrayscale) { + uint16 photometric = PHOTOMETRIC_MINISBLACK; + if (image.colorTable().at(0) == 0xffffffff) + photometric = PHOTOMETRIC_MINISWHITE; + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFFClose(tiff); + return false; + } + } else { + if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE) + || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) + || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) { + TIFFClose(tiff); + return false; + } + //// write the color table + // allocate the color tables + uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); + uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); + uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); + if (!redTable || !greenTable || !blueTable) { + TIFFClose(tiff); + return false; + } - const int tableSize = colorTable.size(); - Q_ASSERT(tableSize <= 256); - for (int i = 0; i<tableSize; ++i) { - const QRgb color = colorTable.at(i); - redTable[i] = qRed(color) * 257; - greenTable[i] = qGreen(color) * 257; - blueTable[i] = qBlue(color) * 257; - } + // set the color table + const int tableSize = colorTable.size(); + Q_ASSERT(tableSize <= 256); + for (int i = 0; i<tableSize; ++i) { + const QRgb color = colorTable.at(i); + redTable[i] = qRed(color) * 257; + greenTable[i] = qGreen(color) * 257; + blueTable[i] = qBlue(color) * 257; + } - const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable); + const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable); - qFree(redTable); - qFree(greenTable); - qFree(blueTable); + qFree(redTable); + qFree(greenTable); + qFree(blueTable); - if (!setColorTableSuccess) { - TIFFClose(tiff); - return false; + if (!setColorTableSuccess) { + TIFFClose(tiff); + return false; + } } //// write the data diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index f834016abf..57927fdca6 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -363,7 +363,10 @@ void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraSt if (m_strokeMiterLimitSet) pen.setMiterLimit(m_stroke.miterLimit()); - if (setDashOffsetNeeded) { + // You can have dash offset on solid strokes in SVG files, but not in Qt. + // QPen::setDashOffset() will set the pen style to Qt::CustomDashLine, + // so don't call the method if the pen is solid. + if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) { qreal currentWidth = pen.widthF(); if (currentWidth == 0) currentWidth = 1; diff --git a/src/xmlpatterns/data/qderivedinteger_p.h b/src/xmlpatterns/data/qderivedinteger_p.h index 859e03de4c..19dc4c4e6f 100644 --- a/src/xmlpatterns/data/qderivedinteger_p.h +++ b/src/xmlpatterns/data/qderivedinteger_p.h @@ -401,18 +401,18 @@ namespace QPatternist { return ValidationError::createError(QtXmlPatterns::tr( "Value %1 of type %2 exceeds maximum (%3).") - .arg(formatData(static_cast<xsInteger>(num))) + .arg(QPatternist::formatData(static_cast<xsInteger>(num))) .arg(formatType(np, itemType())) - .arg(formatData(static_cast<xsInteger>(maxInclusive)))); + .arg(QPatternist::formatData(static_cast<xsInteger>(maxInclusive)))); } else if((limitsUsage & LimitDownwards) && lessThan(num, minimum)) { return ValidationError::createError(QtXmlPatterns::tr( "Value %1 of type %2 is below minimum (%3).") - .arg(formatData(static_cast<xsInteger>(num))) + .arg(QPatternist::formatData(static_cast<xsInteger>(num))) .arg(formatType(np, itemType())) - .arg(formatData(static_cast<xsInteger>(minInclusive)))); + .arg(QPatternist::formatData(static_cast<xsInteger>(minInclusive)))); } else return AtomicValue::Ptr(new DerivedInteger(num)); diff --git a/src/xmlpatterns/functions/qcomparingaggregator.cpp b/src/xmlpatterns/functions/qcomparingaggregator.cpp index 6d07109fb6..acda08c5bc 100644 --- a/src/xmlpatterns/functions/qcomparingaggregator.cpp +++ b/src/xmlpatterns/functions/qcomparingaggregator.cpp @@ -195,7 +195,7 @@ ComparingAggregator<oper, result>::typeCheck(const StaticContext::Ptr &context, !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1)) { context->error(QtXmlPatterns::tr("The first argument to %1 cannot be of type %2.") - .arg(formatFunction(context->namePool(), signature())) + .arg(QPatternist::formatFunction(context->namePool(), signature())) .arg(formatType(context->namePool(), m_operands.first()->staticType())), ReportContext::FORG0006, this); return me; diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index c680decc01..ccb08c3904 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -76,6 +76,7 @@ private slots: void partialGLWidgetUpdates_data(); void partialGLWidgetUpdates(); void glWidgetRendering(); + void glFBOSimpleRendering(); void glFBORendering(); void multipleFBOInterleavedRendering(); void glFBOUseInGLWidget(); @@ -711,6 +712,79 @@ void tst_QGL::openGLVersionCheck() #endif //QT_BUILD_INTERNAL } +static bool fuzzyComparePixels(const QRgb testPixel, const QRgb refPixel, const char* file, int line, int x = -1, int y = -1) +{ + static int maxFuzz = 1; + static bool maxFuzzSet = false; + + // On 16 bpp systems, we need to allow for more fuzz: + if (!maxFuzzSet) { + maxFuzzSet = true; + if (appDefaultDepth() < 24) + maxFuzz = 32; + } + + int redFuzz = qAbs(qRed(testPixel) - qRed(refPixel)); + int greenFuzz = qAbs(qGreen(testPixel) - qGreen(refPixel)); + int blueFuzz = qAbs(qBlue(testPixel) - qBlue(refPixel)); + int alphaFuzz = qAbs(qAlpha(testPixel) - qAlpha(refPixel)); + + if (refPixel != 0 && testPixel == 0) { + QString msg; + if (x >= 0) { + msg = QString("Test pixel [%1, %2] is null (black) when it should be (%3,%4,%5,%6)") + .arg(x).arg(y) + .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel)); + } else { + msg = QString("Test pixel is null (black) when it should be (%2,%3,%4,%5)") + .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel)); + } + + QTest::qFail(msg.toLatin1(), file, line); + return false; + } + + if (redFuzz > maxFuzz || greenFuzz > maxFuzz || blueFuzz > maxFuzz || alphaFuzz > maxFuzz) { + QString msg; + + if (x >= 0) + msg = QString("Pixel [%1,%2]: ").arg(x).arg(y); + else + msg = QString("Pixel "); + + msg += QString("Max fuzz (%1) exceeded: (%2,%3,%4,%5) vs (%6,%7,%8,%9)") + .arg(maxFuzz) + .arg(qRed(testPixel)).arg(qGreen(testPixel)).arg(qBlue(testPixel)).arg(qAlpha(testPixel)) + .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel)); + QTest::qFail(msg.toLatin1(), file, line); + return false; + } + return true; +} + +static void fuzzyCompareImages(const QImage &testImage, const QImage &referenceImage, const char* file, int line) +{ + QCOMPARE(testImage.width(), referenceImage.width()); + QCOMPARE(testImage.height(), referenceImage.height()); + + for (int y = 0; y < testImage.height(); y++) { + for (int x = 0; x < testImage.width(); x++) { + if (!fuzzyComparePixels(testImage.pixel(x, y), referenceImage.pixel(x, y), file, line, x, y)) { + // Might as well save the images for easier debugging: + referenceImage.save("referenceImage.png"); + testImage.save("testImage.png"); + return; + } + } + } +} + +#define QFUZZY_COMPARE_IMAGES(A,B) \ + fuzzyCompareImages(A, B, __FILE__, __LINE__) + +#define QFUZZY_COMPARE_PIXELS(A,B) \ + fuzzyComparePixels(A, B, __FILE__, __LINE__) + class UnclippedWidget : public QWidget { public: @@ -723,8 +797,6 @@ public: void tst_QGL::graphicsViewClipping() { - if (appDefaultDepth() < 24) - QSKIP("This test won't work for bit depths < 24", SkipAll); const int size = 64; UnclippedWidget *widget = new UnclippedWidget; widget->setFixedSize(size, size); @@ -734,6 +806,9 @@ void tst_QGL::graphicsViewClipping() scene.addWidget(widget)->setPos(0, 0); QGraphicsView view(&scene); +#ifdef Q_WS_QWS + view.setWindowFlags(Qt::FramelessWindowHint); +#endif view.resize(2*size, 2*size); QGLWidget *viewport = new QGLWidget; @@ -758,7 +833,7 @@ void tst_QGL::graphicsViewClipping() p.fillRect(QRect(0, 0, size, size), Qt::black); p.end(); - QCOMPARE(image, expected); + QFUZZY_COMPARE_IMAGES(image, expected); } void tst_QGL::partialGLWidgetUpdates_data() @@ -849,7 +924,7 @@ void tst_QGL::glPBufferRendering() p.fillRect(32, 32, 64, 64, Qt::blue); p.end(); - QCOMPARE(fb, reference); + QFUZZY_COMPARE_IMAGES(fb, reference); } class GLWidget : public QGLWidget @@ -868,8 +943,8 @@ public: // This test only ensures it's possible to paint onto a QGLWidget. Full // paint engine feature testing is way out of scope! + p.fillRect(-1, -1, width()+2, height()+2, Qt::red); - p.fillRect(0, 0, width(), height(), Qt::red); // No p.end() or swap buffers, should be done automatically } @@ -877,9 +952,11 @@ public: void tst_QGL::glWidgetRendering() { - if (appDefaultDepth() < 24) - QSKIP("This test won't work for bit depths < 24", SkipAll); GLWidget w; +#ifdef Q_WS_QWS + w.setWindowFlags(Qt::FramelessWindowHint); +#endif + w.setGeometry(100, 100, 200, 200); w.show(); #ifdef Q_WS_X11 @@ -894,7 +971,37 @@ void tst_QGL::glWidgetRendering() QImage reference(fb.size(), QImage::Format_RGB32); reference.fill(0xffff0000); - QCOMPARE(fb, reference); + QFUZZY_COMPARE_IMAGES(fb, reference); +} + +void tst_QGL::glFBOSimpleRendering() +{ + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) + QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle); + + QGLWidget glw; + glw.makeCurrent(); + + // No multisample with combined depth/stencil attachment: + QGLFramebufferObjectFormat fboFormat; + fboFormat.setAttachment(QGLFramebufferObject::NoAttachment); + + // Don't complicate things by using NPOT: + QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat); + + fbo->bind(); + + glClearColor(1.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glFinish(); + + QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32); + QImage reference(fb.size(), QImage::Format_RGB32); + reference.fill(0xffff0000); + + QFUZZY_COMPARE_IMAGES(fb, reference); + + delete fbo; } // NOTE: This tests that CombinedDepthStencil attachment works by assuming the @@ -949,14 +1056,14 @@ void tst_QGL::glFBORendering() // As we're doing more than trivial painting, we can't just compare to // an image rendered with raster. Instead, we sample at well-defined // test-points: - QCOMPARE(fb.pixel(39, 64), QColor(Qt::red).rgb()); - QCOMPARE(fb.pixel(89, 64), QColor(Qt::red).rgb()); - QCOMPARE(fb.pixel(64, 39), QColor(Qt::blue).rgb()); - QCOMPARE(fb.pixel(64, 89), QColor(Qt::blue).rgb()); - - QCOMPARE(fb.pixel(167, 39), QColor(Qt::red).rgb()); - QCOMPARE(fb.pixel(217, 39), QColor(Qt::red).rgb()); - QCOMPARE(fb.pixel(192, 64), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb.pixel(39, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb.pixel(89, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb.pixel(64, 39), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb.pixel(64, 89), QColor(Qt::blue).rgb()); + + QFUZZY_COMPARE_PIXELS(fb.pixel(167, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb.pixel(217, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb.pixel(192, 64), QColor(Qt::green).rgb()); } @@ -1047,29 +1154,29 @@ void tst_QGL::multipleFBOInterleavedRendering() // As we're doing more than trivial painting, we can't just compare to // an image rendered with raster. Instead, we sample at well-defined // test-points: - QCOMPARE(fb1.pixel(39, 64), QColor(Qt::red).rgb()); - QCOMPARE(fb1.pixel(89, 64), QColor(Qt::red).rgb()); - QCOMPARE(fb1.pixel(64, 39), QColor(Qt::blue).rgb()); - QCOMPARE(fb1.pixel(64, 89), QColor(Qt::blue).rgb()); - QCOMPARE(fb1.pixel(167, 39), QColor(Qt::red).rgb()); - QCOMPARE(fb1.pixel(217, 39), QColor(Qt::red).rgb()); - QCOMPARE(fb1.pixel(192, 64), QColor(Qt::green).rgb()); - - QCOMPARE(fb2.pixel(39, 64), QColor(Qt::green).rgb()); - QCOMPARE(fb2.pixel(89, 64), QColor(Qt::green).rgb()); - QCOMPARE(fb2.pixel(64, 39), QColor(Qt::red).rgb()); - QCOMPARE(fb2.pixel(64, 89), QColor(Qt::red).rgb()); - QCOMPARE(fb2.pixel(167, 39), QColor(Qt::green).rgb()); - QCOMPARE(fb2.pixel(217, 39), QColor(Qt::green).rgb()); - QCOMPARE(fb2.pixel(192, 64), QColor(Qt::blue).rgb()); - - QCOMPARE(fb3.pixel(39, 64), QColor(Qt::blue).rgb()); - QCOMPARE(fb3.pixel(89, 64), QColor(Qt::blue).rgb()); - QCOMPARE(fb3.pixel(64, 39), QColor(Qt::green).rgb()); - QCOMPARE(fb3.pixel(64, 89), QColor(Qt::green).rgb()); - QCOMPARE(fb3.pixel(167, 39), QColor(Qt::blue).rgb()); - QCOMPARE(fb3.pixel(217, 39), QColor(Qt::blue).rgb()); - QCOMPARE(fb3.pixel(192, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(39, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(89, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 39), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 89), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(167, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(217, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb1.pixel(192, 64), QColor(Qt::green).rgb()); + + QFUZZY_COMPARE_PIXELS(fb2.pixel(39, 64), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb2.pixel(89, 64), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 89), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(fb2.pixel(167, 39), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb2.pixel(217, 39), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb2.pixel(192, 64), QColor(Qt::blue).rgb()); + + QFUZZY_COMPARE_PIXELS(fb3.pixel(39, 64), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb3.pixel(89, 64), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 39), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 89), QColor(Qt::green).rgb()); + QFUZZY_COMPARE_PIXELS(fb3.pixel(167, 39), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb3.pixel(217, 39), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(fb3.pixel(192, 64), QColor(Qt::red).rgb()); } class FBOUseInGLWidget : public QGLWidget @@ -1089,11 +1196,11 @@ protected: QPainter fboPainter; fboPainterBeginOk = fboPainter.begin(fbo); - fboPainter.fillRect(0, 0, 128, 128, Qt::red); + fboPainter.fillRect(-1, -1, 130, 130, Qt::red); fboPainter.end(); fboImage = fbo->toImage(); - widgetPainter.fillRect(rect(), Qt::blue); + widgetPainter.fillRect(-1, -1, width()+2, width()+2, Qt::blue); delete fbo; } @@ -1102,12 +1209,13 @@ protected: void tst_QGL::glFBOUseInGLWidget() { - if (appDefaultDepth() < 24) - QSKIP("This test won't work for bit depths < 24", SkipAll); if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle); FBOUseInGLWidget w; +#ifdef Q_WS_QWS + w.setWindowFlags(Qt::FramelessWindowHint); +#endif w.resize(128, 128); w.show(); @@ -1122,17 +1230,15 @@ void tst_QGL::glFBOUseInGLWidget() QImage widgetFB = w.grabFrameBuffer(false); QImage widgetReference(widgetFB.size(), widgetFB.format()); widgetReference.fill(0xff0000ff); - QCOMPARE(widgetFB, widgetReference); + QFUZZY_COMPARE_IMAGES(widgetFB, widgetReference); QImage fboReference(w.fboImage.size(), w.fboImage.format()); fboReference.fill(0xffff0000); - QCOMPARE(w.fboImage, fboReference); + QFUZZY_COMPARE_IMAGES(w.fboImage, fboReference); } void tst_QGL::glWidgetReparent() { - if (appDefaultDepth() < 24) - QSKIP("This test won't work for bit depths < 24", SkipAll); // Try it as a top-level first: GLWidget *widget = new GLWidget; widget->setGeometry(0, 0, 200, 30); @@ -1222,7 +1328,7 @@ void tst_QGL::glWidgetRenderPixmap() QImage reference(fb.size(), QImage::Format_RGB32); reference.fill(0xffff0000); - QCOMPARE(fb, reference); + QFUZZY_COMPARE_IMAGES(fb, reference); } class ColormapExtended : public QGLColormap @@ -1495,9 +1601,10 @@ protected: void tst_QGL::replaceClipping() { - if (appDefaultDepth() < 24) - QSKIP("This test won't work for bit depths < 24", SkipAll); ReplaceClippingGLWidget glw; +#ifdef Q_WS_QWS + glw.setWindowFlags(Qt::FramelessWindowHint); +#endif glw.resize(300, 300); glw.show(); @@ -1513,7 +1620,13 @@ void tst_QGL::replaceClipping() const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32); - QCOMPARE(widgetFB, reference); + // Sample pixels in a grid pattern which avoids false failures due to + // off-by-one pixel errors on some buggy GL implementations + for (int x = 25; x < reference.width(); x += 50) { + for (int y = 25; y < reference.width(); y += 50) { + QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y)); + } + } } class ClipTestGLWidget : public QGLWidget @@ -1521,7 +1634,7 @@ class ClipTestGLWidget : public QGLWidget public: void paint(QPainter *painter) { - painter->fillRect(rect(), Qt::white); + painter->fillRect(-1, -1, width()+2, height()+2, Qt::white); painter->setClipRect(10, 10, width()-20, height()-20); painter->fillRect(rect(), Qt::cyan); @@ -1622,9 +1735,10 @@ protected: void tst_QGL::clipTest() { - if (appDefaultDepth() < 24) - QSKIP("This test won't work for bit depths < 24", SkipAll); ClipTestGLWidget glw; +#ifdef Q_WS_QWS + glw.setWindowFlags(Qt::FramelessWindowHint); +#endif glw.resize(220, 220); glw.show(); @@ -1640,7 +1754,13 @@ void tst_QGL::clipTest() const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32); - QCOMPARE(widgetFB, reference); + // Sample pixels in a grid pattern which avoids false failures due to + // off-by-one pixel errors on some buggy GL implementations + for (int x = 2; x < reference.width(); x += 5) { + for (int y = 2; y < reference.width(); y += 5) { + QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y)); + } + } } void tst_QGL::destroyFBOAfterContext() @@ -1728,6 +1848,7 @@ void tst_QGL::shareRegister() delete glw1; QSKIP("Context sharing is not supported", SkipSingle); } + QVERIFY(glw1->isSharing()); QVERIFY(glw1->context() != glw2->context()); // Check that the first context's resource is also on the second. diff --git a/tests/auto/qimagereader/images/grayscale-ref.tif b/tests/auto/qimagereader/images/grayscale-ref.tif Binary files differnew file mode 100644 index 0000000000..960531ea86 --- /dev/null +++ b/tests/auto/qimagereader/images/grayscale-ref.tif diff --git a/tests/auto/qimagereader/images/grayscale.tif b/tests/auto/qimagereader/images/grayscale.tif Binary files differnew file mode 100644 index 0000000000..5f4e11429d --- /dev/null +++ b/tests/auto/qimagereader/images/grayscale.tif diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 05b506ce1e..15b1c1c540 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -157,6 +157,8 @@ private slots: void tiffOrientation_data(); void tiffOrientation(); + + void tiffGrayscale(); #endif void autoDetectImageFormat(); @@ -1376,6 +1378,13 @@ void tst_QImageReader::tiffOrientation() QCOMPARE(expectedImage, orientedImage); } +void tst_QImageReader::tiffGrayscale() +{ + QImage actualImage(prefix + "grayscale.tif"); + QImage expectedImage(prefix + "grayscale-ref.tif"); + + QCOMPARE(expectedImage, actualImage.convertToFormat(expectedImage.format())); +} #endif void tst_QImageReader::dotsPerMeter_data() diff --git a/tests/auto/qimagewriter/tst_qimagewriter.cpp b/tests/auto/qimagewriter/tst_qimagewriter.cpp index ab5572dc58..5997f39924 100644 --- a/tests/auto/qimagewriter/tst_qimagewriter.cpp +++ b/tests/auto/qimagewriter/tst_qimagewriter.cpp @@ -391,16 +391,27 @@ void tst_QImageWriter::readWriteNonDestructive_data() { QTest::addColumn<QImage::Format>("format"); QTest::addColumn<QImage::Format>("expectedFormat"); - QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono; - QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8; - QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32; + QTest::addColumn<bool>("grayscale"); + QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << false; + QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << false; + QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32 << false; + QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true; } void tst_QImageWriter::readWriteNonDestructive() { QFETCH(QImage::Format, format); QFETCH(QImage::Format, expectedFormat); + QFETCH(bool, grayscale); QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format); + + if (grayscale) { + QVector<QRgb> colors; + for (int i = 0; i < 256; ++i) + colors << qRgb(i, i, i); + image.setColorTable(colors); + } + QVERIFY(image.save(prefix + "gen-readWriteNonDestructive.tiff")); QImage image2 = QImage(prefix + "gen-readWriteNonDestructive.tiff"); diff --git a/tests/auto/qpixmapfilter/tst_qpixmapfilter.cpp b/tests/auto/qpixmapfilter/tst_qpixmapfilter.cpp index a80c7878c9..751c7dcb24 100644 --- a/tests/auto/qpixmapfilter/tst_qpixmapfilter.cpp +++ b/tests/auto/qpixmapfilter/tst_qpixmapfilter.cpp @@ -407,7 +407,7 @@ void tst_QPixmapFilter::dropShadowBoundingRectFor() filter.setBlurRadius(2); filter.setOffset(QPointF(0,0)); - int delta = 2 * 2; + qreal delta = 2; QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta, -delta, delta, delta)); QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta, -delta, delta, delta)); QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta, -delta, delta, delta)); diff --git a/tools/qttracereplay/main.cpp b/tools/qttracereplay/main.cpp index 1d21a21324..7261082b15 100644 --- a/tools/qttracereplay/main.cpp +++ b/tools/qttracereplay/main.cpp @@ -56,7 +56,7 @@ public: public slots: void updateRect(); -private: +public: QList<QRegion> updates; QPaintBuffer buffer; @@ -70,7 +70,8 @@ private: void ReplayWidget::updateRect() { - update(updates.at(currentFrame)); + if (!updates.isEmpty()) + update(updates.at(currentFrame)); } void ReplayWidget::paintEvent(QPaintEvent *) @@ -138,12 +139,25 @@ ReplayWidget::ReplayWidget(const QString &filename_) QFile file(filename); QRect bounds; - if (file.open(QIODevice::ReadOnly)) { - QDataStream in(&file); - in >> buffer >> updates; + if (!file.open(QIODevice::ReadOnly)) { + printf("Failed to load input file '%s'\n", qPrintable(filename_)); + return; + } + + QDataStream in(&file); + + char *data; + uint size; + in.readBytes(data, size); + bool isTraceFile = size == 7 && qstrncmp(data, "qttrace", 7) == 0; + delete [] data; + if (!isTraceFile) { + printf("File '%s' is not a trace file\n", qPrintable(filename_)); + return; } - qDebug() << "Read paint buffer with" << buffer.numFrames() << "frames"; + in >> buffer >> updates; + printf("Read paint buffer with %d frames\n", buffer.numFrames()); resize(buffer.boundingRect().size().toSize()); @@ -157,14 +171,18 @@ int main(int argc, char **argv) { QApplication app(argc, argv); - if (argc <= 1) { - printf("Usage: %s filename\n", argv[0]); + if (argc <= 1 || qstrcmp(argv[1], "-h") == 0 || qstrcmp(argv[1], "--help") == 0) { + printf("Replays a tracefile generated with '-graphicssystem trace'\n"); + printf("Usage:\n > %s [traceFile]\n", argv[0]); return 1; } ReplayWidget *widget = new ReplayWidget(argv[1]); - widget->show(); - return app.exec(); + if (!widget->updates.isEmpty()) { + widget->show(); + return app.exec(); + } + } #include "main.moc" diff --git a/tools/qttracereplay/qttracereplay.pro b/tools/qttracereplay/qttracereplay.pro index 766ed0401d..cc5b98dc0c 100644 --- a/tools/qttracereplay/qttracereplay.pro +++ b/tools/qttracereplay/qttracereplay.pro @@ -11,3 +11,5 @@ SOURCES += main.cpp target.path=$$[QT_INSTALL_BINS] INSTALLS += target + +CONFIG += console |