summaryrefslogtreecommitdiffstats
path: root/Python/getversion.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/getversion.c')
0 files changed, 0 insertions, 0 deletions
SE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstatictext.h" +#include "qstatictext_p.h" + +QT_BEGIN_NAMESPACE + +QStaticText::QStaticText(const QString &text, const QFont &font) + : d_ptr(new QStaticTextPrivate) +{ + Q_D(QStaticText); + d->init(text, font); +} + +QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) +{ + return q->d_ptr; +} + +void QStaticTextPrivate::init(const QString &text, const QFont &font) +{ + engine.text = text; + engine.fnt = font; + + /*engine.option.setTextDirection(d->state->layoutDirection); + if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) { + engine.ignoreBidi = true; + engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft); + }*/ + + engine.itemize(); + QScriptLine line; + line.length = text.length(); + engine.shapeLine(line); + + int nItems = engine.layoutData->items.size(); + visualOrder = QVarLengthArray(nItems); + QVarLengthArray levels(nItems); + for (int i = 0; i < nItems; ++i) + levels[i] = engine.layoutData->items[i].analysis.bidiLevel; + QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + + /*if (justificationPadding > 0) { + engine.option.setAlignment(Qt::AlignJustify); + engine.forceJustification = true; + // this works because justify() is only interested in the difference between width and textWidth + line.width = justificationPadding; + engine.justify(line); + }*/ +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h new file mode 100644 index 0000000..4d39e23 --- /dev/null +++ b/src/gui/text/qstatictext.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATICTEXT_H +#define QSTATICTEXT_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStaticTextPrivate; +class Q_GUI_EXPORT QStaticText +{ + Q_DECLARE_PRIVATE(QStaticText); +public: + QStaticText(const QString &text, const QFont &font); + +private: + QStaticTextPrivate *d_ptr; +}; + +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..ad70b1e --- /dev/null +++ b/src/gui/text/qstatictext_p.h @@ -0,0 +1,22 @@ +#ifndef QSTATICTEXT_P_H +#define QSTATICTEXT_P_H + +QT_BEGIN_NAMESPACE + +#include + +class QStaticText; +class QStaticTextPrivate +{ +public: + void init(const QString &text, const QFont &font); + + QTextEngine engine; + QVarLengthArray visualOrder; + + static QStaticTextPrivate *get(const QStaticText *q); +}; + +QT_END_NAMESPACE + +#endif // QSTATICTEXT_P_H diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index b7615a4..026e6c6 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.h \ + text/qstatictext_p.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 += \ -- cgit v0.12 From 26372057d92564da9baf6d17c685fd1b22ff4b8a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 19 May 2009 16:48:16 +0200 Subject: Simplify QStaticText Not much to gain by going directly to the QTextEngine, and the code is a lot simpler if we just use the QTextLayout instead. --- src/gui/painting/qpainter.cpp | 27 ++------------------------- src/gui/text/qstatictext.cpp | 42 +++++++++++++++++------------------------- src/gui/text/qstatictext_p.h | 4 ++-- 3 files changed, 21 insertions(+), 52 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index f5bd2c5..a890d63 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5707,32 +5707,9 @@ void QPainter::drawText(const QPointF &p, const QString &str) void QPainter::drawStaticText(const QPointF &p, const QStaticText &staticText) { const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); - const QTextEngine &engine = staticText_d->engine; - const QVarLengthArray &visualOrder = staticText_d->visualOrder; + QTextLayout *textLayout = staticText_d->textLayout; - QFixed x = QFixed::fromReal(p.x()); - QFixed ox = x; - - int nItems = engine.layoutData->items.size(); - for (int i = 0; i < nItems; ++i) { - int item = visualOrder[i]; - const QScriptItem &si = engine.layoutData->items.at(item); - if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { - x += si.width; - continue; - } - QFont f = engine.font(si); - QTextItemInt gf(si, &f); - gf.glyphs = engine.shapedGlyphs(&si); - gf.chars = engine.layoutData->string.unicode() + si.position; - gf.num_chars = engine.length(item); - gf.width = si.width; - gf.logClusters = engine.logClusters(&si); - - drawTextItem(QPointF(x.toReal(), p.y()), gf); - - x += si.width; - } + textLayout->draw(this, p); } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 90b1145..bb83fd1 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -51,6 +51,11 @@ QStaticText::QStaticText(const QString &text, const QFont &font) d->init(text, font); } +QStaticTextPrivate::QStaticTextPrivate() + : textLayout(0) +{ +} + QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) { return q->d_ptr; @@ -58,34 +63,21 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) void QStaticTextPrivate::init(const QString &text, const QFont &font) { - engine.text = text; - engine.fnt = font; - - /*engine.option.setTextDirection(d->state->layoutDirection); - if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) { - engine.ignoreBidi = true; - engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft); - }*/ + Q_ASSERT(textLayout == 0); + textLayout = new QTextLayout(text, font); + textLayout->setCacheEnabled(true); - engine.itemize(); - QScriptLine line; - line.length = text.length(); - engine.shapeLine(line); + QFontMetrics fontMetrics(font); - int nItems = engine.layoutData->items.size(); - visualOrder = QVarLengthArray(nItems); - QVarLengthArray levels(nItems); - for (int i = 0; i < nItems; ++i) - levels[i] = engine.layoutData->items[i].analysis.bidiLevel; - QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + textLayout->beginLayout(); + int h = fontMetrics.ascent(); + QTextLine line; + if ((line = textLayout->createLine()).isValid()) { + line.setLineWidth(fontMetrics.width(text)); + line.setPosition(QPointF(0, h)); + h += line.height(); + } - /*if (justificationPadding > 0) { - engine.option.setAlignment(Qt::AlignJustify); - engine.forceJustification = true; - // this works because justify() is only interested in the difference between width and textWidth - line.width = justificationPadding; - engine.justify(line); - }*/ } QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index ad70b1e..c9abee3 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -9,10 +9,10 @@ class QStaticText; class QStaticTextPrivate { public: + QStaticTextPrivate(); void init(const QString &text, const QFont &font); - QTextEngine engine; - QVarLengthArray visualOrder; + QTextLayout *textLayout; static QStaticTextPrivate *get(const QStaticText *q); }; -- cgit v0.12 From e3723b2609a5beb10f58690bb58a236a95b1e743 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 19 May 2009 17:03:46 +0200 Subject: Fix position of QStaticText text To mirror the behavior of drawText() the y-position origin should be the baseline of the text. --- src/gui/text/qstatictext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index bb83fd1..b3edde6 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -70,7 +70,7 @@ void QStaticTextPrivate::init(const QString &text, const QFont &font) QFontMetrics fontMetrics(font); textLayout->beginLayout(); - int h = fontMetrics.ascent(); + int h = -fontMetrics.ascent(); QTextLine line; if ((line = textLayout->createLine()).isValid()) { line.setLineWidth(fontMetrics.width(text)); -- cgit v0.12 From e8271e69e1bddc2d5d251ebf34909a53fd711d0e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 19 May 2009 17:06:11 +0200 Subject: Whitespace Trailing spaces and an extra line of whitespace. --- src/gui/text/qstatictext.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index b3edde6..e3bb950 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -65,7 +65,7 @@ void QStaticTextPrivate::init(const QString &text, const QFont &font) { Q_ASSERT(textLayout == 0); textLayout = new QTextLayout(text, font); - textLayout->setCacheEnabled(true); + textLayout->setCacheEnabled(true); QFontMetrics fontMetrics(font); @@ -73,11 +73,10 @@ void QStaticTextPrivate::init(const QString &text, const QFont &font) int h = -fontMetrics.ascent(); QTextLine line; if ((line = textLayout->createLine()).isValid()) { - line.setLineWidth(fontMetrics.width(text)); + line.setLineWidth(fontMetrics.width(text)); line.setPosition(QPointF(0, h)); h += line.height(); } - } QT_END_NAMESPACE -- cgit v0.12 From a25dd3694d752cdf104f0a9064f47f001082edad Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 19 May 2009 18:09:04 +0200 Subject: Start support for formatting text within a bounding rect Support to mirror drawText(QRectF, QString). Instead of a rect you give the text a static size and then paint it to an arbitrary point later on. --- src/gui/text/qstatictext.cpp | 10 +++++----- src/gui/text/qstatictext.h | 2 +- src/gui/text/qstatictext_p.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index e3bb950..9ddcf44 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -44,11 +44,11 @@ QT_BEGIN_NAMESPACE -QStaticText::QStaticText(const QString &text, const QFont &font) +QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &size) : d_ptr(new QStaticTextPrivate) { Q_D(QStaticText); - d->init(text, font); + d->init(text, font, size.isValid() ? size.width() : -1.0); } QStaticTextPrivate::QStaticTextPrivate() @@ -61,7 +61,7 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) return q->d_ptr; } -void QStaticTextPrivate::init(const QString &text, const QFont &font) +void QStaticTextPrivate::init(const QString &text, const QFont &font, qreal width) { Q_ASSERT(textLayout == 0); textLayout = new QTextLayout(text, font); @@ -70,10 +70,10 @@ void QStaticTextPrivate::init(const QString &text, const QFont &font) QFontMetrics fontMetrics(font); textLayout->beginLayout(); - int h = -fontMetrics.ascent(); + int h = width >= 0.0 ? 0 : -fontMetrics.ascent(); QTextLine line; if ((line = textLayout->createLine()).isValid()) { - line.setLineWidth(fontMetrics.width(text)); + line.setLineWidth(width >= 0.0 ? width : fontMetrics.width(text)); line.setPosition(QPointF(0, h)); h += line.height(); } diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 4d39e23..1855114 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -56,7 +56,7 @@ class Q_GUI_EXPORT QStaticText { Q_DECLARE_PRIVATE(QStaticText); public: - QStaticText(const QString &text, const QFont &font); + QStaticText(const QString &text, const QFont &font, const QSizeF &maximumSize = QSizeF()); private: QStaticTextPrivate *d_ptr; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index c9abee3..d0e0c2a 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -10,7 +10,7 @@ class QStaticTextPrivate { public: QStaticTextPrivate(); - void init(const QString &text, const QFont &font); + void init(const QString &text, const QFont &font, qreal width); QTextLayout *textLayout; -- cgit v0.12 From 596d92d6ca25465594e5b852e99d73dda25494fd Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 22 May 2009 16:23:08 +0200 Subject: Fix formatting/clipping rectangle in QPainter::drawStaticText() The rectangle should clip the text vertically and break lines horizontally, to mirror behavior of QPainter::drawText(). --- src/gui/painting/qpainter.cpp | 18 ++++++++++++- src/gui/text/qstatictext.cpp | 26 ++++++++++++++----- src/gui/text/qstatictext.h | 1 + src/gui/text/qstatictext_p.h | 59 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index a890d63..00b462b 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5709,7 +5709,23 @@ void QPainter::drawStaticText(const QPointF &p, const QStaticText &staticText) const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); QTextLayout *textLayout = staticText_d->textLayout; - textLayout->draw(this, p); + QSizeF size = staticText_d->size; + + QRectF clipRect = size.isValid() ? QRectF(p, staticText_d->size) : QRectF(); + QPainterPath oldClipPath; + if (clipRect.isValid()) { + oldClipPath = clipPath(); + + QPainterPath clipPath; + clipPath.addRect(clipRect); + + setClipPath(clipPath, Qt::IntersectClip); + } + + textLayout->draw(this, p, QVector(), clipRect); + + if (clipRect.isValid()) + setClipPath(oldClipPath); } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 9ddcf44..44cb799 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -44,11 +44,17 @@ QT_BEGIN_NAMESPACE -QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &size) +QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &sz) : d_ptr(new QStaticTextPrivate) { Q_D(QStaticText); - d->init(text, font, size.isValid() ? size.width() : -1.0); + d->init(text, font, sz); +} + +QStaticText::~QStaticText() +{ + Q_D(QStaticText); + delete d; } QStaticTextPrivate::QStaticTextPrivate() @@ -56,24 +62,32 @@ QStaticTextPrivate::QStaticTextPrivate() { } +QStaticTextPrivate::~QStaticTextPrivate() +{ + delete textLayout; +} + QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) { return q->d_ptr; } -void QStaticTextPrivate::init(const QString &text, const QFont &font, qreal width) +void QStaticTextPrivate::init(const QString &text, const QFont &font, const QSizeF &sz) { Q_ASSERT(textLayout == 0); + size = sz; + textLayout = new QTextLayout(text, font); textLayout->setCacheEnabled(true); QFontMetrics fontMetrics(font); textLayout->beginLayout(); - int h = width >= 0.0 ? 0 : -fontMetrics.ascent(); + int h = size.isValid() ? 0 : -fontMetrics.ascent(); + QTextLine line; - if ((line = textLayout->createLine()).isValid()) { - line.setLineWidth(width >= 0.0 ? width : fontMetrics.width(text)); + while ((line = textLayout->createLine()).isValid()) { + line.setLineWidth(size.isValid() ? size.width() : fontMetrics.width(text)); line.setPosition(QPointF(0, h)); h += line.height(); } diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 1855114..fc10712 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -57,6 +57,7 @@ class Q_GUI_EXPORT QStaticText Q_DECLARE_PRIVATE(QStaticText); public: QStaticText(const QString &text, const QFont &font, const QSizeF &maximumSize = QSizeF()); + ~QStaticText(); private: QStaticTextPrivate *d_ptr; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index d0e0c2a..b2f29f7 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -1,18 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + #ifndef QSTATICTEXT_P_H #define QSTATICTEXT_P_H -QT_BEGIN_NAMESPACE +// +// 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 +QT_BEGIN_NAMESPACE + class QStaticText; class QStaticTextPrivate { public: QStaticTextPrivate(); - void init(const QString &text, const QFont &font, qreal width); + ~QStaticTextPrivate(); + + void init(const QString &text, const QFont &font, const QSizeF &size); QTextLayout *textLayout; + QSizeF size; static QStaticTextPrivate *get(const QStaticText *q); }; -- cgit v0.12 From 04b9106f87d865aeb7627c8238742a4ca8601def Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 22 May 2009 17:05:42 +0200 Subject: Add convenience overloads to QPainter::drawStaticText() Adds the integer based overloads as inline functions, same as for QPainter::drawText(). --- src/gui/painting/qpainter.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index f2be36f..1ae7c08 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -370,6 +370,8 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; + inline void drawStaticText(int x, int y, const QStaticText &staticText); + inline void drawStaticText(const QPoint &p, const QStaticText &staticText); void drawStaticText(const QPointF &p, const QStaticText &staticText); void drawText(const QPointF &p, const QString &s); @@ -909,6 +911,16 @@ inline void QPainter::drawText(const QPoint &p, const QString &s) drawText(QPointF(p), s); } +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::drawText(int x, int y, int w, int h, int flags, const QString &str, QRect *br) { drawText(QRect(x, y, w, h), flags, str, br); -- cgit v0.12 From 1271197f70862fd1565039aff3b0e40665d3adde Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 22 May 2009 17:07:07 +0200 Subject: doc: Add documentation for QStaticText and QPainter::drawStaticText() --- src/gui/painting/qpainter.cpp | 28 +++++++++++++++++--- src/gui/text/qstatictext.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 00b462b..8ff93d2 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5704,14 +5704,36 @@ void QPainter::drawText(const QPointF &p, const QString &str) drawText(p, str, 0, 0); } -void QPainter::drawStaticText(const QPointF &p, const QStaticText &staticText) +/*! + \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) + + \overload +*/ + +/*! + \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) + + \overload +*/ + +/*! + Draws the given \a staticText beginning at the given \a position. + + This function can be used to optimize drawing text if the text and its layout is updated + seldomly. + + \note To mirror the behavior of QPainter::drawText() the y-position will be used as the baseline + of the font if a size not set on \a staticText. If a size is set for \a staticText, \a position + is the top left corner of the clipping rectangle of the text. +*/ +void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) { const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); QTextLayout *textLayout = staticText_d->textLayout; QSizeF size = staticText_d->size; - QRectF clipRect = size.isValid() ? QRectF(p, staticText_d->size) : QRectF(); + QRectF clipRect = size.isValid() ? QRectF(position, staticText_d->size) : QRectF(); QPainterPath oldClipPath; if (clipRect.isValid()) { oldClipPath = clipPath(); @@ -5722,7 +5744,7 @@ void QPainter::drawStaticText(const QPointF &p, const QStaticText &staticText) setClipPath(clipPath, Qt::IntersectClip); } - textLayout->draw(this, p, QVector(), clipRect); + textLayout->draw(this, position, QVector(), clipRect); if (clipRect.isValid()) setClipPath(oldClipPath); diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 44cb799..1256427 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -44,6 +44,64 @@ QT_BEGIN_NAMESPACE +/*! + \class QStaticText + \brief The QStaticText class enables optimized drawing of text when the text and its layout + is updated rarely. + + \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 text is static over several paint + events. If the text or its layout is changed regularly, QPainter::drawText() is the more + efficient alternative. + + \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 vertically at the given height. The position of the text is decided by the argument + passed to QPainter::drawStaticText() and can change from call to call without affecting + performance. + + \sa QPainter::drawStaticText(). +*/ + +/*! + \fn QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &maximumSize) + + Constructs a QStaticText object with the given \a text which is to be rendered in the given + \a font and bounded by the given \a maximumSize. If an invalid size is passed for \a maximumSize + the text will be unbounded. +*/ QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &sz) : d_ptr(new QStaticTextPrivate) { @@ -51,6 +109,9 @@ QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &s d->init(text, font, sz); } +/*! + Destroys the QStaticText. +*/ QStaticText::~QStaticText() { Q_D(QStaticText); -- cgit v0.12 From c74c00b3a006491c4e7140fd7c5c2553d8abf45d Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 22 May 2009 17:42:25 +0200 Subject: Add lazy initialization to QStaticText People should be able to initialize the QStaticText lazily, or change its data after instantiation. Each of the setters will recalculate the layout to make sure it's always in sync. --- src/gui/text/qstatictext.cpp | 108 +++++++++++++++++++++++++++++++++++++++---- src/gui/text/qstatictext.h | 16 ++++++- src/gui/text/qstatictext_p.h | 2 +- 3 files changed, 114 insertions(+), 12 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 1256427..d665abe 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -92,10 +92,18 @@ QT_BEGIN_NAMESPACE passed to QPainter::drawStaticText() and can change from call to call without affecting performance. - \sa QPainter::drawStaticText(). + \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument */ /*! + Constructs an empty QStaticText +*/ +QStaticText::QStaticText() + : d_ptr(new QStaticTextPrivate) +{ +} + +/*! \fn QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &maximumSize) Constructs a QStaticText object with the given \a text which is to be rendered in the given @@ -106,7 +114,12 @@ QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &s : d_ptr(new QStaticTextPrivate) { Q_D(QStaticText); - d->init(text, font, sz); + + d->textLayout->setText(text); + d->textLayout->setFont(font); + d->size = sz; + + d->init(); } /*! @@ -118,8 +131,84 @@ QStaticText::~QStaticText() delete d; } +/*! + 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) +{ + Q_D(QStaticText); + d->textLayout->setText(text); + d->init(); +} + +/*! + Returns the text of the QStaticText. + + \sa setText() +*/ +QString QStaticText::text() const +{ + Q_D(const QStaticText); + return d->textLayout->text(); +} + +/*! + Sets the font of the QStaticText to \a font. + + \note This function will cause the layout of the text to be recalculated. + + \sa font() +*/ +void QStaticText::setFont(const QFont &font) +{ + Q_D(QStaticText); + d->textLayout->setFont(font); + d->init(); +} + +/*! + Returns the font of the QStaticText. + + \sa setFont() +*/ +QFont QStaticText::font() const +{ + Q_D(const QStaticText); + return d->textLayout->font(); +} + +/*! + Sets the maximum size of the QStaticText to \a maximumSize. If a valid maximum size is set for + the QStaticText, it will be formatted to fit within its width, and clipped by its height. + + \note This function will cause the layout of the text to be recalculated. + + \sa maximumSize() +*/ +void QStaticText::setMaximumSize(const QSizeF &maximumSize) +{ + Q_D(QStaticText); + d->size = maximumSize; + d->init(); +} + +/*! + Returns the maximum size of the QStaticText. + + \sa setMaximumSize() +*/ +QSizeF QStaticText::maximumSize() const +{ + Q_D(const QStaticText); + return d->size; +} + QStaticTextPrivate::QStaticTextPrivate() - : textLayout(0) + : textLayout(new QTextLayout()) { } @@ -133,25 +222,24 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) return q->d_ptr; } -void QStaticTextPrivate::init(const QString &text, const QFont &font, const QSizeF &sz) +void QStaticTextPrivate::init() { - Q_ASSERT(textLayout == 0); - size = sz; - - textLayout = new QTextLayout(text, font); + Q_ASSERT(textLayout != 0); textLayout->setCacheEnabled(true); - QFontMetrics fontMetrics(font); + QFontMetrics fontMetrics(textLayout->font()); textLayout->beginLayout(); int h = size.isValid() ? 0 : -fontMetrics.ascent(); QTextLine line; + qreal lineWidth = size.isValid() ? size.width() : fontMetrics.width(textLayout->text()); while ((line = textLayout->createLine()).isValid()) { - line.setLineWidth(size.isValid() ? size.width() : fontMetrics.width(text)); + line.setLineWidth(lineWidth); line.setPosition(QPointF(0, h)); h += line.height(); } + textLayout->endLayout(); } QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index fc10712..a666a7e 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -56,9 +56,23 @@ class Q_GUI_EXPORT QStaticText { Q_DECLARE_PRIVATE(QStaticText); public: - QStaticText(const QString &text, const QFont &font, const QSizeF &maximumSize = QSizeF()); + QStaticText(); + QStaticText(const QString &text); + QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); ~QStaticText(); + void isValid() const; + + void setText(const QString &text); + QString text() const; + + void setFont(const QFont &font); + QFont font() const; + + void setMaximumSize(const QSizeF &maximumSize); + QSizeF maximumSize() const; + + private: QStaticTextPrivate *d_ptr; }; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index b2f29f7..1e334d7 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -64,7 +64,7 @@ public: QStaticTextPrivate(); ~QStaticTextPrivate(); - void init(const QString &text, const QFont &font, const QSizeF &size); + void init(); QTextLayout *textLayout; QSizeF size; -- cgit v0.12 From c46759628b95e388eb4c5bd8c87347a0f2ea0ad6 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 2 Jun 2009 15:25:04 +0200 Subject: Remove ambiguous overload for QStaticText() constructor The QStaticText(QString) constructor has been replaced by a constructor with defaults for the additional arguments --- src/gui/text/qstatictext.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index a666a7e..a25bef8 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -57,7 +57,6 @@ class Q_GUI_EXPORT QStaticText Q_DECLARE_PRIVATE(QStaticText); public: QStaticText(); - QStaticText(const QString &text); QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); ~QStaticText(); -- cgit v0.12 From 9e4bf3772c808d8bf0016ae6674610bae2272613 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 2 Jun 2009 17:38:17 +0200 Subject: Add operators and implicit sharing to QStaticText Adds copy constructor, operator==, operator= and operator!= to QStaticText. Implemented using an implicitly shared private object. --- src/gui/text/qstatictext.cpp | 105 +++++++++++++++++++++++++++++++++---------- src/gui/text/qstatictext.h | 10 ++++- src/gui/text/qstatictext_p.h | 2 + 3 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index d665abe..b6c123b 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -112,14 +112,21 @@ QStaticText::QStaticText() */ QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &sz) : d_ptr(new QStaticTextPrivate) -{ - Q_D(QStaticText); - - d->textLayout->setText(text); - d->textLayout->setFont(font); - d->size = sz; +{ + d_ptr->textLayout->setText(text); + d_ptr->textLayout->setFont(font); + d_ptr->size = sz; - d->init(); + d_ptr->init(); +} + +/*! + Constructs a QStaticText object which is a copy of \a other. +*/ +QStaticText::QStaticText(const QStaticText &other) +{ + d_ptr = other.d_ptr; + d_ptr->ref.ref(); } /*! @@ -127,8 +134,47 @@ QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &s */ QStaticText::~QStaticText() { - Q_D(QStaticText); - delete d; + if (!d_ptr->ref.deref()) + delete d_ptr; +} + +/*! + \internal +*/ +void QStaticText::detach() +{ + if (d_ptr->ref != 1) + qAtomicDetach(d_ptr); +} + +/*! + Assigns \a other to this QStaticText. +*/ +QStaticText &QStaticText::operator=(const QStaticText &other) +{ + qAtomicAssign(d_ptr, other.d_ptr); + 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 (d_ptr == other.d_ptr + || (d_ptr->textLayout->text() == other.d_ptr->textLayout->text() + && d_ptr->textLayout->font() == other.d_ptr->textLayout->font() + && d_ptr->size == other.d_ptr->size)); +} + +/*! + 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); } /*! @@ -140,9 +186,10 @@ QStaticText::~QStaticText() */ void QStaticText::setText(const QString &text) { - Q_D(QStaticText); - d->textLayout->setText(text); - d->init(); + detach(); + + d_ptr->textLayout->setText(text); + d_ptr->init(); } /*! @@ -152,8 +199,7 @@ void QStaticText::setText(const QString &text) */ QString QStaticText::text() const { - Q_D(const QStaticText); - return d->textLayout->text(); + return d_ptr->textLayout->text(); } /*! @@ -165,9 +211,10 @@ QString QStaticText::text() const */ void QStaticText::setFont(const QFont &font) { - Q_D(QStaticText); - d->textLayout->setFont(font); - d->init(); + detach(); + + d_ptr->textLayout->setFont(font); + d_ptr->init(); } /*! @@ -177,8 +224,7 @@ void QStaticText::setFont(const QFont &font) */ QFont QStaticText::font() const { - Q_D(const QStaticText); - return d->textLayout->font(); + return d_ptr->textLayout->font(); } /*! @@ -191,9 +237,10 @@ QFont QStaticText::font() const */ void QStaticText::setMaximumSize(const QSizeF &maximumSize) { - Q_D(QStaticText); - d->size = maximumSize; - d->init(); + detach(); + + d_ptr->size = maximumSize; + d_ptr->init(); } /*! @@ -203,8 +250,12 @@ void QStaticText::setMaximumSize(const QSizeF &maximumSize) */ QSizeF QStaticText::maximumSize() const { - Q_D(const QStaticText); - return d->size; + return d_ptr->size; +} + +QString QStaticText::toString() const +{ + return text(); } QStaticTextPrivate::QStaticTextPrivate() @@ -212,6 +263,12 @@ QStaticTextPrivate::QStaticTextPrivate() { } +QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) +{ + textLayout = new QTextLayout(other.textLayout->text(), other.textLayout->font()); + size = other.size; +} + QStaticTextPrivate::~QStaticTextPrivate() { delete textLayout; diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index a25bef8..4976039 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -58,10 +58,9 @@ class Q_GUI_EXPORT QStaticText public: QStaticText(); QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); + QStaticText(const QStaticText &other); ~QStaticText(); - void isValid() const; - void setText(const QString &text); QString text() const; @@ -71,8 +70,15 @@ public: void setMaximumSize(const QSizeF &maximumSize); QSizeF maximumSize() const; + QStaticText &operator=(const QStaticText &); + bool operator==(const QStaticText &) const; + bool operator!=(const QStaticText &) const; + + QString toString() const; private: + void detach(); + QStaticTextPrivate *d_ptr; }; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 1e334d7..773971a 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -62,12 +62,14 @@ class QStaticTextPrivate { public: QStaticTextPrivate(); + QStaticTextPrivate(const QStaticTextPrivate &other); ~QStaticTextPrivate(); void init(); QTextLayout *textLayout; QSizeF size; + QAtomicInt ref; static QStaticTextPrivate *get(const QStaticText *q); }; -- cgit v0.12 From b5e265cbbfd809a405664800654f66d5eb3e5367 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 26 Jun 2009 13:28:35 +0200 Subject: Compile Q_DECLARE_PRIVATE requires d_ptr to be a QFooPointer<>-object. --- src/gui/text/qstatictext.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 4976039..d7771e0 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -53,8 +53,7 @@ QT_MODULE(Gui) class QStaticTextPrivate; class Q_GUI_EXPORT QStaticText -{ - Q_DECLARE_PRIVATE(QStaticText); +{ public: QStaticText(); QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); @@ -80,6 +79,7 @@ private: void detach(); QStaticTextPrivate *d_ptr; + friend class QStaticTextPrivate; }; QT_END_NAMESPACE -- cgit v0.12 From 99d9f3c14ecebe72a2d10016b37d9a309f7a8c13 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 30 Jun 2009 16:26:37 +0200 Subject: Compile on S60 --- src/gui/text/qstatictext.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index d7771e0..3d59d6a 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -44,6 +44,7 @@ #include #include +#include QT_BEGIN_HEADER -- cgit v0.12 From 30245b9fcfadaa7b400993aff05f8d1a54bea8d8 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 30 Jun 2009 16:26:54 +0200 Subject: Fix memory leak --- src/gui/text/qstatictext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index b6c123b..f953d71 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -133,7 +133,7 @@ QStaticText::QStaticText(const QStaticText &other) Destroys the QStaticText. */ QStaticText::~QStaticText() -{ +{ if (!d_ptr->ref.deref()) delete d_ptr; } @@ -261,10 +261,12 @@ QString QStaticText::toString() const QStaticTextPrivate::QStaticTextPrivate() : textLayout(new QTextLayout()) { + ref = 1; } QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) { + ref = 1; textLayout = new QTextLayout(other.textLayout->text(), other.textLayout->font()); size = other.size; } -- cgit v0.12 From e459416e357c86f32146de4e7dce220153a132b2 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 3 Aug 2009 15:49:20 +0200 Subject: Optimize QStaticText for one line strings QTextLayout takes a lot of memory. We can get a bigger speed-up and a more reasonable memory consumption by only supporting the single line static texts and caching the text items. We need to copy some structs from the text engine, since this is on the stack. --- src/gui/painting/qpainter.cpp | 29 +++------- src/gui/text/qstatictext.cpp | 128 +++++++++++++++++++++++------------------- src/gui/text/qstatictext.h | 5 +- src/gui/text/qstatictext_p.h | 7 ++- src/gui/text/qtextengine.cpp | 12 ++++ src/gui/text/qtextengine_p.h | 2 + 6 files changed, 98 insertions(+), 85 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 8ff93d2..435ad9b 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5721,33 +5721,22 @@ void QPainter::drawText(const QPointF &p, const QString &str) This function can be used to optimize drawing text if the text and its layout is updated seldomly. - - \note To mirror the behavior of QPainter::drawText() the y-position will be used as the baseline - of the font if a size not set on \a staticText. If a size is set for \a staticText, \a position - is the top left corner of the clipping rectangle of the text. */ void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) { const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); - QTextLayout *textLayout = staticText_d->textLayout; - - QSizeF size = staticText_d->size; - QRectF clipRect = size.isValid() ? QRectF(position, staticText_d->size) : QRectF(); - QPainterPath oldClipPath; - if (clipRect.isValid()) { - oldClipPath = clipPath(); - - QPainterPath clipPath; - clipPath.addRect(clipRect); + QFixed x = QFixed::fromReal(position.x()); + for (int i=0; iitems.size();++i) { + QTextItemInt *gf = staticText_d->items.at(i); + if (gf->num_chars == 0) { + x += gf->width; + continue; + } - setClipPath(clipPath, Qt::IntersectClip); + drawTextItem(QPointF(x.toReal(), position.y()), *gf); + x += gf->width; } - - textLayout->draw(this, position, QVector(), clipRect); - - if (clipRect.isValid()) - setClipPath(oldClipPath); } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index f953d71..90fde9d 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -41,6 +41,7 @@ #include "qstatictext.h" #include "qstatictext_p.h" +#include QT_BEGIN_NAMESPACE @@ -110,13 +111,11 @@ QStaticText::QStaticText() \a font and bounded by the given \a maximumSize. If an invalid size is passed for \a maximumSize the text will be unbounded. */ -QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &sz) +QStaticText::QStaticText(const QString &text, const QFont &font) : d_ptr(new QStaticTextPrivate) { - d_ptr->textLayout->setText(text); - d_ptr->textLayout->setFont(font); - d_ptr->size = sz; - + d_ptr->text = text; + d_ptr->font = font; d_ptr->init(); } @@ -163,9 +162,7 @@ QStaticText &QStaticText::operator=(const QStaticText &other) bool QStaticText::operator==(const QStaticText &other) const { return (d_ptr == other.d_ptr - || (d_ptr->textLayout->text() == other.d_ptr->textLayout->text() - && d_ptr->textLayout->font() == other.d_ptr->textLayout->font() - && d_ptr->size == other.d_ptr->size)); + || (d_ptr->text == other.d_ptr->text && d_ptr->font == other.d_ptr->font)); } /*! @@ -187,8 +184,7 @@ bool QStaticText::operator!=(const QStaticText &other) const void QStaticText::setText(const QString &text) { detach(); - - d_ptr->textLayout->setText(text); + d_ptr->text = text; d_ptr->init(); } @@ -199,7 +195,7 @@ void QStaticText::setText(const QString &text) */ QString QStaticText::text() const { - return d_ptr->textLayout->text(); + return d_ptr->text; } /*! @@ -212,8 +208,7 @@ QString QStaticText::text() const void QStaticText::setFont(const QFont &font) { detach(); - - d_ptr->textLayout->setFont(font); + d_ptr->font = font; d_ptr->init(); } @@ -224,33 +219,7 @@ void QStaticText::setFont(const QFont &font) */ QFont QStaticText::font() const { - return d_ptr->textLayout->font(); -} - -/*! - Sets the maximum size of the QStaticText to \a maximumSize. If a valid maximum size is set for - the QStaticText, it will be formatted to fit within its width, and clipped by its height. - - \note This function will cause the layout of the text to be recalculated. - - \sa maximumSize() -*/ -void QStaticText::setMaximumSize(const QSizeF &maximumSize) -{ - detach(); - - d_ptr->size = maximumSize; - d_ptr->init(); -} - -/*! - Returns the maximum size of the QStaticText. - - \sa setMaximumSize() -*/ -QSizeF QStaticText::maximumSize() const -{ - return d_ptr->size; + return d_ptr->font; } QString QStaticText::toString() const @@ -258,22 +227,24 @@ QString QStaticText::toString() const return text(); } -QStaticTextPrivate::QStaticTextPrivate() - : textLayout(new QTextLayout()) +QStaticTextPrivate::QStaticTextPrivate() : glyphLayoutMemory(0), logClusterMemory(0) { - ref = 1; + ref = 1; } -QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) +QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) { ref = 1; - textLayout = new QTextLayout(other.textLayout->text(), other.textLayout->font()); - size = other.size; + text = other.text; + font = other.font; + init(); } QStaticTextPrivate::~QStaticTextPrivate() { - delete textLayout; + delete glyphLayoutMemory; + delete logClusterMemory; + qDeleteAll(items); } QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) @@ -283,22 +254,61 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) void QStaticTextPrivate::init() { - Q_ASSERT(textLayout != 0); - textLayout->setCacheEnabled(true); + delete glyphLayoutMemory; + delete logClusterMemory; + qDeleteAll(items); + + QStackTextEngine engine = QStackTextEngine(text, font); + engine.itemize(); + + engine.option.setTextDirection(QApplication::layoutDirection()); + QScriptLine line; + line.length = text.length(); + engine.shapeLine(line); + + int nItems = engine.layoutData->items.size(); + QVarLengthArray visualOrder(nItems); + QVarLengthArray levels(nItems); + for (int i = 0; i < nItems; ++i) + levels[i] = engine.layoutData->items[i].analysis.bidiLevel; + QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + + int numGlyphs = engine.layoutData->glyphLayout.numGlyphs; + glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(numGlyphs)]; + logClusterMemory = new unsigned short[numGlyphs]; + + char *currentGlyphLayout = glyphLayoutMemory; + unsigned short *currentLogCluster = logClusterMemory; + for (int i = 0; i < nItems; ++i) { + int item = visualOrder[i]; + const QScriptItem &si = engine.layoutData->items.at(item); + + QFont f = engine.font(si); + if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { + QTextItemInt *gf = new QTextItemInt(si, &f); + gf->width = si.width; + items.append(gf); + continue; + } - QFontMetrics fontMetrics(textLayout->font()); + QTextItemInt *gf = new QTextItemInt(si, &f); - textLayout->beginLayout(); - int h = size.isValid() ? 0 : -fontMetrics.ascent(); + QGlyphLayout l = engine.shapedGlyphs(&si); + gf->glyphs = l.clone(currentGlyphLayout); + currentGlyphLayout += QGlyphLayout::spaceNeededForGlyphLayout(l.numGlyphs); - QTextLine line; - qreal lineWidth = size.isValid() ? size.width() : fontMetrics.width(textLayout->text()); - while ((line = textLayout->createLine()).isValid()) { - line.setLineWidth(lineWidth); - line.setPosition(QPointF(0, h)); - h += line.height(); + gf->chars = text.unicode() + si.position; + gf->num_chars = engine.length(item); + gf->width = si.width; + + memmove(currentLogCluster, engine.logClusters(&si), sizeof(unsigned short) * l.numGlyphs); + gf->logClusters = currentLogCluster; + currentLogCluster += l.numGlyphs; + + items.append(gf); } - textLayout->endLayout(); + + items.squeeze(); } QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 3d59d6a..bcafaa9 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -57,7 +57,7 @@ class Q_GUI_EXPORT QStaticText { public: QStaticText(); - QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); + QStaticText(const QString &text, const QFont &font = QFont()); QStaticText(const QStaticText &other); ~QStaticText(); @@ -67,9 +67,6 @@ public: void setFont(const QFont &font); QFont font() const; - void setMaximumSize(const QSizeF &maximumSize); - QSizeF maximumSize() const; - QStaticText &operator=(const QStaticText &); bool operator==(const QStaticText &) const; bool operator!=(const QStaticText &) const; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 773971a..aaaf300 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -67,9 +67,12 @@ public: void init(); - QTextLayout *textLayout; - QSizeF size; QAtomicInt ref; + QVector items; + QString text; + QFont font; + char *glyphLayoutMemory; + unsigned short *logClusterMemory; static QStaticTextPrivate *get(const QStaticText *q); }; diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 02eae98..7f92279 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2109,6 +2109,18 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs) allocated = newAllocated; } +QGlyphLayout QGlyphLayout::clone(char *address) const +{ + QGlyphLayout layout(address, numGlyphs); + memmove(layout.attributes, attributes, numGlyphs * sizeof(HB_GlyphAttributes)); + memmove(layout.justifications, justifications, numGlyphs * sizeof(QGlyphJustification)); + memmove(layout.advances_y, advances_y, numGlyphs * sizeof(QFixed)); + memmove(layout.advances_x, advances_x, numGlyphs * sizeof(QFixed)); + memmove(layout.glyphs, glyphs, numGlyphs * sizeof(HB_Glyph)); + + return layout; +} + // grow to the new size, copying the existing data to the new layout void QGlyphLayout::grow(char *address, int totalGlyphs) { diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index f36cbd2..2edbd98 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -262,6 +262,8 @@ struct QGlyphLayout } void grow(char *address, int totalGlyphs); + + QGlyphLayout clone(char *address) const; }; class QVarLengthGlyphLayoutArray : private QVarLengthArray, public QGlyphLayout -- cgit v0.12 From 9e40703796bf2a2d9b1dbb4ad09c22f9d036c985 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 4 Aug 2009 11:17:42 +0200 Subject: Space optimization in QStaticText The engine.layoutData's glyph count is the number allocated, which may be larger than the actual number of glyphs. To minimize the space needed we base allocation on "used" which contains the number of glyphs actually used to represent the text. --- src/gui/painting/qpainter.cpp | 8 ++------ src/gui/text/qstatictext.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 435ad9b..6bb8acd 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5729,12 +5729,8 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static QFixed x = QFixed::fromReal(position.x()); for (int i=0; iitems.size();++i) { QTextItemInt *gf = staticText_d->items.at(i); - if (gf->num_chars == 0) { - x += gf->width; - continue; - } - - drawTextItem(QPointF(x.toReal(), position.y()), *gf); + if (gf->num_chars != 0) + drawTextItem(QPointF(x.toReal(), position.y()), *gf); x += gf->width; } } diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 90fde9d..e9fd9c5 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -242,8 +242,8 @@ QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) QStaticTextPrivate::~QStaticTextPrivate() { - delete glyphLayoutMemory; - delete logClusterMemory; + delete[] glyphLayoutMemory; + delete[] logClusterMemory; qDeleteAll(items); } @@ -254,11 +254,11 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) void QStaticTextPrivate::init() { - delete glyphLayoutMemory; - delete logClusterMemory; + delete[] glyphLayoutMemory; + delete[] logClusterMemory; qDeleteAll(items); - QStackTextEngine engine = QStackTextEngine(text, font); + QStackTextEngine engine(text, font); engine.itemize(); engine.option.setTextDirection(QApplication::layoutDirection()); @@ -273,7 +273,7 @@ void QStaticTextPrivate::init() levels[i] = engine.layoutData->items[i].analysis.bidiLevel; QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); - int numGlyphs = engine.layoutData->glyphLayout.numGlyphs; + int numGlyphs = engine.layoutData->used; glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(numGlyphs)]; logClusterMemory = new unsigned short[numGlyphs]; @@ -289,10 +289,9 @@ void QStaticTextPrivate::init() gf->width = si.width; items.append(gf); continue; - } + } QTextItemInt *gf = new QTextItemInt(si, &f); - QGlyphLayout l = engine.shapedGlyphs(&si); gf->glyphs = l.clone(currentGlyphLayout); currentGlyphLayout += QGlyphLayout::spaceNeededForGlyphLayout(l.numGlyphs); -- cgit v0.12 From c8621912c17ed15446da2f25760868bc177808c0 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 4 Aug 2009 11:19:25 +0200 Subject: Fix drawing in QStaticText Also clone the offsets structure into the new QGlyphLayout. --- src/gui/text/qtextengine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 7f92279..da3a3c0 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2112,6 +2112,7 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs) QGlyphLayout QGlyphLayout::clone(char *address) const { QGlyphLayout layout(address, numGlyphs); + memmove(layout.offsets, offsets, numGlyphs * sizeof(QFixedPoint)); memmove(layout.attributes, attributes, numGlyphs * sizeof(HB_GlyphAttributes)); memmove(layout.justifications, justifications, numGlyphs * sizeof(QGlyphJustification)); memmove(layout.advances_y, advances_y, numGlyphs * sizeof(QFixed)); -- cgit v0.12 From 4cfca7cf456722ee8659b595f231f3cc2033b80d Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 4 Aug 2009 13:41:36 +0200 Subject: Speed optimization for QStaticText Don't use QVector to store the text items, but put them in a regular array for quick access. drawStaticText() is now about 2.7 times the speed of drawText(). --- src/gui/painting/qpainter.cpp | 14 +++++++++----- src/gui/text/qstatictext.cpp | 37 ++++++++++++++++++++----------------- src/gui/text/qstatictext.h | 2 ++ src/gui/text/qstatictext_p.h | 3 ++- src/gui/text/qtextengine.cpp | 5 +++++ src/gui/text/qtextengine_p.h | 2 ++ 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 6bb8acd..50d27ac 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5724,14 +5724,18 @@ void QPainter::drawText(const QPointF &p, const QString &str) */ void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) { + Q_D(QPainter); + if (!d->engine || staticText.isEmpty() || pen().style() == Qt::NoPen) + return; + const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); QFixed x = QFixed::fromReal(position.x()); - for (int i=0; iitems.size();++i) { - QTextItemInt *gf = staticText_d->items.at(i); - if (gf->num_chars != 0) - drawTextItem(QPointF(x.toReal(), position.y()), *gf); - x += gf->width; + for (int i=0; iitemCount; ++i) { + const QTextItemInt &gf = staticText_d->items[i]; + if (gf.num_chars != 0) + drawTextItem(QPointF(x.toReal(), position.y()), gf); + x += gf.width; } } diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index e9fd9c5..d97c0c9 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -227,7 +227,13 @@ QString QStaticText::toString() const return text(); } -QStaticTextPrivate::QStaticTextPrivate() : glyphLayoutMemory(0), logClusterMemory(0) +bool QStaticText::isEmpty() const +{ + return d_ptr->text.isEmpty(); +} + +QStaticTextPrivate::QStaticTextPrivate() + : glyphLayoutMemory(0), logClusterMemory(0), items(0), itemCount(0) { ref = 1; } @@ -244,7 +250,7 @@ QStaticTextPrivate::~QStaticTextPrivate() { delete[] glyphLayoutMemory; delete[] logClusterMemory; - qDeleteAll(items); + delete[] items; } QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) @@ -256,7 +262,7 @@ void QStaticTextPrivate::init() { delete[] glyphLayoutMemory; delete[] logClusterMemory; - qDeleteAll(items); + delete[] items; QStackTextEngine engine(text, font); engine.itemize(); @@ -276,6 +282,8 @@ void QStaticTextPrivate::init() int numGlyphs = engine.layoutData->used; glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(numGlyphs)]; logClusterMemory = new unsigned short[numGlyphs]; + items = new QTextItemInt[nItems]; + itemCount = nItems; char *currentGlyphLayout = glyphLayoutMemory; unsigned short *currentLogCluster = logClusterMemory; @@ -285,29 +293,24 @@ void QStaticTextPrivate::init() QFont f = engine.font(si); if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { - QTextItemInt *gf = new QTextItemInt(si, &f); - gf->width = si.width; - items.append(gf); + items[i].width = si.width; continue; } - QTextItemInt *gf = new QTextItemInt(si, &f); + items[i].init(si, &f); + QGlyphLayout l = engine.shapedGlyphs(&si); - gf->glyphs = l.clone(currentGlyphLayout); + items[i].glyphs = l.clone(currentGlyphLayout); currentGlyphLayout += QGlyphLayout::spaceNeededForGlyphLayout(l.numGlyphs); - gf->chars = text.unicode() + si.position; - gf->num_chars = engine.length(item); - gf->width = si.width; + items[i].chars = text.unicode() + si.position; + items[i].num_chars = engine.length(item); + items[i].width = si.width; memmove(currentLogCluster, engine.logClusters(&si), sizeof(unsigned short) * l.numGlyphs); - gf->logClusters = currentLogCluster; - currentLogCluster += l.numGlyphs; - - items.append(gf); + items[i].logClusters = currentLogCluster; + currentLogCluster += l.numGlyphs; } - - items.squeeze(); } QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index bcafaa9..7247bf7 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -73,6 +73,8 @@ public: QString toString() const; + bool isEmpty() const; + private: void detach(); diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index aaaf300..a0d16d4 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -68,7 +68,8 @@ public: void init(); QAtomicInt ref; - QVector items; + QTextItemInt *items; + int itemCount; QString text; QFont font; char *glyphLayoutMemory; diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index da3a3c0..5343085 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2637,6 +2637,11 @@ QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFo : justified(false), underlineStyle(QTextCharFormat::NoUnderline), charFormat(format), num_chars(0), chars(0), logClusters(0), f(0), fontEngine(0) { + init(si, font, format); +} + +void QTextItemInt::init(const QScriptItem &si, QFont *font, const QTextCharFormat &format) +{ // explicitly initialize flags so that initFontAttributes can be called // multiple times on the same TextItem flags = 0; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 2edbd98..0491d87 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -312,7 +312,9 @@ public: : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0), logClusters(0), f(0), fontEngine(0) {} + QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); + void init(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); /// copy the structure items, adjusting the glyphs arrays to the right subarrays. /// the width of the returned QTextItemInt is not adjusted, for speed reasons -- cgit v0.12 From 135dcf11efe11dacb15f4c384b302d99a0470320 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 5 Aug 2009 15:33:08 +0200 Subject: Support maximumSize for the layout of the text in a QStaticText Put back maximumSize property in QStaticText to allow matching calls to drawText with a target rectangle. Implementation is done by having a dummy paint engine which records the calls to drawTextItem() and storing these, then replaying them later. --- src/gui/painting/qpainter.cpp | 6 +- src/gui/text/qstatictext.cpp | 271 ++++++++++++++++++++++++++++++++++-------- src/gui/text/qstatictext.h | 5 +- src/gui/text/qstatictext_p.h | 11 +- src/gui/text/qtextengine.cpp | 40 +++++++ src/gui/text/qtextengine_p.h | 5 + 6 files changed, 279 insertions(+), 59 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 50d27ac..1057893 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5729,13 +5729,9 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static return; const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); - - QFixed x = QFixed::fromReal(position.x()); for (int i=0; iitemCount; ++i) { const QTextItemInt &gf = staticText_d->items[i]; - if (gf.num_chars != 0) - drawTextItem(QPointF(x.toReal(), position.y()), gf); - x += gf.width; + d->engine->drawTextItem(staticText_d->itemPositions[i] + position, gf); } } diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index d97c0c9..5a8fd9b 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -43,6 +43,8 @@ #include "qstatictext_p.h" #include +#include + QT_BEGIN_NAMESPACE /*! @@ -111,11 +113,12 @@ QStaticText::QStaticText() \a font and bounded by the given \a maximumSize. If an invalid size is passed for \a maximumSize the text will be unbounded. */ -QStaticText::QStaticText(const QString &text, const QFont &font) +QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &size) : d_ptr(new QStaticTextPrivate) { d_ptr->text = text; d_ptr->font = font; + d_ptr->size = size; d_ptr->init(); } @@ -162,7 +165,9 @@ QStaticText &QStaticText::operator=(const QStaticText &other) bool QStaticText::operator==(const QStaticText &other) const { return (d_ptr == other.d_ptr - || (d_ptr->text == other.d_ptr->text && d_ptr->font == other.d_ptr->font)); + || (d_ptr->text == other.d_ptr->text + && d_ptr->font == other.d_ptr->font + && d_ptr->size == other.d_ptr->size)); } /*! @@ -199,6 +204,30 @@ QString QStaticText::text() const } /*! + Sets the maximum size of the QStaticText to \a maximumSize. + + \note This function will cause the layout of the text to be recalculated. + + \sa maximumSize() +*/ +void QStaticText::setMaximumSize(const QSizeF &size) +{ + detach(); + d_ptr->size = size; + d_ptr->init(); +} + +/*! + Returns the maximum size of the QStaticText. + + \sa setMaximumSize +*/ +QSizeF QStaticText::maximumSize() const +{ + return d_ptr->size; +} + +/*! Sets the font of the QStaticText to \a font. \note This function will cause the layout of the text to be recalculated. @@ -233,7 +262,7 @@ bool QStaticText::isEmpty() const } QStaticTextPrivate::QStaticTextPrivate() - : glyphLayoutMemory(0), logClusterMemory(0), items(0), itemCount(0) + : glyphLayoutMemory(0), logClusterMemory(0), items(0), itemPositions(0), itemCount(0) { ref = 1; } @@ -243,14 +272,16 @@ QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) ref = 1; text = other.text; font = other.font; + size = other.size; init(); } QStaticTextPrivate::~QStaticTextPrivate() { delete[] glyphLayoutMemory; - delete[] logClusterMemory; + delete[] logClusterMemory; delete[] items; + delete[] itemPositions; } QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) @@ -258,59 +289,199 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) return q->d_ptr; } + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +namespace { + + class DrawTextItemRecorder: public QPaintEngine + { + public: + DrawTextItemRecorder(int expectedItemCount, int expectedGlyphCount, + QTextItemInt *items, + QPointF *positions, + char *glyphLayoutMemory, + unsigned short *logClusterMemory) + : m_items(items), + m_positions(positions), + m_glyphLayoutMemory(glyphLayoutMemory), + m_logClusterMemory(logClusterMemory), + m_glyphLayoutMemoryOffset(0), + m_logClusterMemoryOffset(0), + m_expectedItemCount(expectedItemCount), + m_expectedGlyphCount(expectedGlyphCount), + m_glyphCount(0), + m_itemCount(0) + { + } + + virtual void drawTextItem(const QPointF &p, const QTextItem &textItem) + { + const QTextItemInt &ti = static_cast(textItem); + + m_itemCount++; + m_glyphCount += ti.glyphs.numGlyphs; + + Q_ASSERT(m_expectedItemCount < 0 || m_itemCount <= m_expectedItemCount); + Q_ASSERT(m_expectedGlyphCount < 0 || m_glyphCount <= m_expectedGlyphCount); + + if (m_items == 0 || m_glyphLayoutMemory == 0 || m_logClusterMemory == 0 || m_positions == 0) + return; + + m_items[m_itemCount - 1] = ti.clone(m_glyphLayoutMemory + m_glyphLayoutMemoryOffset, + m_logClusterMemory + m_logClusterMemoryOffset); + m_positions[m_itemCount - 1] = p; + + m_glyphLayoutMemoryOffset += QGlyphLayout::spaceNeededForGlyphLayout(ti.glyphs.numGlyphs); + m_logClusterMemoryOffset += ti.glyphs.numGlyphs; + } + + + 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 glyphCount() const + { + return m_glyphCount; + } + + int itemCount() const + { + return m_itemCount; + } + + private: + QTextItemInt *m_items; + char *m_glyphLayoutMemory; + unsigned short *m_logClusterMemory; + QPointF *m_positions; + + int m_glyphLayoutMemoryOffset; + int m_logClusterMemoryOffset; + int m_expectedGlyphCount; + int m_expectedItemCount; + int m_glyphCount; + int m_itemCount; + }; + + class DrawTextItemDevice: public QPaintDevice + { + public: + DrawTextItemDevice(int expectedItemCount = -1, int expectedGlyphCount = -1, + QTextItemInt *items = 0, QPointF *positions = 0, + char *glyphLayoutMemory = 0, unsigned short *logClusterMemory = 0) + { + m_paintEngine = new DrawTextItemRecorder(expectedItemCount, expectedGlyphCount, + items, positions,glyphLayoutMemory, + logClusterMemory); + } + + ~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 glyphCount() const + { + return m_paintEngine->glyphCount(); + } + + int itemCount() const + { + return m_paintEngine->itemCount(); + } + + + + private: + DrawTextItemRecorder *m_paintEngine; + QRectF brect; + }; + +} + void QStaticTextPrivate::init() { delete[] glyphLayoutMemory; delete[] logClusterMemory; delete[] items; + delete[] itemPositions; + + // 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); + + if (size.isValid()) + painter.drawText(QRectF(QPointF(0, 0), size), text); + else + painter.drawText(0, 0, text); + } - QStackTextEngine engine(text, font); - engine.itemize(); - - engine.option.setTextDirection(QApplication::layoutDirection()); - QScriptLine line; - line.length = text.length(); - engine.shapeLine(line); - - int nItems = engine.layoutData->items.size(); - QVarLengthArray visualOrder(nItems); - QVarLengthArray levels(nItems); - for (int i = 0; i < nItems; ++i) - levels[i] = engine.layoutData->items[i].analysis.bidiLevel; - QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); - - int numGlyphs = engine.layoutData->used; - glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(numGlyphs)]; - logClusterMemory = new unsigned short[numGlyphs]; - items = new QTextItemInt[nItems]; - itemCount = nItems; - - char *currentGlyphLayout = glyphLayoutMemory; - unsigned short *currentLogCluster = logClusterMemory; - for (int i = 0; i < nItems; ++i) { - int item = visualOrder[i]; - const QScriptItem &si = engine.layoutData->items.at(item); - - QFont f = engine.font(si); - if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { - items[i].width = si.width; - continue; - } - - items[i].init(si, &f); - - QGlyphLayout l = engine.shapedGlyphs(&si); - items[i].glyphs = l.clone(currentGlyphLayout); - currentGlyphLayout += QGlyphLayout::spaceNeededForGlyphLayout(l.numGlyphs); - - items[i].chars = text.unicode() + si.position; - items[i].num_chars = engine.length(item); - items[i].width = si.width; - - memmove(currentLogCluster, engine.logClusters(&si), sizeof(unsigned short) * l.numGlyphs); - items[i].logClusters = currentLogCluster; - currentLogCluster += l.numGlyphs; + itemCount = counterDevice.itemCount(); + items = new QTextItemInt[itemCount]; + itemPositions = new QPointF[itemCount]; + + int glyphCount = counterDevice.glyphCount(); + glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(glyphCount)]; + logClusterMemory = new unsigned short[glyphCount]; + + // Draw again to actually record the items and glyphs + DrawTextItemDevice recorderDevice(itemCount, glyphCount, items, itemPositions, + glyphLayoutMemory, logClusterMemory); + { + QPainter painter(&recorderDevice); + + if (size.isValid()) + painter.drawText(QRectF(QPointF(0, 0), size), text); + else + painter.drawText(0, 0, text); } + } QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 7247bf7..9830b32 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -57,7 +57,7 @@ class Q_GUI_EXPORT QStaticText { public: QStaticText(); - QStaticText(const QString &text, const QFont &font = QFont()); + QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); QStaticText(const QStaticText &other); ~QStaticText(); @@ -67,6 +67,9 @@ public: void setFont(const QFont &font); QFont font() const; + void setMaximumSize(const QSizeF &maximumSize); + QSizeF maximumSize() const; + QStaticText &operator=(const QStaticText &); bool operator==(const QStaticText &) const; bool operator!=(const QStaticText &) const; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index a0d16d4..f5fd8d3 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -55,7 +55,7 @@ #include -QT_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE class QStaticText; class QStaticTextPrivate @@ -68,10 +68,15 @@ public: void init(); QAtomicInt ref; - QTextItemInt *items; - int itemCount; + QString text; QFont font; + QSizeF size; + + QTextItemInt *items; + QPointF *itemPositions; + int itemCount; + char *glyphLayoutMemory; unsigned short *logClusterMemory; diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 5343085..b27b0b7 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2640,6 +2640,46 @@ QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFo init(si, font, format); } +QTextItemInt::QTextItemInt(const QTextItemInt &other) + : descent(other.descent), ascent(other.ascent), width(other.width), + flags(other.flags), justified(other.justified), underlineStyle(other.underlineStyle), + charFormat(other.charFormat), num_chars(other.num_chars), chars(other.chars), + fontEngine(other.fontEngine), f(other.f), glyphs(other.glyphs), + logClusters(other.logClusters) +{ +} + + +QTextItemInt QTextItemInt::clone(char *glyphLayoutMemory, unsigned short *logClusterMemory) const +{ + QTextItemInt ti(*this); + + ti.glyphs = glyphs.clone(glyphLayoutMemory); + ti.logClusters = logClusterMemory; + memmove(logClusterMemory, logClusters, glyphs.numGlyphs * sizeof(unsigned short)); + + return ti; +} + +QTextItemInt &QTextItemInt::operator=(const QTextItemInt &other) +{ + descent = other.descent; + ascent = other.ascent; + width = other.width; + flags = other.flags; + justified = other.justified; + underlineStyle = other.underlineStyle; + const_cast(charFormat) = other.charFormat; + num_chars = other.num_chars; + chars = other.chars; + fontEngine = other.fontEngine; + f = other.f; + glyphs = other.glyphs; + logClusters = other.logClusters; + + return *this; +} + void QTextItemInt::init(const QScriptItem &si, QFont *font, const QTextCharFormat &format) { // explicitly initialize flags so that initFontAttributes can be called diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 0491d87..3ce744e 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -313,13 +313,18 @@ public: logClusters(0), f(0), fontEngine(0) {} + QTextItemInt(const QTextItemInt &other); QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); void init(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); + QTextItemInt clone(char *glyphLayoutMemory, unsigned short *logClusterMemory) const; + /// copy the structure items, adjusting the glyphs arrays to the right subarrays. /// the width of the returned QTextItemInt is not adjusted, for speed reasons QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const; + QTextItemInt &operator=(const QTextItemInt &other); + QFixed descent; QFixed ascent; QFixed width; -- cgit v0.12 From c07a9073eaba1b065edb4148c03e0995df618545 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 7 Aug 2009 13:14:17 +0200 Subject: Add test for QStaticText Tests that QStaticText rendering is identical to the same operations done with regular QPainter::drawText() --- tests/auto/qstatictext/qstatictext.pro | 4 + tests/auto/qstatictext/tst_qstatictext.cpp | 158 +++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 tests/auto/qstatictext/qstatictext.pro create mode 100644 tests/auto/qstatictext/tst_qstatictext.cpp diff --git a/tests/auto/qstatictext/qstatictext.pro b/tests/auto/qstatictext/qstatictext.pro new file mode 100644 index 0000000..0f1ca68 --- /dev/null +++ b/tests/auto/qstatictext/qstatictext.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +QT = core gui +SOURCES += tst_qstatictext.cpp + diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp new file mode 100644 index 0000000..4a01124 --- /dev/null +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +class tst_QStaticText: public QObject +{ + Q_OBJECT +private slots: + void init(); + void cleanup(); + + void constructionAndDestruction(); + void drawToPoint(); + void drawToRect(); + void setFont(); + void setMaximumSize(); +}; + +void tst_QStaticText::init() +{ +} + +void tst_QStaticText::cleanup() +{ +} + +void tst_QStaticText::constructionAndDestruction() +{ + QStaticText text("My text"); +} + +void tst_QStaticText::drawToPoint() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::drawToRect() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QFont(), QSizeF(10, 500)); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::setFont() +{ + QFont font = QApplication::font(); + font.setBold(true); + font.setPointSize(28); + + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.setFont(font); + p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + QStaticText text; + text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setFont(font); + p.drawStaticText(11, 120, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::setMaximumSize() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setMaximumSize(QSizeF(10, 500)); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + + + +QTEST_MAIN(tst_QStaticText) +#include "tst_qstatictext.moc" -- cgit v0.12 From 4417f485dbaac79412d43ec403e56e7e2067e5ac Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 7 Aug 2009 13:15:50 +0200 Subject: Respect font settings of QStaticText and clip to maximum size drawText() that renders into a QRect will clip the text (unless otherwise set by the text flags passed to the function.) In drawStaticText() we should do the same for identical behavior. We also need to respect the font set on the QStaticText object. --- src/gui/painting/qpainter.cpp | 21 ++++++++++++++++++++- src/gui/text/qstatictext.cpp | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 1057893..83f66e2 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5728,11 +5728,30 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static if (!d->engine || staticText.isEmpty() || pen().style() == Qt::NoPen) return; - const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); + const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); + bool restoreWhenFinished = false; + + if (staticText_d->size.isValid()) { + setClipRect(QRectF(position, staticText_d->size)); + + save(); + restoreWhenFinished = true; + } + + if (font() != staticText_d->font) { + setFont(staticText_d->font); + + save(); + restoreWhenFinished = true; + } + for (int i=0; iitemCount; ++i) { const QTextItemInt &gf = staticText_d->items[i]; d->engine->drawTextItem(staticText_d->itemPositions[i] + position, gf); } + + if (restoreWhenFinished) + restore(); } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 5a8fd9b..70e1c47 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -455,6 +455,7 @@ void QStaticTextPrivate::init() DrawTextItemDevice counterDevice; { QPainter painter(&counterDevice); + painter.setFont(font); if (size.isValid()) painter.drawText(QRectF(QPointF(0, 0), size), text); @@ -475,6 +476,7 @@ void QStaticTextPrivate::init() glyphLayoutMemory, logClusterMemory); { QPainter painter(&recorderDevice); + painter.setFont(font); if (size.isValid()) painter.drawText(QRectF(QPointF(0, 0), size), text); -- cgit v0.12 From 49dfc4ed6a89cdd7377e4b88236bb7303fdfdc15 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 7 Aug 2009 13:18:41 +0200 Subject: Remove const-specifier to make QTextItemInt::operator=() more beautiful The const-specifier on the char format was unecessary, and made the operator= implementation ugly, so it has been removed. Reviewed-by: Simon Hausmann --- src/gui/text/qtextengine.cpp | 2 +- src/gui/text/qtextengine_p.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index b27b0b7..b55ac68 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2669,7 +2669,7 @@ QTextItemInt &QTextItemInt::operator=(const QTextItemInt &other) flags = other.flags; justified = other.justified; underlineStyle = other.underlineStyle; - const_cast(charFormat) = other.charFormat; + charFormat = other.charFormat; num_chars = other.num_chars; chars = other.chars; fontEngine = other.fontEngine; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 3ce744e..347b71e 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -332,7 +332,7 @@ public: RenderFlags flags; bool justified; QTextCharFormat::UnderlineStyle underlineStyle; - const QTextCharFormat charFormat; + QTextCharFormat charFormat; int num_chars; const QChar *chars; const unsigned short *logClusters; -- cgit v0.12 From 91e96d6c730aac4accef64e5eaab1b289939ef8e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 17 Aug 2009 13:09:51 +0200 Subject: Optimize QStaticText for space By caching the results of getGlyphPositions() we can make a code path in the critical paint engines which is optimal both in space and speed. The engines where speed is of less importance (pdf engine etc.) which may need more information, we choose the slower code path of drawText() which lays out the text again. We should have optimal paths in raster, vg and GL2 paint engines. The others are less important. Memory consumption of static text is now 14 bytes per glyph, 8 bytes per item and a static overhead of 40 bytes per QStaticText object. --- src/gui/painting/qpaintengine_raster.cpp | 53 ++++++++---- src/gui/painting/qpaintengine_raster_p.h | 7 +- src/gui/painting/qpaintengineex.cpp | 6 ++ src/gui/painting/qpaintengineex_p.h | 3 + src/gui/painting/qpainter.cpp | 22 +++-- src/gui/painting/qtextureglyphcache.cpp | 16 ++-- src/gui/painting/qtextureglyphcache_p.h | 7 +- src/gui/text/qstatictext.cpp | 93 ++++++---------------- src/gui/text/qstatictext_p.h | 38 ++++++--- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- 10 files changed, 137 insertions(+), 110 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 3f2322e..387d646 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -67,6 +67,7 @@ // #include // #include #include +#include #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" @@ -3006,27 +3007,23 @@ 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(const QVarLengthArray &glyphs, + const QVarLengthArray &positions, + QFontEngine *fontEngine, + const QTransform &matrix) { Q_D(QRasterPaintEngine); - QRasterPaintEngineState *s = state(); - - QVarLengthArray positions; - QVarLengthArray 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(fontEngine->glyphCache(0, glyphType, matrix)); if (!cache) { - cache = new QImageTextureGlyphCache(glyphType, s->matrix); - ti.fontEngine->setGlyphCache(0, cache); + cache = new QImageTextureGlyphCache(glyphType, matrix); + fontEngine->setGlyphCache(0, cache); } - cache->populate(ti, glyphs, positions); + cache->populate(fontEngine, glyphs, positions); const QImage &image = cache->image(); int bpl = image.bytesPerLine(); @@ -3216,6 +3213,26 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; } +void QRasterPaintEngine::drawStaticTextItem(const QPointF &p, QStaticTextItem *textItem) +{ + ensurePen(); + ensureState(); + + QTransform matrix; + matrix.translate(p.x(), p.y()); + + // Translate to actual position + QVarLengthArray glyphPositions = textItem->glyphPositions; + + QFixed fx = QFixed::fromReal(p.x()); + QFixed fy = QFixed::fromReal(p.y()); + for (int i=0; iglyphs, glyphPositions, textItem->fontEngine, matrix); +} + /*! \reimp */ @@ -3264,7 +3281,15 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte drawCached = false; #endif if (drawCached) { - drawCachedGlyphs(p, ti); + QRasterPaintEngineState *s = state(); + + QVarLengthArray positions; + QVarLengthArray glyphs; + QTransform matrix = s->matrix; + matrix.translate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + drawCachedGlyphs(glyphs, positions, ti.fontEngine, matrix); return; } diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index b937f66..0250c3d 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -257,7 +257,12 @@ 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(const QVarLengthArray &glyphs, + const QVarLengthArray &positions, + QFontEngine *fontEngine, + const QTransform &matrix); + + void drawStaticTextItem(const QPointF &p, QStaticTextItem *textItem); #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 058f226..15085f9 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -44,6 +44,7 @@ #include "qstroker_p.h" #include "qbezier_p.h" #include +#include #include #include @@ -589,6 +590,11 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) } } +void QPaintEngineEx::drawStaticTextItem(const QPointF &position, QStaticTextItem *item) +{ + // ### fall back (we need to recalculate the text item and call drawTextItem()) +} + void QPaintEngineEx::draw(const QVectorPath &path) { const QBrush &brush = state()->brush; diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index fccd1dc..4096907 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(const QPointF &position, QStaticTextItem *item); + virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast(QPaintEngine::state); } inline const QPainterState *state() const { return static_cast(QPaintEngine::state); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 83f66e2..1d7f57d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5719,8 +5719,10 @@ void QPainter::drawText(const QPointF &p, const QString &str) /*! Draws the given \a staticText beginning at the given \a position. - This function can be used to optimize drawing text if the text and its layout is updated + This function can be used to optimize drawing text if the text and its layout is updated seldomly. + + \sa QStaticText */ void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) { @@ -5728,9 +5730,19 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static if (!d->engine || staticText.isEmpty() || pen().style() == Qt::NoPen) return; - const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); - bool restoreWhenFinished = false; + const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); + // If we don't have an extended paint engine, or if the painter is transformed, + // we go through standard code path + if (d->extended == 0 || !d->state->matrix.isIdentity()) { + if (staticText_d->size.isValid()) + drawText(QRectF(position, staticText_d->size), staticText_d->text); + else + drawText(position, staticText_d->text); + return; + } + + bool restoreWhenFinished = false; if (staticText_d->size.isValid()) { setClipRect(QRectF(position, staticText_d->size)); @@ -5746,8 +5758,8 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static } for (int i=0; iitemCount; ++i) { - const QTextItemInt &gf = staticText_d->items[i]; - d->engine->drawTextItem(staticText_d->itemPositions[i] + position, gf); + QStaticTextItem *item = staticText_d->items + i; + d->extended->drawStaticTextItem(position, item); } if (restoreWhenFinished) diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 7b7f325..46da88e 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE // #define CACHE_DEBUG -void QTextureGlyphCache::populate(const QTextItemInt &ti, +void QTextureGlyphCache::populate(QFontEngine *fontEngine, const QVarLengthArray &glyphs, const QVarLengthArray &) { @@ -64,7 +64,7 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, qDebug() << " -> current transformation: " << m_transform; #endif - m_current_textitem = &ti; + m_current_fontengine = fontEngine; const int margin = glyphMargin(); QHash listItemCoordinates; @@ -77,7 +77,7 @@ void QTextureGlyphCache::populate(const QTextItemInt &ti, 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", @@ -182,7 +182,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const break; }; - QFontEngineFT *ft = static_cast (m_current_textitem->fontEngine); + QFontEngineFT *ft = static_cast (m_current_fontengine); QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform); if (gset && ft->loadGlyphs(gset, &g, 1, format)) { @@ -194,9 +194,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(); } @@ -321,13 +321,13 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g) #ifdef CACHE_DEBUG // QPainter p(&m_image); // p.drawLine( - QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1); + /*QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1); if (m_image.rect().contains(base)) m_image.setPixel(base, 255); m_image.save(QString::fromLatin1("cache-%1-%2-%3.png") .arg(m_current_textitem->font().family()) .arg(m_current_textitem->font().pointSize()) - .arg(m_transform.type())); + .arg(m_transform.type()));*/ #endif } diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index d347e61..2f7fc96 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -76,7 +76,8 @@ 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_w(0), m_h(0), m_cx(0), m_cy(0), + m_current_fontengine(0) { } virtual ~QTextureGlyphCache() { } @@ -90,7 +91,7 @@ public: int baseLineY; }; - void populate(const QTextItemInt &ti, + void populate(QFontEngine *fontEngine, const QVarLengthArray &glyphs, const QVarLengthArray &positions); @@ -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 index 70e1c47..c43eeb0 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -262,7 +262,7 @@ bool QStaticText::isEmpty() const } QStaticTextPrivate::QStaticTextPrivate() - : glyphLayoutMemory(0), logClusterMemory(0), items(0), itemPositions(0), itemCount(0) + : items(0), itemCount(0) { ref = 1; } @@ -278,10 +278,7 @@ QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) QStaticTextPrivate::~QStaticTextPrivate() { - delete[] glyphLayoutMemory; - delete[] logClusterMemory; - delete[] items; - delete[] itemPositions; + delete[] items; } QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) @@ -298,43 +295,37 @@ namespace { class DrawTextItemRecorder: public QPaintEngine { public: - DrawTextItemRecorder(int expectedItemCount, int expectedGlyphCount, - QTextItemInt *items, - QPointF *positions, - char *glyphLayoutMemory, - unsigned short *logClusterMemory) + DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items) : m_items(items), - m_positions(positions), - m_glyphLayoutMemory(glyphLayoutMemory), - m_logClusterMemory(logClusterMemory), - m_glyphLayoutMemoryOffset(0), - m_logClusterMemoryOffset(0), m_expectedItemCount(expectedItemCount), - m_expectedGlyphCount(expectedGlyphCount), - m_glyphCount(0), m_itemCount(0) { } virtual void drawTextItem(const QPointF &p, const QTextItem &textItem) { - const QTextItemInt &ti = static_cast(textItem); - + const QTextItemInt &ti = static_cast(textItem); + + Q_ASSERT(m_expectedItemCount < 0 || m_itemCount < m_expectedItemCount); m_itemCount++; - m_glyphCount += ti.glyphs.numGlyphs; - Q_ASSERT(m_expectedItemCount < 0 || m_itemCount <= m_expectedItemCount); - Q_ASSERT(m_expectedGlyphCount < 0 || m_glyphCount <= m_expectedGlyphCount); - - if (m_items == 0 || m_glyphLayoutMemory == 0 || m_logClusterMemory == 0 || m_positions == 0) + if (m_items == 0) return; - m_items[m_itemCount - 1] = ti.clone(m_glyphLayoutMemory + m_glyphLayoutMemoryOffset, - m_logClusterMemory + m_logClusterMemoryOffset); - m_positions[m_itemCount - 1] = p; + QStaticTextItem *currentItem = (m_items + (m_itemCount - 1)); + currentItem->fontEngine = ti.fontEngine; + currentItem->chars = ti.chars; + currentItem->numChars = ti.num_chars; + ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform(), ti.flags, currentItem->glyphs, + currentItem->glyphPositions); + + QFixed fx = QFixed::fromReal(p.x()); + QFixed fy = QFixed::fromReal(p.y()); - m_glyphLayoutMemoryOffset += QGlyphLayout::spaceNeededForGlyphLayout(ti.glyphs.numGlyphs); - m_logClusterMemoryOffset += ti.glyphs.numGlyphs; + for (int i=0; iglyphPositions.size(); ++i) { + currentItem->glyphPositions[i].x += fx; + currentItem->glyphPositions[i].y += fy; + } } @@ -347,40 +338,23 @@ namespace { return User; } - int glyphCount() const - { - return m_glyphCount; - } - int itemCount() const { return m_itemCount; } private: - QTextItemInt *m_items; - char *m_glyphLayoutMemory; - unsigned short *m_logClusterMemory; - QPointF *m_positions; - - int m_glyphLayoutMemoryOffset; - int m_logClusterMemoryOffset; - int m_expectedGlyphCount; - int m_expectedItemCount; - int m_glyphCount; + QStaticTextItem *m_items; int m_itemCount; + int m_expectedItemCount; }; class DrawTextItemDevice: public QPaintDevice { public: - DrawTextItemDevice(int expectedItemCount = -1, int expectedGlyphCount = -1, - QTextItemInt *items = 0, QPointF *positions = 0, - char *glyphLayoutMemory = 0, unsigned short *logClusterMemory = 0) + DrawTextItemDevice(int expectedItemCount = -1, QStaticTextItem *items = 0) { - m_paintEngine = new DrawTextItemRecorder(expectedItemCount, expectedGlyphCount, - items, positions,glyphLayoutMemory, - logClusterMemory); + m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items); } ~DrawTextItemDevice() @@ -424,11 +398,6 @@ namespace { return m_paintEngine; } - int glyphCount() const - { - return m_paintEngine->glyphCount(); - } - int itemCount() const { return m_paintEngine->itemCount(); @@ -438,17 +407,13 @@ namespace { private: DrawTextItemRecorder *m_paintEngine; - QRectF brect; }; } void QStaticTextPrivate::init() { - delete[] glyphLayoutMemory; - delete[] logClusterMemory; delete[] items; - delete[] itemPositions; // Draw once to count number of items and glyphs, so that we can use as little memory // as possible to store the data @@ -464,16 +429,10 @@ void QStaticTextPrivate::init() } itemCount = counterDevice.itemCount(); - items = new QTextItemInt[itemCount]; - itemPositions = new QPointF[itemCount]; - - int glyphCount = counterDevice.glyphCount(); - glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(glyphCount)]; - logClusterMemory = new unsigned short[glyphCount]; + items = new QStaticTextItem[itemCount]; // Draw again to actually record the items and glyphs - DrawTextItemDevice recorderDevice(itemCount, glyphCount, items, itemPositions, - glyphLayoutMemory, logClusterMemory); + DrawTextItemDevice recorderDevice(itemCount, items); { QPainter painter(&recorderDevice); painter.setFont(font); diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index f5fd8d3..2a8d23a 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -54,8 +54,26 @@ // #include +#include -QT_BEGIN_NAMESPACE +QT_BEGIN_NAMESPACE + +class QStaticTextItem +{ +public: + QStaticTextItem() : chars(0), numChars(0), fontEngine(0) {} + + QVarLengthArray glyphPositions; // 8 bytes per glyph + QVarLengthArray glyphs; // 4 bytes per glyph + const QChar *chars; // 2 bytes per glyph + // ================= + // 14 bytes per glyph + + int numChars; // 4 bytes per item + QFontEngine *fontEngine; // 4 bytes per item + // ================ + // 8 bytes per item +}; class QStaticText; class QStaticTextPrivate @@ -67,19 +85,17 @@ public: void init(); - QAtomicInt ref; + QAtomicInt ref; // 4 bytes per text - QString text; - QFont font; - QSizeF size; + QString text; // 4 bytes per text + QFont font; // 8 bytes per text + QSizeF size; // 16 bytes per text - QTextItemInt *items; - QPointF *itemPositions; - int itemCount; + QStaticTextItem *items; // 4 bytes per text + int itemCount; // 4 bytes per text + // ================ + // 40 bytes per text - char *glyphLayoutMemory; - unsigned short *logClusterMemory; - static QStaticTextPrivate *get(const QStaticText *q); }; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index caa679b..02a5246 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1272,7 +1272,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly } cache->setPaintEnginePrivate(this); - cache->populate(ti, glyphs, positions); + cache->populate(ti.fontEngine, glyphs, positions); if (cache->width() == 0 || cache->height() == 0) return; -- cgit v0.12 From 5290c50b240abbcd0477df1db1808d33b96ca856 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 17 Aug 2009 15:29:02 +0200 Subject: Support transformations in drawStaticText() and optimize for space 1. Support transformations on the painter in drawStaticText(). Transforming the painter will cause the text layout to be recalculated, except for translations, which are handled by shifting the position of the text items. 2. Make const length arrays of the internal data in QStaticTextItem in order to minimize the memory consumption. --- src/gui/painting/qpaintengine_raster.cpp | 34 +++++----- src/gui/painting/qpaintengine_raster_p.h | 6 +- src/gui/painting/qpaintengineex.cpp | 2 +- src/gui/painting/qpainter.cpp | 31 +++++++-- src/gui/painting/qtextureglyphcache.cpp | 7 +- src/gui/painting/qtextureglyphcache_p.h | 5 +- src/gui/text/qstatictext.cpp | 77 +++++++++++++++++----- src/gui/text/qstatictext_p.h | 27 ++++---- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- 9 files changed, 130 insertions(+), 61 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 387d646..87f374c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3007,23 +3007,22 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx blend(current, spans, &s->penData); } -void QRasterPaintEngine::drawCachedGlyphs(const QVarLengthArray &glyphs, - const QVarLengthArray &positions, - QFontEngine *fontEngine, - const QTransform &matrix) +void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, + const QFixedPoint *positions, QFontEngine *fontEngine) { Q_D(QRasterPaintEngine); + QRasterPaintEngineState *s = state(); QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; QImageTextureGlyphCache *cache = - static_cast(fontEngine->glyphCache(0, glyphType, matrix)); + static_cast(fontEngine->glyphCache(0, glyphType, s->matrix)); if (!cache) { - cache = new QImageTextureGlyphCache(glyphType, matrix); + cache = new QImageTextureGlyphCache(glyphType, s->matrix); fontEngine->setGlyphCache(0, cache); } - cache->populate(fontEngine, glyphs, positions); + cache->populate(fontEngine, numGlyphs, glyphs, positions); const QImage &image = cache->image(); int bpl = image.bytesPerLine(); @@ -3041,7 +3040,7 @@ void QRasterPaintEngine::drawCachedGlyphs(const QVarLengthArray &glyphs const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); const uchar *bits = image.bits(); - for (int i=0; icoords.value(glyphs[i]); int x = qFloor(positions[i].x + offs) + c.baseLineX - margin; int y = qFloor(positions[i].y + offs) - c.baseLineY - margin; @@ -3218,19 +3217,16 @@ void QRasterPaintEngine::drawStaticTextItem(const QPointF &p, QStaticTextItem *t ensurePen(); ensureState(); - QTransform matrix; - matrix.translate(p.x(), p.y()); - // Translate to actual position - QVarLengthArray glyphPositions = textItem->glyphPositions; - QFixed fx = QFixed::fromReal(p.x()); QFixed fy = QFixed::fromReal(p.y()); - for (int i=0; inumGlyphs; ++i) { + textItem->glyphPositions[i].x += fx; + textItem->glyphPositions[i].y += fy; } - drawCachedGlyphs(textItem->glyphs, glyphPositions, textItem->fontEngine, matrix); + + drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, + textItem->fontEngine); } /*! @@ -3285,11 +3281,13 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte QVarLengthArray positions; QVarLengthArray glyphs; + QTransform matrix = s->matrix; matrix.translate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - drawCachedGlyphs(glyphs, positions, ti.fontEngine, matrix); + 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 0250c3d..0626a48 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -257,10 +257,8 @@ private: void fillRect(const QRectF &rect, QSpanData *data); void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); - void drawCachedGlyphs(const QVarLengthArray &glyphs, - const QVarLengthArray &positions, - QFontEngine *fontEngine, - const QTransform &matrix); + void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, + QFontEngine *fontEngine); void drawStaticTextItem(const QPointF &p, QStaticTextItem *textItem); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 15085f9..f167b348 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -592,7 +592,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) void QPaintEngineEx::drawStaticTextItem(const QPointF &position, QStaticTextItem *item) { - // ### fall back (we need to recalculate the text item and call drawTextItem()) + // ### Make this pure virtual after implementing in all subclasses } void QPaintEngineEx::draw(const QVectorPath &path) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 1d7f57d..4eace16 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5730,11 +5730,12 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static if (!d->engine || staticText.isEmpty() || pen().style() == Qt::NoPen) return; - const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText); + QStaticTextPrivate *staticText_d = + const_cast(QStaticTextPrivate::get(&staticText)); // If we don't have an extended paint engine, or if the painter is transformed, // we go through standard code path - if (d->extended == 0 || !d->state->matrix.isIdentity()) { + if (d->extended == 0) { if (staticText_d->size.isValid()) drawText(QRectF(position, staticText_d->size), staticText_d->text); else @@ -5742,14 +5743,33 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static 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 translatedPosition = position; + QTransform matrix = d->state->transform(); + if (matrix.isTranslating()) { + translatedPosition.rx() += matrix.dx(); + translatedPosition.ry() += matrix.dy(); + translate(-matrix.dx(), -matrix.dy()); + } + + // If the transform is not identical to the text transform, + // we have to relayout the text (for other transformations than plain translation) + if (staticText_d->matrix != d->state->transform()) { + staticText_d->matrix = d->state->transform(); + staticText_d->init(); + } + bool restoreWhenFinished = false; if (staticText_d->size.isValid()) { + save(); setClipRect(QRectF(position, staticText_d->size)); - save(); restoreWhenFinished = true; } + // ### Should we pick up the painter's font and recalculate the layout, like we do + // with the matrix? if (font() != staticText_d->font) { setFont(staticText_d->font); @@ -5759,11 +5779,14 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static for (int i=0; iitemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; - d->extended->drawStaticTextItem(position, item); + d->extended->drawStaticTextItem(translatedPosition, item); } if (restoreWhenFinished) restore(); + + if (matrix.isTranslating()) + setTransform(matrix); } /*! diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 46da88e..5a6a0d9 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -55,9 +55,8 @@ QT_BEGIN_NAMESPACE // #define CACHE_DEBUG -void QTextureGlyphCache::populate(QFontEngine *fontEngine, - const QVarLengthArray &glyphs, - const QVarLengthArray &) +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()); @@ -71,7 +70,7 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, 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; diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 2f7fc96..b8717b1 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -91,9 +91,8 @@ public: int baseLineY; }; - void populate(QFontEngine *fontEngine, - const QVarLengthArray &glyphs, - const QVarLengthArray &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; diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index c43eeb0..e6f2cc6 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -262,7 +262,7 @@ bool QStaticText::isEmpty() const } QStaticTextPrivate::QStaticTextPrivate() - : items(0), itemCount(0) + : items(0), itemCount(0), glyphPool(0), positionPool(0) { ref = 1; } @@ -279,6 +279,8 @@ QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) QStaticTextPrivate::~QStaticTextPrivate() { delete[] items; + delete[] glyphPool; + delete[] positionPool; } QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) @@ -295,37 +297,58 @@ namespace { class DrawTextItemRecorder: public QPaintEngine { public: - DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items) + DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items, + int expectedGlyphCount, QFixedPoint *positionPool, glyph_t *glyphPool) : m_items(items), m_expectedItemCount(expectedItemCount), - m_itemCount(0) + m_expectedGlyphCount(expectedGlyphCount), + m_itemCount(0), m_glyphCount(0), + m_positionPool(positionPool), + m_glyphPool(glyphPool) { } virtual void drawTextItem(const QPointF &p, const QTextItem &textItem) { const QTextItemInt &ti = static_cast(textItem); - - Q_ASSERT(m_expectedItemCount < 0 || m_itemCount < m_expectedItemCount); - m_itemCount++; + 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->chars = ti.chars; currentItem->numChars = ti.num_chars; - ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform(), ti.flags, currentItem->glyphs, - currentItem->glyphPositions); + currentItem->numGlyphs = ti.glyphs.numGlyphs; + currentItem->glyphs = m_glyphPool; + currentItem->glyphPositions = m_positionPool; + + QVarLengthArray glyphs; + QVarLengthArray positions; + ti.fontEngine->getGlyphPositions(ti.glyphs, state->transform(), 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); QFixed fx = QFixed::fromReal(p.x()); QFixed fy = QFixed::fromReal(p.y()); - - for (int i=0; iglyphPositions.size(); ++i) { + for (int i=0; iglyphPositions[i].x += fx; currentItem->glyphPositions[i].y += fy; } + + m_glyphPool += size; + m_positionPool += size; } @@ -343,18 +366,31 @@ namespace { 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) + DrawTextItemDevice(int expectedItemCount = -1, QStaticTextItem *items = 0, + int expectedGlyphCount = -1, QFixedPoint *positionPool = 0, + glyph_t *glyphPool = 0) { - m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items); + m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items, + expectedGlyphCount, positionPool, glyphPool); } ~DrawTextItemDevice() @@ -403,7 +439,10 @@ namespace { return m_paintEngine->itemCount(); } - + int glyphCount() const + { + return m_paintEngine->glyphCount(); + } private: DrawTextItemRecorder *m_paintEngine; @@ -414,6 +453,8 @@ namespace { void QStaticTextPrivate::init() { delete[] items; + delete[] glyphPool; + delete[] positionPool; // Draw once to count number of items and glyphs, so that we can use as little memory // as possible to store the data @@ -421,6 +462,7 @@ void QStaticTextPrivate::init() { QPainter painter(&counterDevice); painter.setFont(font); + painter.setTransform(matrix); if (size.isValid()) painter.drawText(QRectF(QPointF(0, 0), size), text); @@ -428,14 +470,19 @@ void QStaticTextPrivate::init() painter.drawText(0, 0, text); } - itemCount = counterDevice.itemCount(); + itemCount = counterDevice.itemCount(); items = new QStaticTextItem[itemCount]; + 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); + DrawTextItemDevice recorderDevice(itemCount, items, glyphCount, positionPool, glyphPool); { QPainter painter(&recorderDevice); painter.setFont(font); + painter.setTransform(matrix); if (size.isValid()) painter.drawText(QRectF(QPointF(0, 0), size), text); diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 2a8d23a..e1ae80d 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -63,16 +63,18 @@ class QStaticTextItem public: QStaticTextItem() : chars(0), numChars(0), fontEngine(0) {} - QVarLengthArray glyphPositions; // 8 bytes per glyph - QVarLengthArray glyphs; // 4 bytes per glyph + // ### Use constant length arrays here to minimize memory consumption + QFixedPoint *glyphPositions; // 8 bytes per glyph + glyph_t *glyphs; // 4 bytes per glyph const QChar *chars; // 2 bytes per glyph // ================= // 14 bytes per glyph + int numGlyphs; // 4 bytes per item int numChars; // 4 bytes per item QFontEngine *fontEngine; // 4 bytes per item // ================ - // 8 bytes per item + // 12 bytes per item }; class QStaticText; @@ -85,16 +87,19 @@ public: void init(); - QAtomicInt ref; // 4 bytes per text + QAtomicInt ref; // 4 bytes per text - QString text; // 4 bytes per text - QFont font; // 8 bytes per text - QSizeF size; // 16 bytes per text + QString text; // 4 bytes per text + QFont font; // 8 bytes per text + QSizeF size; // 16 bytes per text - QStaticTextItem *items; // 4 bytes per text - int itemCount; // 4 bytes per text - // ================ - // 40 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 + // ================ + // 128 bytes per text static QStaticTextPrivate *get(const QStaticText *q); }; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 02a5246..e4fe84f 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1272,7 +1272,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly } cache->setPaintEnginePrivate(this); - cache->populate(ti.fontEngine, glyphs, positions); + cache->populate(ti.fontEngine, glyphs.size(), glyphs.constData(), positions.constData()); if (cache->width() == 0 || cache->height() == 0) return; -- cgit v0.12 From 5ea1825ec7a19a9b02eacf5c6f558536e085c510 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 17 Aug 2009 16:16:21 +0200 Subject: Some documentation fixes Clarify the use of transformations combined with static texts. --- src/gui/text/qstatictext.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index e6f2cc6..5b0b471 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -42,6 +42,7 @@ #include "qstatictext.h" #include "qstatictext_p.h" #include +#include #include @@ -60,9 +61,11 @@ QT_BEGIN_NAMESPACE 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 text is static over several paint - events. If the text or its layout is changed regularly, QPainter::drawText() is the more - efficient alternative. + The class primarily provides an optimization for cases where text and the transformations on + the painter are static over several paint events. If the text or its layout is changed + regularly, QPainter::drawText() is the more efficient alternative. Translating the painter + will not affect the performance of drawStaticText(), but altering any other parts of the + painter's transformation will cause the layout of the static text to be recalculated. \code class MyWidget: public QWidget @@ -91,7 +94,7 @@ QT_BEGIN_NAMESPACE 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 vertically at the given height. The position of the text is decided by the argument + 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 without affecting performance. -- cgit v0.12 From 6aa3acf3e1a8a45cc820e2132aac030ed86a6a15 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 17 Aug 2009 16:17:25 +0200 Subject: Allow access to QStaticTextPrivate from autotests Remove a private include which was unresolvable in autotests (because it indirectly included a 3rdparty header) and add Q_AUTOTEST_EXPORT. --- src/gui/text/qstatictext_p.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index e1ae80d..2cb1262 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -53,12 +53,11 @@ // We mean it. // -#include -#include +#include QT_BEGIN_NAMESPACE -class QStaticTextItem +class Q_AUTOTEST_EXPORT QStaticTextItem { public: QStaticTextItem() : chars(0), numChars(0), fontEngine(0) {} @@ -78,7 +77,7 @@ public: }; class QStaticText; -class QStaticTextPrivate +class Q_AUTOTEST_EXPORT QStaticTextPrivate { public: QStaticTextPrivate(); -- cgit v0.12 From 6ebcad8e355a3d076cf76a3d670c1abbf5e9b1c7 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 17 Aug 2009 16:18:45 +0200 Subject: Add autotests for transformed static text Most of these tests currently fail revealing som offset bugs in the painting code. --- tests/auto/qstatictext/tst_qstatictext.cpp | 184 +++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 4a01124..47be17d 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -45,6 +45,10 @@ #include #include +#include + +// #define DEBUG_SAVE_IMAGE + class tst_QStaticText: public QObject { Q_OBJECT @@ -57,6 +61,13 @@ private slots: void drawToRect(); void setFont(); void setMaximumSize(); + + void translatedPainter(); + void rotatedPainter(); + void scaledPainter(); + void rotatedScaledAndTranslatedPainter(); + void transformationChanged(); + void translationDoesntCauseRelayout(); }; void tst_QStaticText::init() @@ -152,6 +163,179 @@ void tst_QStaticText::setMaximumSize() QCOMPARE(imageDrawStaticText, imageDrawText); } +void tst_QStaticText::translatedPainter() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.translate(100, 200); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.translate(100, 200); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::rotatedPainter() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.rotate(30.0); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.rotate(30.0); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("rotatedPainter_imageDrawText.png"); + imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); + +} + +void tst_QStaticText::scaledPainter() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.scale(2.0, 0.2); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.scale(2.0, 0.2); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::rotatedScaledAndTranslatedPainter() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.rotate(45.0); + p.scale(0.2, 2.0); + p.translate(100, 200); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.rotate(45.0); + p.scale(0.2, 2.0); + p.translate(100, 200); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::transformationChanged() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.rotate(33.0); + p.scale(0.5, 0.7); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + p.rotate(77.0); + p.scale(0.7, 0.5); + p.drawText(100, 200, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.rotate(33.0); + p.scale(0.5, 0.7); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + + p.rotate(77.0); + p.scale(0.7, 0.5); + p.drawStaticText(100, 200, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::translationDoesntCauseRelayout() +{ + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.rotate(33.0); + p.scale(0.5, 0.7); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + p.translate(100, 200); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.rotate(33.0); + p.scale(0.5, 0.7); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + QStaticTextPrivate *textd = QStaticTextPrivate::get(&text); + glyph_t *glyphPool = textd->glyphPool; + QFixedPoint *positionPool = textd->positionPool; + QStaticTextItem *items = textd->items; + + p.drawStaticText(11, 12, text); + + p.translate(100, 200); + p.drawStaticText(11, 12, text); + + // ### + // If the layout is recalculated, the data is reallocated. Not a entirely deterministic + // test, since the memory can be reused. + QCOMPARE(textd->glyphPool, glyphPool); + QCOMPARE(textd->positionPool, positionPool); + QCOMPARE(textd->items, items); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); + +} QTEST_MAIN(tst_QStaticText) -- cgit v0.12 From f7476c80f61de0e7a0a1454d80e7d6808cb89593 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 19 Aug 2009 15:26:55 +0200 Subject: Apply painter matrix to position in QPainter::drawStaticText() We need to transform the position of the text in accordance with the painter's matrix. Also, use state->matrix directly instead of calling a function to get it. --- src/gui/painting/qpainter.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 4eace16..9ad19f0 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5745,18 +5745,17 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // 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 translatedPosition = position; - QTransform matrix = d->state->transform(); - if (matrix.isTranslating()) { - translatedPosition.rx() += matrix.dx(); - translatedPosition.ry() += matrix.dy(); - translate(-matrix.dx(), -matrix.dy()); - } + QPointF transformedPosition = position * d->state->matrix; + QTransform matrix = d->state->matrix; + + // Already added in transformedPosition + if (d->state->matrix.isTranslating()) + translate(-d->state->matrix.dx(), -d->state->matrix.dy()); // If the transform is not identical to the text transform, // we have to relayout the text (for other transformations than plain translation) - if (staticText_d->matrix != d->state->transform()) { - staticText_d->matrix = d->state->transform(); + if (staticText_d->matrix != d->state->matrix) { + staticText_d->matrix = d->state->matrix; staticText_d->init(); } @@ -5779,7 +5778,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static for (int i=0; iitemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; - d->extended->drawStaticTextItem(translatedPosition, item); + d->extended->drawStaticTextItem(transformedPosition, item); } if (restoreWhenFinished) -- cgit v0.12 From 5247001c8d1a012b5895223dd7f09a9a0fd9286e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 19 Aug 2009 15:28:55 +0200 Subject: Speed up QStaticText initialization Instead of translating each position manually afterwards, just have the matrix do it when calculating the positions inside getGlyphPositions(). --- src/gui/text/qstatictext.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 5b0b471..30935f9 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -311,7 +311,7 @@ namespace { { } - virtual void drawTextItem(const QPointF &p, const QTextItem &textItem) + virtual void drawTextItem(const QPointF &position, const QTextItem &textItem) { const QTextItemInt &ti = static_cast(textItem); @@ -331,10 +331,12 @@ namespace { currentItem->glyphs = m_glyphPool; currentItem->glyphPositions = m_positionPool; + QTransform matrix = state->transform(); + matrix.translate(position.x(), position.y()); + QVarLengthArray glyphs; QVarLengthArray positions; - ti.fontEngine->getGlyphPositions(ti.glyphs, state->transform(), ti.flags, - glyphs, positions); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); int size = glyphs.size(); Q_ASSERT(size == ti.glyphs.numGlyphs); @@ -343,13 +345,6 @@ namespace { memmove(currentItem->glyphs, glyphs.constData(), sizeof(glyph_t) * size); memmove(currentItem->glyphPositions, positions.constData(), sizeof(QFixedPoint) * size); - QFixed fx = QFixed::fromReal(p.x()); - QFixed fy = QFixed::fromReal(p.y()); - for (int i=0; iglyphPositions[i].x += fx; - currentItem->glyphPositions[i].y += fy; - } - m_glyphPool += size; m_positionPool += size; } -- cgit v0.12 From bf86841fd9ec41263b2fd53b3f69661f09cfa9b9 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 19 Aug 2009 15:30:25 +0200 Subject: Ignore rounding error when painting to rotated painter There are tiny rounding errors in the matrix rotations which cause tiny differences in drawText() and drawStaticText(). I've chosen to ignore these. Instead of having a threshold on the comparison between the two images, I've chosen to take the easy way out and avoid the problem by not passing in any position for the text. --- tests/auto/qstatictext/tst_qstatictext.cpp | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 47be17d..0eda3c3 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -47,7 +47,7 @@ #include -// #define DEBUG_SAVE_IMAGE +#define DEBUG_SAVE_IMAGE class tst_QStaticText: public QObject { @@ -191,17 +191,16 @@ void tst_QStaticText::rotatedPainter() { QPainter p(&imageDrawText); p.rotate(30.0); - - p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + QPainter p(&imageDrawStaticText); p.rotate(30.0); - - QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(11, 12, text); + p.drawStaticText(0, 0, text); } #if defined(DEBUG_SAVE_IMAGE) @@ -210,7 +209,6 @@ void tst_QStaticText::rotatedPainter() #endif QCOMPARE(imageDrawStaticText, imageDrawText); - } void tst_QStaticText::scaledPainter() @@ -264,16 +262,16 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() void tst_QStaticText::transformationChanged() { QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { QPainter p(&imageDrawText); p.rotate(33.0); p.scale(0.5, 0.7); - p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.rotate(77.0); - p.scale(0.7, 0.5); - p.drawText(100, 200, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.scale(7.0, 5.0); + p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); @@ -283,13 +281,17 @@ void tst_QStaticText::transformationChanged() p.scale(0.5, 0.7); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(11, 12, text); + p.drawStaticText(0, 0, text); - p.rotate(77.0); - p.scale(0.7, 0.5); - p.drawStaticText(100, 200, text); + p.scale(7.0, 5.0); + p.drawStaticText(0, 0, text); } +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("transformationChanged_imageDrawText.png"); + imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png"); +#endif + QCOMPARE(imageDrawStaticText, imageDrawText); } -- cgit v0.12 From 73d686c7e8ddb075e1fd3219f0c212bfc5cac200 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 19 Aug 2009 15:36:20 +0200 Subject: Remove debug output Don't save images by default. --- tests/auto/qstatictext/tst_qstatictext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 0eda3c3..50a1d2e 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -47,7 +47,7 @@ #include -#define DEBUG_SAVE_IMAGE +// #define DEBUG_SAVE_IMAGE class tst_QStaticText: public QObject { -- cgit v0.12 From 161f6b4ccdec38c9817672ad977f4d025acb14f4 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 19 Aug 2009 15:39:20 +0200 Subject: Ignore rounding errors in QStaticText test Combining rotations and translations will cause minor differences between drawText() and drawStaticText(). This is not what the function is testing, so it has been massaged to pass. --- tests/auto/qstatictext/tst_qstatictext.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 50a1d2e..3a407c8 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -300,21 +300,15 @@ void tst_QStaticText::translationDoesntCauseRelayout() QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawText); - p.rotate(33.0); - p.scale(0.5, 0.7); - - p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); p.translate(100, 200); - p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawStaticText); - p.rotate(33.0); - p.scale(0.5, 0.7); - QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); QStaticTextPrivate *textd = QStaticTextPrivate::get(&text); @@ -322,10 +316,10 @@ void tst_QStaticText::translationDoesntCauseRelayout() QFixedPoint *positionPool = textd->positionPool; QStaticTextItem *items = textd->items; - p.drawStaticText(11, 12, text); + p.drawStaticText(0, 0, text); p.translate(100, 200); - p.drawStaticText(11, 12, text); + p.drawStaticText(0, 0, text); // ### // If the layout is recalculated, the data is reallocated. Not a entirely deterministic @@ -336,7 +330,6 @@ void tst_QStaticText::translationDoesntCauseRelayout() } QCOMPARE(imageDrawStaticText, imageDrawText); - } -- cgit v0.12 From 7fbffd29e5904151a3a249004031d0502a16f4fc Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 20 Aug 2009 12:57:34 +0200 Subject: Remove font property in QStaticText and fix handling translation on painter 1. The font property in QStaticText has been removed. Rather than set a font on the text explicitly, it picks up the font from the painter. If you change the font on the painter, the text layout will have to be updated, like with a matrix. 2. The translation might not be the only transformation on the painter, so rather than translate back to origo, we explicitly set dx and dy on the transform to 0.0 for the duration of the function. 3. Update test to reflect changes --- src/gui/painting/qpainter.cpp | 35 ++++++++++++++++++++---------- src/gui/text/qstatictext.cpp | 33 ++++------------------------ src/gui/text/qstatictext.h | 7 +----- tests/auto/qstatictext/tst_qstatictext.cpp | 19 ++++++++++++---- 4 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 9ad19f0..c75547f 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5748,15 +5748,28 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static QPointF transformedPosition = position * d->state->matrix; QTransform matrix = d->state->matrix; - // Already added in transformedPosition - if (d->state->matrix.isTranslating()) - translate(-d->state->matrix.dx(), -d->state->matrix.dy()); + // 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; - staticText_d->init(); + staticTextNeedsReinit = true; } bool restoreWhenFinished = false; @@ -5767,15 +5780,15 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static restoreWhenFinished = true; } - // ### Should we pick up the painter's font and recalculate the layout, like we do - // with the matrix? if (font() != staticText_d->font) { - setFont(staticText_d->font); - - save(); - restoreWhenFinished = true; + 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(); + for (int i=0; iitemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; d->extended->drawStaticTextItem(transformedPosition, item); @@ -5785,7 +5798,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static restore(); if (matrix.isTranslating()) - setTransform(matrix); + d->state->matrix = matrix; } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 30935f9..d4f8fbd 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -116,11 +116,10 @@ QStaticText::QStaticText() \a font and bounded by the given \a maximumSize. If an invalid size is passed for \a maximumSize the text will be unbounded. */ -QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &size) +QStaticText::QStaticText(const QString &text, const QSizeF &size) : d_ptr(new QStaticTextPrivate) { d_ptr->text = text; - d_ptr->font = font; d_ptr->size = size; d_ptr->init(); } @@ -223,7 +222,7 @@ void QStaticText::setMaximumSize(const QSizeF &size) /*! Returns the maximum size of the QStaticText. - \sa setMaximumSize + \sa setMaximumSize() */ QSizeF QStaticText::maximumSize() const { @@ -231,34 +230,10 @@ QSizeF QStaticText::maximumSize() const } /*! - Sets the font of the QStaticText to \a font. + Returns true if the text of the QStaticText is empty, and false if not. - \note This function will cause the layout of the text to be recalculated. - - \sa font() -*/ -void QStaticText::setFont(const QFont &font) -{ - detach(); - d_ptr->font = font; - d_ptr->init(); -} - -/*! - Returns the font of the QStaticText. - - \sa setFont() + \sa text() */ -QFont QStaticText::font() const -{ - return d_ptr->font; -} - -QString QStaticText::toString() const -{ - return text(); -} - bool QStaticText::isEmpty() const { return d_ptr->text.isEmpty(); diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 9830b32..c7b5429 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -57,16 +57,13 @@ class Q_GUI_EXPORT QStaticText { public: QStaticText(); - QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF()); + QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); QStaticText(const QStaticText &other); ~QStaticText(); void setText(const QString &text); QString text() const; - void setFont(const QFont &font); - QFont font() const; - void setMaximumSize(const QSizeF &maximumSize); QSizeF maximumSize() const; @@ -74,8 +71,6 @@ public: bool operator==(const QStaticText &) const; bool operator!=(const QStaticText &) const; - QString toString() const; - bool isEmpty() const; private: diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 3a407c8..0e1532b 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -112,7 +112,7 @@ void tst_QStaticText::drawToRect() QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawStaticText); - QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QFont(), QSizeF(10, 500)); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500)); p.drawStaticText(11, 12, text); } @@ -128,6 +128,8 @@ void tst_QStaticText::setFont() QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawText); + p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.setFont(font); p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } @@ -135,9 +137,12 @@ void tst_QStaticText::setFont() QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawStaticText); + QStaticText text; text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - text.setFont(font); + + p.drawStaticText(0, 0, text); + p.setFont(font); p.drawStaticText(11, 120, text); } @@ -300,6 +305,7 @@ void tst_QStaticText::translationDoesntCauseRelayout() QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawText); + p.scale(2.0, 2.0); p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); p.translate(100, 200); @@ -309,15 +315,15 @@ void tst_QStaticText::translationDoesntCauseRelayout() QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); { QPainter p(&imageDrawStaticText); + p.scale(2.0, 2.0); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(0, 0, text); QStaticTextPrivate *textd = QStaticTextPrivate::get(&text); glyph_t *glyphPool = textd->glyphPool; QFixedPoint *positionPool = textd->positionPool; QStaticTextItem *items = textd->items; - p.drawStaticText(0, 0, text); - p.translate(100, 200); p.drawStaticText(0, 0, text); @@ -329,6 +335,11 @@ void tst_QStaticText::translationDoesntCauseRelayout() QCOMPARE(textd->items, items); } +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("translationDoesntCauseRelayout_imageDrawText.png"); + imageDrawStaticText.save("translationDoesntCauseRelayout_imageDrawStaticText.png"); +#endif + QCOMPARE(imageDrawStaticText, imageDrawText); } -- cgit v0.12 From bf919e06127962836a6b566bf119cf248c6a999b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 21 Aug 2009 16:29:44 +0200 Subject: Implement drawStaticTextItem() in OpenGL paint engines The OpenGL and OpenGL2 engines now have support for static text, as well as the QEmulationPaintEngine. Also contains an optimization: Instead of passing both the position and glyph positions to drawStaticTextItem() we add the position into the glyph position and update it only when it changes. Otherwise we would have to do this work in all engines for every call. This means we have to cache the position in QStaticTextPrivate as well, but it seems like a small price to pay, since it's a per-text overhead and only 16 bytes. --- src/gui/painting/qemulationpaintengine.cpp | 5 ++ src/gui/painting/qemulationpaintengine_p.h | 1 + src/gui/painting/qpaintengine_raster.cpp | 10 +-- src/gui/painting/qpaintengine_raster_p.h | 2 +- src/gui/painting/qpaintengineex.cpp | 2 + src/gui/painting/qpaintengineex_p.h | 2 +- src/gui/painting/qpainter.cpp | 20 ++++- src/gui/text/qstatictext.cpp | 2 + src/gui/text/qstatictext_p.h | 5 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 55 +++++++++---- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 3 +- src/opengl/qpaintengine_opengl.cpp | 96 +++++++++++++--------- src/opengl/qpaintengine_opengl_p.h | 1 + 13 files changed, 135 insertions(+), 69 deletions(-) diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp index f2f0c73..4067b97 100644 --- a/src/gui/painting/qemulationpaintengine.cpp +++ b/src/gui/painting/qemulationpaintengine.cpp @@ -175,6 +175,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/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 87f374c..1fbfbb4 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3212,19 +3212,11 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect, return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend; } -void QRasterPaintEngine::drawStaticTextItem(const QPointF &p, QStaticTextItem *textItem) +void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { ensurePen(); ensureState(); - // Translate to actual position - QFixed fx = QFixed::fromReal(p.x()); - QFixed fy = QFixed::fromReal(p.y()); - for (int i=0; inumGlyphs; ++i) { - textItem->glyphPositions[i].x += fx; - textItem->glyphPositions[i].y += fy; - } - drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, textItem->fontEngine); } diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 0626a48..e441a6b 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -260,7 +260,7 @@ private: void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine); - void drawStaticTextItem(const QPointF &p, QStaticTextItem *textItem); + void drawStaticTextItem(QStaticTextItem *textItem); #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti); diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index f167b348..1bbdafa 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -590,10 +590,12 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) } } +/* void QPaintEngineEx::drawStaticTextItem(const QPointF &position, QStaticTextItem *item) { // ### Make this pure virtual after implementing in all subclasses } +*/ void QPaintEngineEx::draw(const QVectorPath &path) { diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 4096907..85090bd 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -201,7 +201,7 @@ public: virtual void updateState(const QPaintEngineState &state); - virtual void drawStaticTextItem(const QPointF &position, QStaticTextItem *item); + virtual void drawStaticTextItem(QStaticTextItem *item) = 0; virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast(QPaintEngine::state); } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index c75547f..524f243 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5787,11 +5787,27 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // Recreate the layout of the static text because the matrix or font has changed if (staticTextNeedsReinit) - staticText_d->init(); + 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; itemitemCount;++item) { + QStaticTextItem *textItem = staticText_d->items + item; + for (int i=0; inumGlyphs; ++i) { + textItem->glyphPositions[i].x += fx - oldX; + textItem->glyphPositions[i].y += fy - oldY; + } + } + + staticText_d->position = transformedPosition; + } for (int i=0; iitemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; - d->extended->drawStaticTextItem(transformedPosition, item); + d->extended->drawStaticTextItem(item); } if (restoreWhenFinished) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index d4f8fbd..56950ed 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -429,6 +429,8 @@ void QStaticTextPrivate::init() 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; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 2cb1262..4756773 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE -class Q_AUTOTEST_EXPORT QStaticTextItem +class Q_GUI_EXPORT QStaticTextItem { public: QStaticTextItem() : chars(0), numChars(0), fontEngine(0) {} @@ -91,6 +91,7 @@ public: QString text; // 4 bytes per text QFont font; // 8 bytes per text QSizeF size; // 16 bytes per text + QPointF position; // 16 bytes per text QTransform matrix; // 80 bytes per text QStaticTextItem *items; // 4 bytes per text @@ -98,7 +99,7 @@ public: glyph_t *glyphPool; // 4 bytes per text QFixedPoint *positionPool; // 4 bytes per text // ================ - // 128 bytes per text + // 144 bytes per text static QStaticTextPrivate *get(const QStaticText *q); }; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index e4fe84f..35087d2 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include "qglgradientcache_p.h" #include "qglengineshadermanager_p.h" @@ -1212,6 +1213,17 @@ void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const d->drawTexture(dest, srcRect, size, false); } +void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) +{ + Q_D(QGL2PaintEngineEx); + + ensureActive(); + + // ### What about transformations and huge fonts? These are not passed through cache + // in drawTextItem(). + d->drawCachedGlyphs(textItem); +} + void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) { Q_D(QGL2PaintEngineEx); @@ -1246,33 +1258,46 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem } if (drawCached) { - d->drawCachedGlyphs(p, glyphType, ti); + QVarLengthArray positions; + QVarLengthArray glyphs; + QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + { + QStaticTextItem staticTextItem; + staticTextItem.chars = ti.chars; + staticTextItem.fontEngine = ti.fontEngine; + staticTextItem.glyphs = glyphs.data(); + staticTextItem.numChars = ti.num_chars; + staticTextItem.numGlyphs = glyphs.size(); + staticTextItem.glyphPositions = positions.data(); + + d->drawCachedGlyphs(&staticTextItem); + } return; } QPaintEngineEx::drawTextItem(p, ti); } -void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, - const QTextItemInt &ti) +void QGL2PaintEngineExPrivate::drawCachedGlyphs(QStaticTextItem *staticTextItem) { Q_Q(QGL2PaintEngineEx); - QVarLengthArray positions; - QVarLengthArray glyphs; - QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + QFontEngineGlyphCache::Type glyphType = staticTextItem->fontEngine->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(staticTextItem->fontEngine->glyphFormat) + : QFontEngineGlyphCache::Raster_A8; QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); - + (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); - ti.fontEngine->setGlyphCache(ctx, cache); + staticTextItem->fontEngine->setGlyphCache(ctx, cache); } cache->setPaintEnginePrivate(this); - cache->populate(ti.fontEngine, glyphs.size(), glyphs.constData(), positions.constData()); + cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs, + staticTextItem->glyphPositions); if (cache->width() == 0 || cache->height() == 0) return; @@ -1287,10 +1312,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly vertexCoordinateArray.clear(); textureCoordinateArray.clear(); - for (int i=0; icoords.value(glyphs[i]); - int x = positions[i].x.toInt() + c.baseLineX - margin; - int y = positions[i].y.toInt() - c.baseLineY - margin; + for (int i=0; inumGlyphs; ++i) { + const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); + int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; + int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index ce1b538..b683b8b 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -133,6 +133,7 @@ public: virtual void stroke(const QVectorPath &path, const QPen &pen); virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + virtual void drawStaticTextItem(QStaticTextItem *textItem); Type type() const { return OpenGL2; } @@ -194,7 +195,7 @@ public: void stroke(const QVectorPath &path, const QPen &pen); void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); - void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti); + void drawCachedGlyphs(QStaticTextItem *staticTextItem); // Calls glVertexAttributePointer if the pointer has changed inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer); diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 57918d0..d6175e9 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include "private/qtessellator_p.h" @@ -4555,7 +4556,7 @@ public: QGLGlyphCache() : QObject(0) { current_cache = 0; } ~QGLGlyphCache(); QGLGlyphCoord *lookup(QFontEngine *, glyph_t); - void cacheGlyphs(QGLContext *, const QTextItemInt &, const QVarLengthArray &); + void cacheGlyphs(QGLContext *, QFontEngine *, glyph_t *glyphs, int numGlyphs); void cleanCache(); void allocTexture(int width, int height, GLuint texture); @@ -4707,8 +4708,8 @@ static QImage getCurrentTexture(const QColor &color, QGLFontTexture *font_tex) } #endif -void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, - const QVarLengthArray &glyphs) +void QGLGlyphCache::cacheGlyphs(QGLContext *context, QFontEngine *fontEngine, + glyph_t *glyphs, int numGlyphs) { QGLContextHash::const_iterator dev_it = qt_context_cache.constFind(context); QGLFontGlyphHash *font_cache = 0; @@ -4744,25 +4745,25 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, } Q_ASSERT(font_cache != 0); - QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(ti.fontEngine); + QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(fontEngine); QGLGlyphHash *cache = 0; if (cache_it == font_cache->constEnd()) { cache = new QGLGlyphHash; - font_cache->insert(ti.fontEngine, cache); - connect(ti.fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*))); + font_cache->insert(fontEngine, cache); + connect(fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*))); } else { cache = cache_it.value(); } current_cache = cache; quint64 font_key = (reinterpret_cast(context_key ? context_key : context) << 32) - | reinterpret_cast(ti.fontEngine); + | reinterpret_cast(fontEngine); QGLFontTexHash::const_iterator it = qt_font_textures.constFind(font_key); QGLFontTexture *font_tex; if (it == qt_font_textures.constEnd()) { GLuint font_texture; glGenTextures(1, &font_texture); - GLint tex_height = qt_next_power_of_two(qRound(ti.ascent.toReal() + ti.descent.toReal())+2); + GLint tex_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2); GLint tex_width = qt_next_power_of_two(tex_height*30); // ### GLint max_tex_size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); @@ -4784,16 +4785,16 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, glBindTexture(GL_TEXTURE_2D, font_tex->texture); } - for (int i=0; i< glyphs.size(); ++i) { + for (int i=0; i< numGlyphs; ++i) { QGLGlyphHash::const_iterator it = cache->constFind(glyphs[i]); if (it == cache->constEnd()) { // render new glyph and put it in the cache - glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]); + glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]); int glyph_width = qRound(metrics.width.toReal())+2; - int glyph_height = qRound(ti.ascent.toReal() + ti.descent.toReal())+2; + int glyph_height = qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2; if (font_tex->x_offset + glyph_width + x_margin > font_tex->width) { - int strip_height = qt_next_power_of_two(qRound(ti.ascent.toReal() + ti.descent.toReal())+2); + int strip_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2); font_tex->x_offset = x_margin; font_tex->y_offset += strip_height; if (font_tex->y_offset >= font_tex->height) { @@ -4826,8 +4827,8 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, } } - QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i])); - glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8); + QImage glyph_im(fontEngine->alphaMapForGlyph(glyphs[i])); + glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8); glyph_width = glyph_im.width(); Q_ASSERT(glyph_width >= 0); // pad the glyph width to an even number @@ -4906,30 +4907,15 @@ void qgl_cleanup_glyph_cache(QGLContext *ctx) qt_glyph_cache()->cleanupContext(ctx); } -void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +void QOpenGLPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { Q_D(QOpenGLPaintEngine); - const QTextItemInt &ti = static_cast(textItem); - - // fall back to drawing a polygon if the scale factor is large, or - // we use a gradient pen - if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern - && d->pen_brush_style <= Qt::ConicalGradientPattern)) { - QPaintEngine::drawTextItem(p, textItem); - return; - } - d->flushDrawQueue(); - // add the glyphs used to the glyph texture cache - QVarLengthArray positions; - QVarLengthArray glyphs; - QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y())); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - // make sure the glyphs we want to draw are in the cache - qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs); + qt_glyph_cache()->cacheGlyphs(d->device.context(), textItem->fontEngine, textItem->glyphs, + textItem->numGlyphs); d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops qt_glColor4ubv(d->pen_color); @@ -4951,13 +4937,13 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - bool antialias = !(ti.fontEngine->fontDef.styleStrategy & QFont::NoAntialias) - && (d->matrix.type() > QTransform::TxTranslate); + bool antialias = !(textItem->fontEngine->fontDef.styleStrategy & QFont::NoAntialias) + && (d->matrix.type() > QTransform::TxTranslate); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST); - for (int i=0; i< glyphs.size(); ++i) { - QGLGlyphCoord *g = qt_glyph_cache()->lookup(ti.fontEngine, glyphs[i]); + for (int i=0; i< textItem->numGlyphs; ++i) { + QGLGlyphCoord *g = qt_glyph_cache()->lookup(textItem->fontEngine, textItem->glyphs[i]); // we don't cache glyphs with no width/height if (!g) @@ -4969,8 +4955,8 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte x2 = x1 + g->width; y2 = y1 + g->height; - QPointF logical_pos((positions[i].x - g->x_offset).toReal(), - (positions[i].y + g->y_offset).toReal()); + QPointF logical_pos((textItem->glyphPositions[i].x - g->x_offset).toReal(), + (textItem->glyphPositions[i].y + g->y_offset).toReal()); qt_add_rect_to_array(QRectF(logical_pos, QSizeF(g->log_width, g->log_height)), vertexArray); qt_add_texcoords_to_array(x1, y1, x2, y2, texCoordArray); @@ -4987,6 +4973,40 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte // XXX: This may not be needed as this behavior does seem to be caused by driver bug glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); #endif + +} + +void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ + Q_D(QOpenGLPaintEngine); + + const QTextItemInt &ti = static_cast(textItem); + + // fall back to drawing a polygon if the scale factor is large, or + // we use a gradient pen + if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern + && d->pen_brush_style <= Qt::ConicalGradientPattern)) { + QPaintEngine::drawTextItem(p, textItem); + return; + } + + // add the glyphs used to the glyph texture cache + QVarLengthArray positions; + QVarLengthArray glyphs; + QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y())); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + { + QStaticTextItem staticTextItem; + staticTextItem.chars = ti.chars; + staticTextItem.fontEngine = ti.fontEngine; + staticTextItem.glyphs = glyphs.data(); + staticTextItem.numChars = ti.num_chars; + staticTextItem.numGlyphs = glyphs.size(); + staticTextItem.glyphPositions = positions.data(); + drawStaticTextItem(&staticTextItem); + } + } diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h index de0086a..55f7792 100644 --- a/src/opengl/qpaintengine_opengl_p.h +++ b/src/opengl/qpaintengine_opengl_p.h @@ -133,6 +133,7 @@ public: void drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags conversionFlags); void drawTextItem(const QPointF &p, const QTextItem &ti); + void drawStaticTextItem(QStaticTextItem *staticTextItem); void drawEllipse(const QRectF &rect); -- cgit v0.12 From 378c08e56110b2a57c0112e5bfb189e28cc8e88f Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 24 Nov 2009 10:09:15 +0100 Subject: Compile Update the code to compile with merged changes. --- src/gui/painting/qpaintengineex_p.h | 2 +- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 17 ++++++++++++++++- src/opengl/qpaintengine_opengl.cpp | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 85090bd..1370e82 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -201,7 +201,7 @@ public: virtual void updateState(const QPaintEngineState &state); - virtual void drawStaticTextItem(QStaticTextItem *item) = 0; + virtual void drawStaticTextItem(QStaticTextItem *) { /* ### should be pure virtual ### */ }; virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast(QPaintEngine::state); } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 35087d2..638e4d3 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1194,6 +1194,21 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); } +void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) +{ + Q_D(QGL2PaintEngineEx); + + ensureActive(); + + QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat) + : d->glyphCacheType; + + // ### What about transformations and huge fonts? These are not passed through cache + // in drawTextItem(). + d->drawCachedGlyphs(glyphType, textItem); +} + void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) { Q_D(QGL2PaintEngineEx); @@ -1389,7 +1404,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QStaticTextItem *staticTextItem) updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); - glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); + glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2); diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index d6175e9..fecbc45 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -4828,7 +4828,7 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, QFontEngine *fontEngine, } QImage glyph_im(fontEngine->alphaMapForGlyph(glyphs[i])); - glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8); + glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8); glyph_width = glyph_im.width(); Q_ASSERT(glyph_width >= 0); // pad the glyph width to an even number -- cgit v0.12 From a9e08c091c822e65ae8453581c6fee4b94001682 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 1 Dec 2009 16:58:52 +0100 Subject: Add prepare() function to QStaticText Allow the QStaticText layout to be completely defined prior to painting by introducing a function for setting the font and transform on the object ahead of using it with a QPainter. --- src/gui/text/qstatictext.cpp | 23 +++++++++++++++++++++++ src/gui/text/qstatictext.h | 7 ++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 56950ed..9a0ddca 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -152,6 +152,29 @@ void QStaticText::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) +{ + d_ptr->matrix = matrix; + d_ptr->font = font; + d_ptr->init(); +} + + +/*! Assigns \a other to this QStaticText. */ QStaticText &QStaticText::operator=(const QStaticText &other) diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index c7b5429..e507d82 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -42,9 +42,12 @@ #ifndef QSTATICTEXT_H #define QSTATICTEXT_H +#include #include + +#include #include -#include + QT_BEGIN_HEADER @@ -67,6 +70,8 @@ public: void setMaximumSize(const QSizeF &maximumSize); QSizeF maximumSize() const; + void prepare(const QTransform &matrix, const QFont &font); + QStaticText &operator=(const QStaticText &); bool operator==(const QStaticText &) const; bool operator!=(const QStaticText &) const; -- cgit v0.12 From eb674a7ff5fad2f4a76e3b20873c574eb8a6135f Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 9 Dec 2009 14:23:02 +0100 Subject: Optimize drawStaticText() with rectangle destination In order to be feature consistent with drawText(), we have to clip the text whenever the text expands beyond its borders. This is a performance hit, but luckily we can detect the cases where it's necessary before-hand. --- src/gui/painting/qpainter.cpp | 2 +- src/gui/text/qstatictext.cpp | 15 +++++++++++---- src/gui/text/qstatictext_p.h | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 524f243..114492d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5773,7 +5773,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static } bool restoreWhenFinished = false; - if (staticText_d->size.isValid()) { + if (staticText_d->needsClipRect) { save(); setClipRect(QRectF(position, staticText_d->size)); diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 9a0ddca..85d3c81 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -263,7 +263,7 @@ bool QStaticText::isEmpty() const } QStaticTextPrivate::QStaticTextPrivate() - : items(0), itemCount(0), glyphPool(0), positionPool(0) + : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false) { ref = 1; } @@ -482,10 +482,17 @@ void QStaticTextPrivate::init() painter.setFont(font); painter.setTransform(matrix); - if (size.isValid()) - painter.drawText(QRectF(QPointF(0, 0), size), text); - else + if (size.isValid()) { + QRectF boundingRect; + painter.drawText(QRectF(QPointF(0, 0), size), 0, text, &boundingRect); + + needsClipRect = boundingRect.width() > size.width() + || boundingRect.height() > size.height(); + + } else { painter.drawText(0, 0, text); + needsClipRect = false; + } } } diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 4756773..0677920 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -62,7 +62,6 @@ class Q_GUI_EXPORT QStaticTextItem public: QStaticTextItem() : chars(0), numChars(0), fontEngine(0) {} - // ### Use constant length arrays here to minimize memory consumption QFixedPoint *glyphPositions; // 8 bytes per glyph glyph_t *glyphs; // 4 bytes per glyph const QChar *chars; // 2 bytes per glyph @@ -98,6 +97,8 @@ public: int itemCount; // 4 bytes per text glyph_t *glyphPool; // 4 bytes per text QFixedPoint *positionPool; // 4 bytes per text + + char needsClipRect : 1; // 1 byte per text // ================ // 144 bytes per text -- cgit v0.12 From f89a82b97eb5585fdb246fc71df7d64df5220971 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 11 Dec 2009 14:17:54 +0100 Subject: Update size comment in QStaticTextPrivate I've added a flag char, so the size of the static text is now one byte greater. --- src/gui/text/qstatictext_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 0677920..8c8cea8 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -100,7 +100,7 @@ public: char needsClipRect : 1; // 1 byte per text // ================ - // 144 bytes per text + // 145 bytes per text static QStaticTextPrivate *get(const QStaticText *q); }; -- cgit v0.12 From f53271c1cac46ad63612e951e34ffae34328fec6 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Fri, 15 Jan 2010 14:12:40 +1000 Subject: Move QtMobility multimedia framework into Qt. --- demos/demos.pro | 2 + demos/multimedia/multimedia.pro | 4 + src/multimedia/base/base.pri | 62 + src/multimedia/base/qgraphicsvideoitem.cpp | 299 ++++ src/multimedia/base/qgraphicsvideoitem.h | 92 ++ .../base/qlocalmediaplaylistprovider.cpp | 196 +++ src/multimedia/base/qlocalmediaplaylistprovider.h | 87 ++ src/multimedia/base/qmediacontent.cpp | 219 +++ src/multimedia/base/qmediacontent.h | 90 ++ src/multimedia/base/qmediacontrol.cpp | 139 ++ src/multimedia/base/qmediacontrol.h | 82 + src/multimedia/base/qmediacontrol_p.h | 74 + src/multimedia/base/qmediaobject.cpp | 418 +++++ src/multimedia/base/qmediaobject.h | 121 ++ src/multimedia/base/qmediaobject_p.h | 94 ++ src/multimedia/base/qmediaplaylist.cpp | 719 +++++++++ src/multimedia/base/qmediaplaylist.h | 147 ++ src/multimedia/base/qmediaplaylist_p.h | 172 +++ src/multimedia/base/qmediaplaylistcontrol.cpp | 203 +++ src/multimedia/base/qmediaplaylistcontrol.h | 97 ++ src/multimedia/base/qmediaplaylistioplugin.cpp | 189 +++ src/multimedia/base/qmediaplaylistioplugin.h | 126 ++ src/multimedia/base/qmediaplaylistnavigator.cpp | 544 +++++++ src/multimedia/base/qmediaplaylistnavigator.h | 116 ++ src/multimedia/base/qmediaplaylistprovider.cpp | 307 ++++ src/multimedia/base/qmediaplaylistprovider.h | 114 ++ src/multimedia/base/qmediaplaylistprovider_p.h | 75 + src/multimedia/base/qmediapluginloader.cpp | 134 ++ src/multimedia/base/qmediapluginloader_p.h | 92 ++ src/multimedia/base/qmediaresource.cpp | 378 +++++ src/multimedia/base/qmediaresource.h | 130 ++ src/multimedia/base/qmediaservice.cpp | 139 ++ src/multimedia/base/qmediaservice.h | 90 ++ src/multimedia/base/qmediaservice_p.h | 74 + src/multimedia/base/qmediaserviceprovider.cpp | 678 +++++++++ src/multimedia/base/qmediaserviceprovider.h | 169 +++ src/multimedia/base/qmediaserviceproviderplugin.h | 125 ++ src/multimedia/base/qmediatimerange.cpp | 706 +++++++++ src/multimedia/base/qmediatimerange.h | 135 ++ src/multimedia/base/qmetadatacontrol.cpp | 185 +++ src/multimedia/base/qmetadatacontrol.h | 92 ++ src/multimedia/base/qpaintervideosurface.cpp | 1456 ++++++++++++++++++ src/multimedia/base/qpaintervideosurface_p.h | 155 ++ src/multimedia/base/qtmedianamespace.h | 189 +++ src/multimedia/base/qtmedianamespace.qdoc | 210 +++ src/multimedia/base/qvideodevicecontrol.cpp | 154 ++ src/multimedia/base/qvideodevicecontrol.h | 90 ++ src/multimedia/base/qvideooutputcontrol.cpp | 135 ++ src/multimedia/base/qvideooutputcontrol.h | 91 ++ src/multimedia/base/qvideorenderercontrol.cpp | 124 ++ src/multimedia/base/qvideorenderercontrol.h | 77 + src/multimedia/base/qvideowidget.cpp | 916 +++++++++++ src/multimedia/base/qvideowidget.h | 134 ++ src/multimedia/base/qvideowidget_p.h | 265 ++++ src/multimedia/base/qvideowidgetcontrol.cpp | 235 +++ src/multimedia/base/qvideowidgetcontrol.h | 105 ++ src/multimedia/base/qvideowindowcontrol.cpp | 274 ++++ src/multimedia/base/qvideowindowcontrol.h | 111 ++ src/multimedia/multimedia.pro | 5 +- src/multimedia/playback/playback.pri | 11 + src/multimedia/playback/qmediaplayer.cpp | 930 ++++++++++++ src/multimedia/playback/qmediaplayer.h | 199 +++ src/multimedia/playback/qmediaplayercontrol.cpp | 362 +++++ src/multimedia/playback/qmediaplayercontrol.h | 129 ++ src/multimedia/qml/qml.pri | 11 + src/multimedia/qml/qmlsound.cpp | 168 +++ src/multimedia/qml/qmlsound_p.h | 126 ++ src/plugins/mediaservices/mediaservices.pro | 5 + src/plugins/mediaservices/qt7/qcvdisplaylink.h | 90 ++ src/plugins/mediaservices/qt7/qcvdisplaylink.mm | 159 ++ src/plugins/mediaservices/qt7/qt7.pro | 52 + src/plugins/mediaservices/qt7/qt7backend.h | 68 + src/plugins/mediaservices/qt7/qt7backend.mm | 60 + src/plugins/mediaservices/qt7/qt7movierenderer.h | 112 ++ src/plugins/mediaservices/qt7/qt7movierenderer.mm | 441 ++++++ .../mediaservices/qt7/qt7movievideowidget.h | 131 ++ .../mediaservices/qt7/qt7movievideowidget.mm | 409 +++++ src/plugins/mediaservices/qt7/qt7movieviewoutput.h | 118 ++ .../mediaservices/qt7/qt7movieviewoutput.mm | 307 ++++ .../mediaservices/qt7/qt7movieviewrenderer.h | 96 ++ .../mediaservices/qt7/qt7movieviewrenderer.mm | 341 +++++ src/plugins/mediaservices/qt7/qt7playercontrol.h | 128 ++ src/plugins/mediaservices/qt7/qt7playercontrol.mm | 188 +++ src/plugins/mediaservices/qt7/qt7playermetadata.h | 84 ++ src/plugins/mediaservices/qt7/qt7playermetadata.mm | 261 ++++ src/plugins/mediaservices/qt7/qt7playerservice.h | 90 ++ src/plugins/mediaservices/qt7/qt7playerservice.mm | 151 ++ src/plugins/mediaservices/qt7/qt7playersession.h | 140 ++ src/plugins/mediaservices/qt7/qt7playersession.mm | 402 +++++ src/plugins/mediaservices/qt7/qt7serviceplugin.h | 64 + src/plugins/mediaservices/qt7/qt7serviceplugin.mm | 74 + .../mediaservices/qt7/qt7videooutputcontrol.h | 134 ++ .../mediaservices/qt7/qt7videooutputcontrol.mm | 93 ++ src/plugins/plugins.pro | 3 +- tests/auto/auto.pro | 11 + tests/auto/qmediacontent/qmediacontent.pro | 6 + tests/auto/qmediacontent/tst_qmediacontent.cpp | 160 ++ tests/auto/qmediaobject/qmediaobject.pro | 4 + tests/auto/qmediaobject/tst_qmediaobject.cpp | 549 +++++++ tests/auto/qmediaplayer/qmediaplayer.pro | 6 + tests/auto/qmediaplayer/tst_qmediaplayer.cpp | 1011 +++++++++++++ tests/auto/qmediaplaylist/qmediaplaylist.pro | 6 + tests/auto/qmediaplaylist/tmp.unsupported_format | 0 tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp | 622 ++++++++ .../qmediaplaylistnavigator.pro | 6 + .../tst_qmediaplaylistnavigator.cpp | 316 ++++ .../auto/qmediapluginloader/qmediapluginloader.pro | 6 + .../qmediapluginloader/tst_qmediapluginloader.cpp | 121 ++ tests/auto/qmediaresource/qmediaresource.pro | 6 + tests/auto/qmediaresource/tst_qmediaresource.cpp | 471 ++++++ tests/auto/qmediaservice/qmediaservice.pro | 6 + tests/auto/qmediaservice/tst_qmediaservice.cpp | 211 +++ .../qmediaserviceprovider.pro | 6 + .../tst_qmediaserviceprovider.cpp | 458 ++++++ tests/auto/qmediatimerange/qmediatimerange.pro | 6 + tests/auto/qmediatimerange/tst_qmediatimerange.cpp | 735 +++++++++ tests/auto/qvideowidget/qvideowidget.pro | 6 + tests/auto/qvideowidget/tst_qvideowidget.cpp | 1595 ++++++++++++++++++++ tests/auto/tests.xml | 11 + 119 files changed, 25111 insertions(+), 2 deletions(-) create mode 100644 demos/multimedia/multimedia.pro create mode 100644 src/multimedia/base/base.pri create mode 100644 src/multimedia/base/qgraphicsvideoitem.cpp create mode 100644 src/multimedia/base/qgraphicsvideoitem.h create mode 100644 src/multimedia/base/qlocalmediaplaylistprovider.cpp create mode 100644 src/multimedia/base/qlocalmediaplaylistprovider.h create mode 100644 src/multimedia/base/qmediacontent.cpp create mode 100644 src/multimedia/base/qmediacontent.h create mode 100644 src/multimedia/base/qmediacontrol.cpp create mode 100644 src/multimedia/base/qmediacontrol.h create mode 100644 src/multimedia/base/qmediacontrol_p.h create mode 100644 src/multimedia/base/qmediaobject.cpp create mode 100644 src/multimedia/base/qmediaobject.h create mode 100644 src/multimedia/base/qmediaobject_p.h create mode 100644 src/multimedia/base/qmediaplaylist.cpp create mode 100644 src/multimedia/base/qmediaplaylist.h create mode 100644 src/multimedia/base/qmediaplaylist_p.h create mode 100644 src/multimedia/base/qmediaplaylistcontrol.cpp create mode 100644 src/multimedia/base/qmediaplaylistcontrol.h create mode 100644 src/multimedia/base/qmediaplaylistioplugin.cpp create mode 100644 src/multimedia/base/qmediaplaylistioplugin.h create mode 100644 src/multimedia/base/qmediaplaylistnavigator.cpp create mode 100644 src/multimedia/base/qmediaplaylistnavigator.h create mode 100644 src/multimedia/base/qmediaplaylistprovider.cpp create mode 100644 src/multimedia/base/qmediaplaylistprovider.h create mode 100644 src/multimedia/base/qmediaplaylistprovider_p.h create mode 100644 src/multimedia/base/qmediapluginloader.cpp create mode 100644 src/multimedia/base/qmediapluginloader_p.h create mode 100644 src/multimedia/base/qmediaresource.cpp create mode 100644 src/multimedia/base/qmediaresource.h create mode 100644 src/multimedia/base/qmediaservice.cpp create mode 100644 src/multimedia/base/qmediaservice.h create mode 100644 src/multimedia/base/qmediaservice_p.h create mode 100644 src/multimedia/base/qmediaserviceprovider.cpp create mode 100644 src/multimedia/base/qmediaserviceprovider.h create mode 100644 src/multimedia/base/qmediaserviceproviderplugin.h create mode 100644 src/multimedia/base/qmediatimerange.cpp create mode 100644 src/multimedia/base/qmediatimerange.h create mode 100644 src/multimedia/base/qmetadatacontrol.cpp create mode 100644 src/multimedia/base/qmetadatacontrol.h create mode 100644 src/multimedia/base/qpaintervideosurface.cpp create mode 100644 src/multimedia/base/qpaintervideosurface_p.h create mode 100644 src/multimedia/base/qtmedianamespace.h create mode 100644 src/multimedia/base/qtmedianamespace.qdoc create mode 100644 src/multimedia/base/qvideodevicecontrol.cpp create mode 100644 src/multimedia/base/qvideodevicecontrol.h create mode 100644 src/multimedia/base/qvideooutputcontrol.cpp create mode 100644 src/multimedia/base/qvideooutputcontrol.h create mode 100644 src/multimedia/base/qvideorenderercontrol.cpp create mode 100644 src/multimedia/base/qvideorenderercontrol.h create mode 100644 src/multimedia/base/qvideowidget.cpp create mode 100644 src/multimedia/base/qvideowidget.h create mode 100644 src/multimedia/base/qvideowidget_p.h create mode 100644 src/multimedia/base/qvideowidgetcontrol.cpp create mode 100644 src/multimedia/base/qvideowidgetcontrol.h create mode 100644 src/multimedia/base/qvideowindowcontrol.cpp create mode 100644 src/multimedia/base/qvideowindowcontrol.h create mode 100644 src/multimedia/playback/playback.pri create mode 100644 src/multimedia/playback/qmediaplayer.cpp create mode 100644 src/multimedia/playback/qmediaplayer.h create mode 100644 src/multimedia/playback/qmediaplayercontrol.cpp create mode 100644 src/multimedia/playback/qmediaplayercontrol.h create mode 100644 src/multimedia/qml/qml.pri create mode 100644 src/multimedia/qml/qmlsound.cpp create mode 100644 src/multimedia/qml/qmlsound_p.h create mode 100644 src/plugins/mediaservices/mediaservices.pro create mode 100644 src/plugins/mediaservices/qt7/qcvdisplaylink.h create mode 100644 src/plugins/mediaservices/qt7/qcvdisplaylink.mm create mode 100644 src/plugins/mediaservices/qt7/qt7.pro create mode 100644 src/plugins/mediaservices/qt7/qt7backend.h create mode 100644 src/plugins/mediaservices/qt7/qt7backend.mm create mode 100644 src/plugins/mediaservices/qt7/qt7movierenderer.h create mode 100644 src/plugins/mediaservices/qt7/qt7movierenderer.mm create mode 100644 src/plugins/mediaservices/qt7/qt7movievideowidget.h create mode 100644 src/plugins/mediaservices/qt7/qt7movievideowidget.mm create mode 100644 src/plugins/mediaservices/qt7/qt7movieviewoutput.h create mode 100644 src/plugins/mediaservices/qt7/qt7movieviewoutput.mm create mode 100644 src/plugins/mediaservices/qt7/qt7movieviewrenderer.h create mode 100644 src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm create mode 100644 src/plugins/mediaservices/qt7/qt7playercontrol.h create mode 100644 src/plugins/mediaservices/qt7/qt7playercontrol.mm create mode 100644 src/plugins/mediaservices/qt7/qt7playermetadata.h create mode 100644 src/plugins/mediaservices/qt7/qt7playermetadata.mm create mode 100644 src/plugins/mediaservices/qt7/qt7playerservice.h create mode 100644 src/plugins/mediaservices/qt7/qt7playerservice.mm create mode 100644 src/plugins/mediaservices/qt7/qt7playersession.h create mode 100644 src/plugins/mediaservices/qt7/qt7playersession.mm create mode 100644 src/plugins/mediaservices/qt7/qt7serviceplugin.h create mode 100644 src/plugins/mediaservices/qt7/qt7serviceplugin.mm create mode 100644 src/plugins/mediaservices/qt7/qt7videooutputcontrol.h create mode 100644 src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm create mode 100644 tests/auto/qmediacontent/qmediacontent.pro create mode 100644 tests/auto/qmediacontent/tst_qmediacontent.cpp create mode 100644 tests/auto/qmediaobject/qmediaobject.pro create mode 100644 tests/auto/qmediaobject/tst_qmediaobject.cpp create mode 100644 tests/auto/qmediaplayer/qmediaplayer.pro create mode 100644 tests/auto/qmediaplayer/tst_qmediaplayer.cpp create mode 100644 tests/auto/qmediaplaylist/qmediaplaylist.pro create mode 100644 tests/auto/qmediaplaylist/tmp.unsupported_format create mode 100644 tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp create mode 100644 tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro create mode 100644 tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp create mode 100644 tests/auto/qmediapluginloader/qmediapluginloader.pro create mode 100644 tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp create mode 100644 tests/auto/qmediaresource/qmediaresource.pro create mode 100644 tests/auto/qmediaresource/tst_qmediaresource.cpp create mode 100644 tests/auto/qmediaservice/qmediaservice.pro create mode 100644 tests/auto/qmediaservice/tst_qmediaservice.cpp create mode 100644 tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro create mode 100644 tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp create mode 100644 tests/auto/qmediatimerange/qmediatimerange.pro create mode 100644 tests/auto/qmediatimerange/tst_qmediatimerange.cpp create mode 100644 tests/auto/qvideowidget/qvideowidget.pro create mode 100644 tests/auto/qvideowidget/tst_qvideowidget.cpp diff --git a/demos/demos.pro b/demos/demos.pro index 5a9b6db..86553dc 100644 --- a/demos/demos.pro +++ b/demos/demos.pro @@ -55,6 +55,7 @@ wince*:SUBDIRS += demos_sqlbrowser } contains(QT_CONFIG, phonon):!static:SUBDIRS += demos_mediaplayer contains(QT_CONFIG, webkit):contains(QT_CONFIG, svg):!symbian:SUBDIRS += demos_browser +contains(QT_CONFIG, multimedia):SUBDIRS += demos_multimedia # install sources.files = README *.pro @@ -82,6 +83,7 @@ demos_sqlbrowser.subdir = sqlbrowser demos_undo.subdir = undo demos_qtdemo.subdir = qtdemo demos_mediaplayer.subdir = qmediaplayer +demos_multimedia.subdir = multimedia demos_browser.subdir = browser diff --git a/demos/multimedia/multimedia.pro b/demos/multimedia/multimedia.pro new file mode 100644 index 0000000..042650f --- /dev/null +++ b/demos/multimedia/multimedia.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = player + + diff --git a/src/multimedia/base/base.pri b/src/multimedia/base/base.pri new file mode 100644 index 0000000..fb2784d --- /dev/null +++ b/src/multimedia/base/base.pri @@ -0,0 +1,62 @@ + +contains(QT_CONFIG, opengl):QT += opengl + +HEADERS += \ + $$PWD/qmediaresource.h \ + $$PWD/qmediacontent.h \ + $$PWD/qmediaobject.h \ + $$PWD/qmediaobject_p.h \ + $$PWD/qmediapluginloader_p.h \ + $$PWD/qmediaservice.h \ + $$PWD/qmediaservice_p.h \ + $$PWD/qmediaserviceprovider.h \ + $$PWD/qmediaserviceproviderplugin.h \ + $$PWD/qmediacontrol.h \ + $$PWD/qmediacontrol_p.h \ + $$PWD/qmetadatacontrol.h \ + $$PWD/qvideooutputcontrol.h \ + $$PWD/qvideowindowcontrol.h \ + $$PWD/qvideorenderercontrol.h \ + $$PWD/qvideodevicecontrol.h \ + $$PWD/qvideowidgetcontrol.h \ + $$PWD/qvideowidget.h \ + $$PWD/qvideowidget_p.h \ + $$PWD/qgraphicsvideoitem.h \ + $$PWD/qmediaplaylistcontrol.h \ + $$PWD/qmediaplaylist.h \ + $$PWD/qmediaplaylist_p.h \ + $$PWD/qmediaplaylistprovider.h \ + $$PWD/qmediaplaylistprovider_p.h \ + $$PWD/qmediaplaylistioplugin.h \ + $$PWD/qlocalmediaplaylistprovider.h \ + $$PWD/qmediaplaylistnavigator.h \ + $$PWD/qpaintervideosurface_p.h \ + $$PWD/qmediatimerange.h \ + $$PWD/qtmedianamespace.h + +SOURCES += \ + $$PWD/qmediaresource.cpp \ + $$PWD/qmediacontent.cpp \ + $$PWD/qmediaobject.cpp \ + $$PWD/qmediapluginloader.cpp \ + $$PWD/qmediaservice.cpp \ + $$PWD/qmediaserviceprovider.cpp \ + $$PWD/qmediacontrol.cpp \ + $$PWD/qmetadatacontrol.cpp \ + $$PWD/qvideooutputcontrol.cpp \ + $$PWD/qvideowindowcontrol.cpp \ + $$PWD/qvideorenderercontrol.cpp \ + $$PWD/qvideodevicecontrol.cpp \ + $$PWD/qvideowidgetcontrol.cpp \ + $$PWD/qvideowidget.cpp \ + $$PWD/qgraphicsvideoitem.cpp \ + $$PWD/qmediaplaylistcontrol.cpp \ + $$PWD/qmediaplaylist.cpp \ + $$PWD/qmediaplaylistprovider.cpp \ + $$PWD/qmediaplaylistioplugin.cpp \ + $$PWD/qlocalmediaplaylistprovider.cpp \ + $$PWD/qmediaplaylistnavigator.cpp \ + $$PWD/qpaintervideosurface.cpp \ + $$PWD/qmediatimerange.cpp + + diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp new file mode 100644 index 0000000..7fa2e7d --- /dev/null +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +#include +#include +#include "qpaintervideosurface_p.h" +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +class QGraphicsVideoItemPrivate +{ +public: + QGraphicsVideoItemPrivate() + : q_ptr(0) + , surface(0) + , mediaObject(0) + , service(0) + , outputControl(0) + , rendererControl(0) + { + } + + QGraphicsVideoItem *q_ptr; + + QPainterVideoSurface *surface; + QMediaObject *mediaObject; + QMediaService *service; + QVideoOutputControl *outputControl; + QVideoRendererControl *rendererControl; + QRect boundingRect; + + void clearService(); + + void _q_present(); + void _q_formatChanged(const QVideoSurfaceFormat &format); + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); +}; + +void QGraphicsVideoItemPrivate::clearService() +{ + if (outputControl) { + outputControl->setOutput(QVideoOutputControl::NoOutput); + outputControl = 0; + } + if (rendererControl) { + surface->stop(); + rendererControl->setSurface(0); + rendererControl = 0; + } + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_ptr, SLOT(_q_serviceDestroyed())); + service = 0; + } +} + +void QGraphicsVideoItemPrivate::_q_present() +{ + q_ptr->update(boundingRect); +} + +void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format) +{ + q_ptr->prepareGeometryChange(); + + boundingRect = QRect(QPoint(0, 0), format.sizeHint()); + boundingRect.moveCenter(QPoint(0, 0)); +} + +void QGraphicsVideoItemPrivate::_q_serviceDestroyed() +{ + rendererControl = 0; + outputControl = 0; + service = 0; + + surface->stop(); +} + +void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() +{ + mediaObject = 0; + + clearService(); +} + +/*! + \class QGraphicsVideoItem + + \brief The QGraphicsVideoItem class provides a graphics item which display video produced by a QMediaObject. + + \ingroup multimedia + + Attaching a QGraphicsVideoItem to a QMediaObject allows it to display + the video or image output of that media object. A QGraphicsVideoItem + is attached to a media object by passing a pointer to the QMediaObject + to the setMediaObject() function. + + \code + player = new QMediaPlayer(this); + + QGraphicsVideoItem *item = new QGraphicsVideoItem; + item->setMediaObject(player); + graphicsView->scence()->addItem(item); + graphicsView->show(); + + player->setMedia(video); + player->play(); + \endcode + + \bold {Note}: Only a single display output can be attached to a media object at one time. + + \sa QMediaObject, QMediaPlayer, QVideoWidget +*/ + +/*! + Constructs a graphics item that displays video. + + The \a parent is passed to QGraphicsItem. +*/ +QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) + : QGraphicsItem(parent) + , d_ptr(new QGraphicsVideoItemPrivate) +{ + d_ptr->q_ptr = this; + d_ptr->surface = new QPainterVideoSurface; +} + +/*! + Destroys a video graphics item. +*/ +QGraphicsVideoItem::~QGraphicsVideoItem() +{ + if (d_ptr->outputControl) + d_ptr->outputControl->setOutput(QVideoOutputControl::NoOutput); + + if (d_ptr->rendererControl) + d_ptr->rendererControl->setSurface(0); + + delete d_ptr->surface; + delete d_ptr; +} + +/*! + \property QGraphicsVideoItem::mediaObject + \brief the media object which provides the video displayed by a graphics item. +*/ + +QMediaObject *QGraphicsVideoItem::mediaObject() const +{ + return d_func()->mediaObject; +} + +void QGraphicsVideoItem::setMediaObject(QMediaObject *object) +{ + Q_D(QGraphicsVideoItem); + + if (object == d->mediaObject) + return; + + d->clearService(); + + if (d->mediaObject) { + disconnect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + d->mediaObject->unbind(this); + } + + d->mediaObject = object; + + if (d->mediaObject) { + d->mediaObject->bind(this); + + connect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + + d->service = d->mediaObject->service(); + + if (d->service) { + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + + d->outputControl = qobject_cast( + d->service->control(QVideoOutputControl_iid)); + d->rendererControl = qobject_cast( + d->service->control(QVideoRendererControl_iid)); + + if (d->outputControl != 0 && d->rendererControl != 0) { + if (!d->surface) { + d->surface = new QPainterVideoSurface; + + connect(d->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_formatChanged(QVideoSurfaceFormat))); + connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); + } + + d->rendererControl->setSurface(d->surface); + + if (isVisible()) + d->outputControl->setOutput(QVideoOutputControl::RendererOutput); + } + } + } +} + +/*! + \reimp +*/ +QRectF QGraphicsVideoItem::boundingRect() const +{ + return d_func()->boundingRect; +} + +/*! + \reimp +*/ +void QGraphicsVideoItem::paint( + QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_D(QGraphicsVideoItem); + + Q_UNUSED(option); + Q_UNUSED(widget); + + if (d->surface != 0) { + d->surface->paint(painter, d->boundingRect); + d->surface->setReady(true); + } +} + +/*! + \reimp + + \internal +*/ +QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + Q_D(QGraphicsVideoItem); + + if (change == ItemVisibleChange && d->outputControl != 0 && d->rendererControl != 0) { + if (value.toBool()) { + d->outputControl->setOutput(QVideoOutputControl::RendererOutput); + + return d->outputControl->output() == QVideoOutputControl::RendererOutput; + } else { + d->outputControl->setOutput(QVideoOutputControl::NoOutput); + + return value; + } + } else { + return QGraphicsItem::itemChange(change, value); + } +} + +QT_END_NAMESPACE + +#include "moc_qgraphicsvideoitem.cpp" diff --git a/src/multimedia/base/qgraphicsvideoitem.h b/src/multimedia/base/qgraphicsvideoitem.h new file mode 100644 index 0000000..0cd5d46 --- /dev/null +++ b/src/multimedia/base/qgraphicsvideoitem.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QGRAPHICSVIDEOITEM_H +#define QGRAPHICSVIDEOITEM_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QVideoSurfaceFormat; + +class QGraphicsVideoItemPrivate; +class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + +public: + QGraphicsVideoItem(QGraphicsItem *parent = 0); + ~QGraphicsVideoItem(); + + QMediaObject *mediaObject() const; + void setMediaObject(QMediaObject *object); + + QRectF boundingRect() const; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + + QGraphicsVideoItemPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QGraphicsVideoItem) + Q_PRIVATE_SLOT(d_func(), void _q_present()) + Q_PRIVATE_SLOT(d_func(), void _q_formatChanged(const QVideoSurfaceFormat &)) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_mediaObjectDestroyed()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qlocalmediaplaylistprovider.cpp b/src/multimedia/base/qlocalmediaplaylistprovider.cpp new file mode 100644 index 0000000..40ff1fc --- /dev/null +++ b/src/multimedia/base/qlocalmediaplaylistprovider.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include "qmediaplaylistprovider_p.h" +#include + + +QT_BEGIN_NAMESPACE + +class QLocalMediaPlaylistProviderPrivate: public QMediaPlaylistProviderPrivate +{ +public: + QList resources; +}; + +QLocalMediaPlaylistProvider::QLocalMediaPlaylistProvider(QObject *parent) + :QMediaPlaylistProvider(*new QLocalMediaPlaylistProviderPrivate, parent) +{ +} + +QLocalMediaPlaylistProvider::~QLocalMediaPlaylistProvider() +{ +} + +bool QLocalMediaPlaylistProvider::isReadOnly() const +{ + return false; +} + +int QLocalMediaPlaylistProvider::mediaCount() const +{ + return d_func()->resources.size(); +} + +QMediaContent QLocalMediaPlaylistProvider::media(int pos) const +{ + return d_func()->resources.value(pos); +} + +bool QLocalMediaPlaylistProvider::addMedia(const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + int pos = d->resources.count(); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.append(content); + emit mediaInserted(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::addMedia(const QList &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + int pos = d->resources.count(); + int end = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, end); + d->resources.append(items); + emit mediaInserted(pos, end); + + return true; +} + + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QMediaContent &content) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeInserted(pos, pos); + d->resources.insert(pos, content); + emit mediaInserted(pos,pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::insertMedia(int pos, const QList &items) +{ + Q_D(QLocalMediaPlaylistProvider); + + if (items.isEmpty()) + return true; + + const int last = pos+items.count()-1; + + emit mediaAboutToBeInserted(pos, last); + for (int i=0; iresources.insert(pos+i, items.at(i)); + emit mediaInserted(pos, last); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int fromPos, int toPos) +{ + Q_D(QLocalMediaPlaylistProvider); + + Q_ASSERT(fromPos >= 0); + Q_ASSERT(fromPos <= toPos); + Q_ASSERT(toPos < mediaCount()); + + emit mediaAboutToBeRemoved(fromPos, toPos); + d->resources.erase(d->resources.begin()+fromPos, d->resources.begin()+toPos+1); + emit mediaRemoved(fromPos, toPos); + + return true; +} + +bool QLocalMediaPlaylistProvider::removeMedia(int pos) +{ + Q_D(QLocalMediaPlaylistProvider); + + emit mediaAboutToBeRemoved(pos, pos); + d->resources.removeAt(pos); + emit mediaRemoved(pos, pos); + + return true; +} + +bool QLocalMediaPlaylistProvider::clear() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + int lastPos = mediaCount()-1; + emit mediaAboutToBeRemoved(0, lastPos); + d->resources.clear(); + emit mediaRemoved(0, lastPos); + } + + return true; +} + +void QLocalMediaPlaylistProvider::shuffle() +{ + Q_D(QLocalMediaPlaylistProvider); + if (!d->resources.isEmpty()) { + QList resources; + + while (!d->resources.isEmpty()) { + resources.append(d->resources.takeAt(qrand() % d->resources.size())); + } + + d->resources = resources; + emit mediaChanged(0, mediaCount()-1); + } + +} + +#include "moc_qlocalmediaplaylistprovider.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qlocalmediaplaylistprovider.h b/src/multimedia/base/qlocalmediaplaylistprovider.h new file mode 100644 index 0000000..db8deb1 --- /dev/null +++ b/src/multimedia/base/qlocalmediaplaylistprovider.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QLOCALMEDIAPAYLISTPROVIDER_H +#define QLOCALMEDIAPAYLISTPROVIDER_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QLocalMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QLocalMediaPlaylistProvider : public QMediaPlaylistProvider +{ + Q_OBJECT + +public: + QLocalMediaPlaylistProvider(QObject *parent=0); + virtual ~QLocalMediaPlaylistProvider(); + + virtual int mediaCount() const; + virtual QMediaContent media(int pos) const; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList &items); + virtual bool insertMedia(int pos, const QMediaContent &content); + virtual bool insertMedia(int pos, const QList &items); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +private: + Q_DECLARE_PRIVATE(QLocalMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QLOCALMEDIAPAYLISTSOURCE_H diff --git a/src/multimedia/base/qmediacontent.cpp b/src/multimedia/base/qmediacontent.cpp new file mode 100644 index 0000000..3e32af0 --- /dev/null +++ b/src/multimedia/base/qmediacontent.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include + +#include + + +QT_BEGIN_NAMESPACE + + +class QMediaContentPrivate : public QSharedData +{ +public: + QMediaContentPrivate() {} + QMediaContentPrivate(const QMediaResourceList &r): + resources(r) {} + + QMediaContentPrivate(const QMediaContentPrivate &other): + QSharedData(other), + resources(other.resources) + {} + + bool operator==(const QMediaContentPrivate &other) const + { + return resources == other.resources; + } + + QMediaResourceList resources; + +private: + QMediaContentPrivate& operator=(const QMediaContentPrivate &other); +}; + + +/*! + \class QMediaContent + \preliminary + \brief The QMediaContent class provides access to the resources relating to a media content. + + \ingroup multimedia + + QMediaContent is used within the multimedia framework as the logical handle + to media content. A QMediaContent object is composed of one or more + \l {QMediaResource}s where each resource provides the URL and format + information of a different encoding of the content. + + A non-null QMediaContent will always have a primary or canonical reference to + the content available through the canonicalUrl() or canonicalResource() + methods, any additional resources are optional. +*/ + + +/*! + Constructs a null QMediaContent. +*/ + +QMediaContent::QMediaContent() +{ +} + +/*! + Constructs a media content with \a url providing a reference to the content. +*/ + +QMediaContent::QMediaContent(const QUrl &url): + d(new QMediaContentPrivate) +{ + d->resources << QMediaResource(url); +} + +/*! + Constructs a media content with \a resource providing a reference to the content. +*/ + +QMediaContent::QMediaContent(const QMediaResource &resource): + d(new QMediaContentPrivate) +{ + d->resources << resource; +} + +/*! + Constructs a media content with \a resources providing a reference to the content. +*/ + +QMediaContent::QMediaContent(const QMediaResourceList &resources): + d(new QMediaContentPrivate(resources)) +{ +} + +/*! + Constructs a copy of the media content \a other. +*/ + +QMediaContent::QMediaContent(const QMediaContent &other): + d(other.d) +{ +} + +/*! + Destroys the media content object. +*/ + +QMediaContent::~QMediaContent() +{ +} + +/*! + Assigns the value of \a other to this media content. +*/ + +QMediaContent& QMediaContent::operator=(const QMediaContent &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if \a other is equivalent to this media content; false otherwise. +*/ + +bool QMediaContent::operator==(const QMediaContent &other) const +{ + return (d.constData() == 0 && other.d.constData() == 0) || + (d.constData() != 0 && other.d.constData() != 0 && + *d.constData() == *other.d.constData()); +} + +/*! + Returns true if \a other is not equivalent to this media content; false otherwise. +*/ + +bool QMediaContent::operator!=(const QMediaContent &other) const +{ + return !(*this == other); +} + +/*! + Returns true if this media content is null (uninitialized); false otherwise. +*/ + +bool QMediaContent::isNull() const +{ + return d.constData() == 0; +} + +/*! + Returns a QUrl that represents that canonical resource for this media content. +*/ + +QUrl QMediaContent::canonicalUrl() const +{ + return canonicalResource().url(); +} + +/*! + Returns a QMediaResource that represents that canonical resource for this media content. +*/ + +QMediaResource QMediaContent::canonicalResource() const +{ + return d.constData() != 0 + ? d->resources.value(0) + : QMediaResource(); +} + +/*! + Returns a list of alternative resources for this media content. The first item in this list + is always the canonical resource. +*/ + +QMediaResourceList QMediaContent::resources() const +{ + return d.constData() != 0 + ? d->resources + : QMediaResourceList(); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediacontent.h b/src/multimedia/base/qmediacontent.h new file mode 100644 index 0000000..49d1155 --- /dev/null +++ b/src/multimedia/base/qmediacontent.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIACONTENT_H +#define QMEDIACONTENT_H + +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaContentPrivate; +class Q_MULTIMEDIA_EXPORT QMediaContent +{ +public: + QMediaContent(); + QMediaContent(const QUrl &contentUrl); + QMediaContent(const QMediaResource &contentResource); + QMediaContent(const QMediaResourceList &resources); + QMediaContent(const QMediaContent &other); + ~QMediaContent(); + + QMediaContent& operator=(const QMediaContent &other); + + bool operator==(const QMediaContent &other) const; + bool operator!=(const QMediaContent &other) const; + + bool isNull() const; + + QUrl canonicalUrl() const; + QMediaResource canonicalResource() const; + + QMediaResourceList resources() const; + +private: + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaContent)) + +QT_END_HEADER + +#endif // QMEDIACONTENT_H diff --git a/src/multimedia/base/qmediacontrol.cpp b/src/multimedia/base/qmediacontrol.cpp new file mode 100644 index 0000000..c8bbfd4 --- /dev/null +++ b/src/multimedia/base/qmediacontrol.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include + +#include +#include "qmediacontrol_p.h" + + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaControl + \ingroup multimedia-serv + + \preliminary + \brief The QMediaControl class provides a base interface for media service controls. + + Media controls provide an interface to individual features provided by a media service. Most + services implement a principal control which exposes the core functionality of the service and + a number optional controls which expose any additional functionality. + + A pointer to a control implemented by a media service can be obtained using the + \l {QMediaService::control()}{control()} member of QMediaService. If the service doesn't + implement a control it will instead return a null pointer. + + \code + QMediaPlayerControl *control = qobject_cast( + service->control("com.nokia.Qt.QMediaPlayerControl/1.0")); + \endcode + + Alternatively if the IId of the control has been declared using Q_MEDIA_DECLARE_CONTROL + the template version of QMediaService::control() can be used to request the service without + explicitly passing the IId. + + \code + QMediaPlayerControl *control = service->control(); + \endcode + + Most application code will not interface directly with a media service's controls, instead the + QMediaObject which owns the service acts as an intermeditary between one or more controls and + the application. + + \sa QMediaService, QMediaObject +*/ + +/*! + \macro Q_MEDIA_DECLARE_CONTROL(Class, IId) + \relates QMediaControl + + The Q_MEDIA_DECLARE_CONTROL macro declares an \a IId for a \a Class that inherits from + QMediaControl. + + Declaring an IId for a QMediaControl allows an instance of that control to be requested from + QMediaService::control() without explicitly passing the IId. + + \code + QMediaPlayerControl *control = service->control(); + \endcode + + \sa QMediaService::control() +*/ + +/*! + Destroys a media control. +*/ + +QMediaControl::~QMediaControl() +{ + delete d_ptr; +} + +/*! + Constructs a media control with the given \a parent. +*/ + +QMediaControl::QMediaControl(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaControlPrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ + +QMediaControl::QMediaControl(QMediaControlPrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) + +{ + d_ptr->q_ptr = this; +} + +#include "moc_qmediacontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediacontrol.h b/src/multimedia/base/qmediacontrol.h new file mode 100644 index 0000000..8ed9fe8 --- /dev/null +++ b/src/multimedia/base/qmediacontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QABSTRACTMEDIACONTROL_H +#define QABSTRACTMEDIACONTROL_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaControlPrivate; +class Q_MULTIMEDIA_EXPORT QMediaControl : public QObject +{ + Q_OBJECT + +public: + ~QMediaControl(); + +protected: + QMediaControl(QObject *parent = 0); + QMediaControl(QMediaControlPrivate &dd, QObject *parent = 0); + + QMediaControlPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaControl) +}; + +template const char *qmediacontrol_iid() { return 0; } + +#define Q_MEDIA_DECLARE_CONTROL(Class, IId) \ + template <> inline const char *qmediacontrol_iid() { return IId; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTMEDIACONTROL_H diff --git a/src/multimedia/base/qmediacontrol_p.h b/src/multimedia/base/qmediacontrol_p.h new file mode 100644 index 0000000..4d00f11 --- /dev/null +++ b/src/multimedia/base/qmediacontrol_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QABSTRACTMEDIACONTROL_P_H +#define QABSTRACTMEDIACONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaControl; + +class QMediaControlPrivate +{ +public: + virtual ~QMediaControlPrivate() {} + + QMediaControl *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qmediaobject.cpp b/src/multimedia/base/qmediaobject.cpp new file mode 100644 index 0000000..34b57c9 --- /dev/null +++ b/src/multimedia/base/qmediaobject.cpp @@ -0,0 +1,418 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +#include "qmediaobject_p.h" + +#include +#include + + +QT_BEGIN_NAMESPACE + +void QMediaObjectPrivate::_q_notify() +{ + Q_Q(QMediaObject); + + const QMetaObject* m = q->metaObject(); + + foreach (int pi, notifyProperties) { + QMetaProperty p = m->property(pi); + p.notifySignal().invoke( + q, QGenericArgument(QMetaType::typeName(p.userType()), p.read(q).data())); + } +} + + +/*! + \class QMediaObject + \preliminary + \brief The QMediaObject class provides a common base for multimedia objects. + + \ingroup multimedia + + QMediaObject derived classes provide access to the functionality of a + QMediaService. Each media object hosts a QMediaService and uses the + QMediaControl interfaces implemented by the service to implement its + API. Most media objects when constructed will request a new + QMediaService instance from a QMediaServiceProvider, but some like + QMediaRecorder will share a service with another object. + + QMediaObject itself provides an API for accessing a media service's \l {metaData()}{meta-data} and a means of connecting other media objects, + and peripheral classes like QVideoWidget and QMediaPlaylist. + + \sa QMediaService, QMediaControl +*/ + +/*! + Destroys a media object. +*/ + +QMediaObject::~QMediaObject() +{ + delete d_ptr; +} + +/*! + Returns the service availability error state. +*/ + +QtMedia::AvailabilityError QMediaObject::availabilityError() const +{ + return QtMedia::ServiceMissingError; +} + +/*! + Returns true if the service is available for use. +*/ + +bool QMediaObject::isAvailable() const +{ + return false; +} + +/*! + Returns the media service that provides the functionality of a multimedia object. +*/ + +QMediaService* QMediaObject::service() const +{ + return d_func()->service; +} + +int QMediaObject::notifyInterval() const +{ + return d_func()->notifyTimer->interval(); +} + +void QMediaObject::setNotifyInterval(int milliSeconds) +{ + Q_D(QMediaObject); + + if (d->notifyTimer->interval() != milliSeconds) { + d->notifyTimer->setInterval(milliSeconds); + + emit notifyIntervalChanged(milliSeconds); + } +} + +/*! + \internal +*/ +void QMediaObject::bind(QObject*) +{ +} + +/*! + \internal +*/ +void QMediaObject::unbind(QObject*) +{ +} + + +/*! + Constructs a media object which uses the functionality provided by a media \a service. + + The \a parent is passed to QObject. + + This class is meant as a base class for Multimedia objects so this + constructor is protected. +*/ + +QMediaObject::QMediaObject(QObject *parent, QMediaService *service): + QObject(parent), + d_ptr(new QMediaObjectPrivate) + +{ + Q_D(QMediaObject); + + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + \internal +*/ + +QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, + QMediaService *service): + QObject(parent), + d_ptr(&dd) +{ + Q_D(QMediaObject); + d->q_ptr = this; + + d->notifyTimer = new QTimer(this); + d->notifyTimer->setInterval(1000); + connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); + + d->service = service; + + setupMetaData(); +} + +/*! + Watch the property \a name. The property's notify signal will be emitted + once every notifyInterval milliseconds. + + \sa notifyInterval +*/ + +void QMediaObject::addPropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + const QMetaObject* m = metaObject(); + + int index = m->indexOfProperty(name.constData()); + + if (index != -1 && m->property(index).hasNotifySignal()) { + d->notifyProperties.insert(index); + + if (!d->notifyTimer->isActive()) + d->notifyTimer->start(); + } +} + +/*! + Remove property \a name from the list of properties whose changes are + regularly signaled. + + \sa notifyInterval +*/ + +void QMediaObject::removePropertyWatch(QByteArray const &name) +{ + Q_D(QMediaObject); + + int index = metaObject()->indexOfProperty(name.constData()); + + if (index != -1) { + d->notifyProperties.remove(index); + + if (d->notifyProperties.isEmpty()) + d->notifyTimer->stop(); + } +} + +/*! + \property QMediaObject::notifyInterval + + The interval at which notifiable properties will update. + + The interval is expressed in milliseconds, the default value is 1000. + + \sa addPropertyWatch(), removePropertyWatch() +*/ + +/*! + \fn void QMediaObject::notifyIntervalChanged(int milliseconds) + + Signal a change in the notify interval period to \a milliseconds. +*/ + +/*! + \property QMediaObject::metaDataAvailable + \brief whether access to a media object's meta-data is available. + + If this is true there is meta-data available, otherwise there is no meta-data available. +*/ + +bool QMediaObject::isMetaDataAvailable() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->isMetaDataAvailable() + : false; +} + +/*! + \fn QMediaObject::metaDataAvailableChanged(bool available) + + Signals that the \a available state of a media object's meta-data has changed. +*/ + +/*! + \property QMediaObject::metaDataWritable + \brief whether a media object's meta-data is writable. + + If this is true the meta-data is writable, otherwise the meta-data is read-only. +*/ + +bool QMediaObject::isMetaDataWritable() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->isWritable() + : false; +} + +/*! + \fn QMediaObject::metaDataWritableChanged(bool writable) + + Signals that the \a writable state of a media object's meta-data has changed. +*/ + +/*! + Returns the value associated with a meta-data \a key. +*/ +QVariant QMediaObject::metaData(QtMedia::MetaData key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->metaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. +*/ +void QMediaObject::setMetaData(QtMedia::MetaData key, const QVariant &value) +{ + Q_D(QMediaObject); + + if (d->metaDataControl) + d->metaDataControl->setMetaData(key, value); +} + +/*! + Returns a list of keys there is meta-data available for. +*/ +QList QMediaObject::availableMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableMetaData() + : QList(); +} + +/*! + \fn QMediaObject::metaDataChanged() + + Signals that a media object's meta-data has changed. +*/ + +/*! + Returns the value associated with a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. +*/ +QVariant QMediaObject::extendedMetaData(const QString &key) const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->extendedMetaData(key) + : QVariant(); +} + +/*! + Sets a \a value for a meta-data \a key. + + The naming and type of extended meta-data is not standardized, so the values and meaning + of keys may vary between backends. +*/ +void QMediaObject::setExtendedMetaData(const QString &key, const QVariant &value) +{ + Q_D(QMediaObject); + + if (d->metaDataControl) + d->metaDataControl->setExtendedMetaData(key, value); +} + +/*! + Returns a list of keys there is extended meta-data available for. +*/ +QStringList QMediaObject::availableExtendedMetaData() const +{ + Q_D(const QMediaObject); + + return d->metaDataControl + ? d->metaDataControl->availableExtendedMetaData() + : QStringList(); +} + + +void QMediaObject::setupMetaData() +{ + Q_D(QMediaObject); + + if (d->service != 0) { + d->metaDataControl = + qobject_cast(d->service->control(QMetaDataControl_iid)); + + if (d->metaDataControl) { + connect(d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged())); + connect(d->metaDataControl, + SIGNAL(metaDataAvailableChanged(bool)), + SIGNAL(metaDataAvailableChanged(bool))); + connect(d->metaDataControl, + SIGNAL(writableChanged(bool)), + SIGNAL(metaDataWritableChanged(bool))); + } + } +} + +/*! + \fn QMediaObject::availabilityChanged(bool available) + + Signal emitted when the availability state has changed to \a available +*/ + + +#include "moc_qmediaobject.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaobject.h b/src/multimedia/base/qmediaobject.h new file mode 100644 index 0000000..a6eff1e --- /dev/null +++ b/src/multimedia/base/qmediaobject.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QABSTRACTMEDIAOBJECT_H +#define QABSTRACTMEDIAOBJECT_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaService; + +class QMediaObjectPrivate; +class Q_MULTIMEDIA_EXPORT QMediaObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(int notifyInterval READ notifyInterval WRITE setNotifyInterval NOTIFY notifyIntervalChanged) + Q_PROPERTY(bool metaDataAvailable READ isMetaDataAvailable NOTIFY metaDataAvailableChanged) + Q_PROPERTY(bool metaDataWritable READ isMetaDataWritable NOTIFY metaDataWritableChanged) + +public: + ~QMediaObject(); + + virtual bool isAvailable() const; + virtual QtMedia::AvailabilityError availabilityError() const; + + virtual QMediaService* service() const; + + int notifyInterval() const; + void setNotifyInterval(int milliSeconds); + + virtual void bind(QObject*); + virtual void unbind(QObject*); + + bool isMetaDataAvailable() const; + bool isMetaDataWritable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +Q_SIGNALS: + void notifyIntervalChanged(int milliSeconds); + + void metaDataAvailableChanged(bool available); + void metaDataWritableChanged(bool writable); + void metaDataChanged(); + + void availabilityChanged(bool available); + +protected: + QMediaObject(QObject *parent, QMediaService *service); + QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service); + + void addPropertyWatch(QByteArray const &name); + void removePropertyWatch(QByteArray const &name); + + QMediaObjectPrivate *d_ptr; + +private: + void setupMetaData(); + + Q_DECLARE_PRIVATE(QMediaObject) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QABSTRACTMEDIAOBJECT_H diff --git a/src/multimedia/base/qmediaobject_p.h b/src/multimedia/base/qmediaobject_p.h new file mode 100644 index 0000000..4bbe06a --- /dev/null +++ b/src/multimedia/base/qmediaobject_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QABSTRACTMEDIAOBJECT_P_H +#define QABSTRACTMEDIAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMetaDataControl; + +#define Q_DECLARE_NON_CONST_PUBLIC(Class) \ + inline Class* q_func() { return static_cast(q_ptr); } \ + friend class Class; + + +class QMediaObjectPrivate +{ + Q_DECLARE_PUBLIC(QMediaObject) + +public: + QMediaObjectPrivate():metaDataControl(0), notifyTimer(0) {} + + void _q_notify(); + + QMediaService *service; + QMetaDataControl *metaDataControl; + QTimer* notifyTimer; + QSet notifyProperties; + + QMediaObject *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qmediaplaylist.cpp b/src/multimedia/base/qmediaplaylist.cpp new file mode 100644 index 0000000..8a0de80 --- /dev/null +++ b/src/multimedia/base/qmediaplaylist.cpp @@ -0,0 +1,719 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include +#include +#include +#include + +#include +#include "qmediaplaylist_p.h" +#include +#include +#include +#include +#include +#include + +#include "qmediapluginloader_p.h" + + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, playlistIOLoader, + (QMediaPlaylistIOInterface_iid, QLatin1String("/playlistformats"), Qt::CaseInsensitive)) + + +/*! + \class QMediaPlaylist + \ingroup multimedia + + \preliminary + \brief The QMediaPlaylist class provides a list of media content to play. + + QMediaPlaylist is intended to be used with other media objects, + like QMediaPlayer or QMediaImageViewer. + QMediaPlaylist allows to access the service intrinsic playlist functionality + if available, otherwise it provides the the local memory playlist implementation. + +\code + player = new QMediaPlayer; + + playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + playlist->append(QUrl("http://example.com/movie1.mp4")); + playlist->append(QUrl("http://example.com/movie2.mp4")); + playlist->append(QUrl("http://example.com/movie3.mp4")); + + playlist->setCurrentIndex(1); + + player->play(); +\endcode + + Depending on playlist source implementation, + most of playlist modifcation operations can be asynchronous. + + \sa QMediaContent +*/ + + +/*! + \enum QMediaPlaylist::PlaybackMode + + The QMediaPlaylist::PlaybackMode describes the order items in playlist are played. + + \value CurrentItemOnce The current item is played only once. + + \value CurrentItemInLoop The current item is played in the loop. + + \value Linear Playback starts from the first to the last items and stops. + next item is a null item when the last one is currently playing. + + \value Loop Playback continues from the first item after the last one finished playing. + + \value Random Play items in random order. +*/ + + + +/*! + Create a new playlist object for with the given \a parent. +*/ + +QMediaPlaylist::QMediaPlaylist(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistPrivate) +{ + Q_D(QMediaPlaylist); + + d->q_ptr = this; + d->localPlaylistControl = new QLocalMediaPlaylistControl(this); + + setMediaObject(0); +} + +/*! + Destroys the playlist. + */ + +QMediaPlaylist::~QMediaPlaylist() +{ + Q_D(QMediaPlaylist); + + if (d->mediaObject) + d->mediaObject->unbind(this); + + delete d_ptr; +} + +QMediaObject *QMediaPlaylist::mediaObject() const +{ + return d_func()->mediaObject; +} + +/*! + If \a mediaObject is null or doesn't have an intrinsic playlist, + internal local memory playlist source will be created. +*/ +void QMediaPlaylist::setMediaObject(QMediaObject *mediaObject) +{ + Q_D(QMediaPlaylist); + + if (mediaObject && mediaObject == d->mediaObject) + return; + + QMediaService *service = mediaObject + ? mediaObject->service() : 0; + + QMediaPlaylistControl *newControl = 0; + + if (service) + newControl = qobject_cast(service->control(QMediaPlaylistControl_iid)); + + if (!newControl) + newControl = d->localPlaylistControl; + + if (d->control != newControl) { + int oldSize = 0; + if (d->control) { + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + oldSize = playlist->mediaCount(); + disconnect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + disconnect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + disconnect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + disconnect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + disconnect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + disconnect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + disconnect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + disconnect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + disconnect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + } + + d->control = newControl; + QMediaPlaylistProvider *playlist = d->control->playlistProvider(); + connect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), + this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); + + connect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); + connect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); + connect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); + connect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + + connect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + + connect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), + this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); + connect(d->control, SIGNAL(currentIndexChanged(int)), + this, SIGNAL(currentIndexChanged(int))); + connect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), + this, SIGNAL(currentMediaChanged(QMediaContent))); + + if (oldSize) + emit mediaRemoved(0, oldSize-1); + + if (playlist->mediaCount()) { + emit mediaAboutToBeInserted(0,playlist->mediaCount()-1); + emit mediaInserted(0,playlist->mediaCount()-1); + } + } + + if (d->mediaObject) + d->mediaObject->unbind(this); + + d->mediaObject = mediaObject; + if (d->mediaObject) + d->mediaObject->bind(this); +} + +/*! + \property QMediaPlaylist::playbackMode + + This property defines the order, items in playlist are played. + + \sa QMediaPlaylist::PlaybackMode +*/ + +QMediaPlaylist::PlaybackMode QMediaPlaylist::playbackMode() const +{ + return d_func()->control->playbackMode(); +} + +void QMediaPlaylist::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylist); + d->control->setPlaybackMode(mode); +} + +/*! + Returns position of the current media source in the playlist. +*/ +int QMediaPlaylist::currentIndex() const +{ + return d_func()->control->currentIndex(); +} + +/*! + Returns the current media content. +*/ + +QMediaContent QMediaPlaylist::currentMedia() const +{ + return d_func()->playlist()->media(currentIndex()); +} + +/*! + Returns the index of item, which were current after calling next() + \a steps times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \sa QMediaPlaylist::playbackMode +*/ +int QMediaPlaylist::nextIndex(int steps) const +{ + return d_func()->control->nextIndex(steps); +} + +/*! + Returns the index of item, which were current after calling previous() + \a steps times. + + \sa QMediaPlaylist::playbackMode +*/ + +int QMediaPlaylist::previousIndex(int steps) const +{ + return d_func()->control->previousIndex(steps); +} + + +/*! + Returns the number of items in the playlist. + + \sa isEmpty() + */ +int QMediaPlaylist::mediaCount() const +{ + return d_func()->playlist()->mediaCount(); +} + +/*! + Returns true if the playlist contains no items; otherwise returns false. + \sa size() + */ +bool QMediaPlaylist::isEmpty() const +{ + return mediaCount() == 0; +} + +/*! + Returns true if the playlist can be modified; otherwise returns false. + \sa size() + */ +bool QMediaPlaylist::isReadOnly() const +{ + return d_func()->playlist()->isReadOnly(); +} + +/*! + Returns the media content at \a index in the playlist. +*/ + +QMediaContent QMediaPlaylist::media(int index) const +{ + return d_func()->playlist()->media(index); +} + +/*! + Append the media \a content to the playlist. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::addMedia(const QMediaContent &content) +{ + return d_func()->control->playlistProvider()->addMedia(content); +} + +/*! + Append multiple media content \a items to the playlist. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::addMedia(const QList &items) +{ + return d_func()->control->playlistProvider()->addMedia(items); +} + +/*! + Insert the media \a content to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QMediaContent &content) +{ + return d_func()->playlist()->insertMedia(pos, content); +} + +/*! + Insert multiple media content \a items to the playlist at position \a pos. + + Returns true if the operation is successful, otherwise false. +*/ + +bool QMediaPlaylist::insertMedia(int pos, const QList &items) +{ + return d_func()->playlist()->insertMedia(pos, items); +} + +/*! + Remove the item from the playlist at position \a pos. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::removeMedia(int pos) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(pos); +} + +/*! + Remove the items from the playlist from position \a start to \a end inclusive. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::removeMedia(int start, int end) +{ + Q_D(QMediaPlaylist); + return d->playlist()->removeMedia(start, end); +} + +/*! + Remove all the items from the playlist. + + Returns true if the operation is successfull, other wise return false. + */ +bool QMediaPlaylist::clear() +{ + Q_D(QMediaPlaylist); + return d->playlist()->clear(); +} + +bool QMediaPlaylistPrivate::readItems(QMediaPlaylistReader *reader) +{ + while (!reader->atEnd()) + playlist()->addMedia(reader->readItem()); + + return true; +} + +bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer) +{ + for (int i=0; imediaCount(); i++) { + if (!writer->writeItem(playlist()->media(i))) + return false; + } + writer->close(); + return true; +} + +/*! + Load playlist from \a location. If \a format is specified, it is used, + otherwise format is guessed from location name and data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emited if playlist was loaded succesfully, + otherwise the playlist emits loadFailed(). +*/ +void QMediaPlaylist::load(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(location,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(location,format)) { + QMediaPlaylistReader *reader = plugin->createReader(location,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Load playlist from QIODevice \a device. If \a format is specified, it is used, + otherwise format is guessed from device data. + + New items are appended to playlist. + + QMediaPlaylist::loaded() signal is emited if playlist was loaded succesfully, + otherwise the playlist emits loadFailed(). +*/ +void QMediaPlaylist::load(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->load(device,format)) + return; + + if (isReadOnly()) { + d->error = AccessDeniedError; + d->errorString = tr("Could not add items to read only playlist."); + emit loadFailed(); + return; + } + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast(playlistIOLoader()->instance(key)); + if (plugin && plugin->canRead(device,format)) { + QMediaPlaylistReader *reader = plugin->createReader(device,QByteArray(format)); + if (reader && d->readItems(reader)) { + delete reader; + emit loaded(); + return; + } + delete reader; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported"); + emit loadFailed(); + + return; +} + +/*! + Save playlist to \a location. If \a format is specified, it is used, + otherwise format is guessed from location name. + + Returns true if playlist was saved succesfully, otherwise returns false. + */ +bool QMediaPlaylist::save(const QUrl &location, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(location,format)) + return true; + + QFile file(location.toLocalFile()); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + d->error = AccessDeniedError; + d->errorString = tr("The file could not be accessed."); + return false; + } + + return save(&file, format); +} + +/*! + Save playlist to QIODevice \a device using format \a format. + + Returns true if playlist was saved succesfully, otherwise returns false. +*/ +bool QMediaPlaylist::save(QIODevice * device, const char *format) +{ + Q_D(QMediaPlaylist); + + d->error = NoError; + d->errorString.clear(); + + if (d->playlist()->save(device,format)) + return true; + + foreach (QString const& key, playlistIOLoader()->keys()) { + QMediaPlaylistIOInterface* plugin = qobject_cast(playlistIOLoader()->instance(key)); + if (plugin && plugin->canWrite(device,format)) { + QMediaPlaylistWriter *writer = plugin->createWriter(device,QByteArray(format)); + if (writer && d->writeItems(writer)) { + delete writer; + return true; + } + delete writer; + } + } + + d->error = FormatNotSupportedError; + d->errorString = tr("Playlist format is not supported."); + + return false; +} + +/*! + Returns the last error condition. +*/ +QMediaPlaylist::Error QMediaPlaylist::error() const +{ + return d_func()->error; +} + +/*! + Returns the string describing the last error condition. +*/ +QString QMediaPlaylist::errorString() const +{ + return d_func()->errorString; +} + +/*! + Shuffle items in the playlist. +*/ +void QMediaPlaylist::shuffle() +{ + d_func()->playlist()->shuffle(); +} + + +/*! + Advance to the next media content in playlist. +*/ +void QMediaPlaylist::next() +{ + d_func()->control->next(); +} + +/*! + Return to the previous media content in playlist. +*/ +void QMediaPlaylist::previous() +{ + d_func()->control->previous(); +} + +/*! + Activate media content from playlist at position \a playlistPosition. +*/ + +void QMediaPlaylist::setCurrentIndex(int playlistPosition) +{ + d_func()->control->setCurrentIndex(playlistPosition); +} + +/*! + \fn void QMediaPlaylist::mediaInserted(int start, int end) + + This signal is emitted after media has been inserted into the playlist. + The new items are those between \a start and \a end inclusive. + */ + +/*! + \fn void QMediaPlaylist::mediaRemoved(int start, int end) + + This signal is emitted after media has been removed from the playlist. + The removed items are those between \a start and \a end inclusive. + */ + +/*! + \fn void QMediaPlaylist::mediaChanged(int start, int end) + + This signal is emitted after media has been changed in the playlist + between \a start and \a end positions inclusive. + */ + +/*! + \fn void QMediaPlaylist::currentIndexChanged(int position) + + Signal emitted when playlist position changed to \a position. +*/ + +/*! + \fn void QMediaPlaylist::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emitted when playback mode changed to \a mode. +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeInserted(int start, int end) + + Signal emitted when item to be inserted at \a start and ending at \a end. +*/ + +/*! + \fn void QMediaPlaylist::mediaAboutToBeRemoved(int start, int end) + + Signal emitted when item to de deleted ar \a start and ending at \a end. +*/ + +/*! + \fn void QMediaPlaylist::currentMediaChanged(const QMediaContent &content) + + Signal emitted when current media changes to \a content. +*/ + +/*! + \property QMediaPlaylist::currentIndex + \brief Current position. +*/ + +/*! + \property QMediaPlaylist::currentMedia + \brief Current media content. +*/ + +/*! + \fn QMediaPlaylist::loaded() + + Signal emitted when playlist finished loading. +*/ + +/*! + \fn QMediaPlaylist::loadFailed() + + Signal emitted if failed to load playlist. +*/ + +/*! + \enum QMediaPlaylist::Error + + This enum describes the QMediaPlaylist error codes. + + \value NoError No errors. + \value FormatError Format error. + \value FormatNotSupportedError Format not supported. + \value NetworkError Network error. + \value AccessDeniedError Access denied error. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaplaylist.cpp" +#include "moc_qmediaplaylist_p.cpp" diff --git a/src/multimedia/base/qmediaplaylist.h b/src/multimedia/base/qmediaplaylist.h new file mode 100644 index 0000000..c16541a --- /dev/null +++ b/src/multimedia/base/qmediaplaylist.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYLIST_H +#define QMEDIAPLAYLIST_H + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaPlaylistProvider; + +class QMediaPlaylistPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylist : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(QMediaContent currentMedia READ currentMedia NOTIFY currentMediaChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_ENUMS(PlaybackMode Error) + +public: + enum PlaybackMode { CurrentItemOnce, CurrentItemInLoop, Linear, Loop, Random }; + enum Error { NoError, FormatError, FormatNotSupportedError, NetworkError, AccessDeniedError }; + + QMediaPlaylist(QObject *parent = 0); + virtual ~QMediaPlaylist(); + + QMediaObject *mediaObject() const; + void setMediaObject(QMediaObject *object); + + PlaybackMode playbackMode() const; + void setPlaybackMode(PlaybackMode mode); + + int currentIndex() const; + QMediaContent currentMedia() const; + + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + + QMediaContent media(int index) const; + + int mediaCount() const; + bool isEmpty() const; + bool isReadOnly() const; + + bool addMedia(const QMediaContent &content); + bool addMedia(const QList &items); + bool insertMedia(int index, const QMediaContent &content); + bool insertMedia(int index, const QList &items); + bool removeMedia(int pos); + bool removeMedia(int start, int end); + bool clear(); + + void load(const QUrl &location, const char *format = 0); + void load(QIODevice * device, const char *format = 0); + + bool save(const QUrl &location, const char *format = 0); + bool save(QIODevice * device, const char *format); + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void shuffle(); + + void next(); + void previous(); + + void setCurrentIndex(int index); + +Q_SIGNALS: + void currentIndexChanged(int index); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + void currentMediaChanged(const QMediaContent&); + + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(); + +protected: + QMediaPlaylistPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaPlaylist) + Q_PRIVATE_SLOT(d_func(), void _q_loadFailed(QMediaPlaylist::Error, const QString &)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlaylist::PlaybackMode)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlaylist::Error)) + +QT_END_HEADER + +#endif // QMEDIAPLAYLIST_H diff --git a/src/multimedia/base/qmediaplaylist_p.h b/src/multimedia/base/qmediaplaylist_p.h new file mode 100644 index 0000000..da529b7 --- /dev/null +++ b/src/multimedia/base/qmediaplaylist_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYLIST_P_H +#define QMEDIAPLAYLIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include "qmediaobject_p.h" + +#include + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistControl; +class QMediaPlaylistProvider; +class QMediaPlaylistReader; +class QMediaPlaylistWriter; +class QMediaPlayerControl; + +class QMediaPlaylistPrivate +{ + Q_DECLARE_PUBLIC(QMediaPlaylist) +public: + QMediaPlaylistPrivate() + :mediaObject(0), + control(0), + localPlaylistControl(0), + error(QMediaPlaylist::NoError) + { + } + + virtual ~QMediaPlaylistPrivate() {} + + void _q_loadFailed(QMediaPlaylist::Error error, const QString &errorString) + { + this->error = error; + this->errorString = errorString; + + emit q_ptr->loadFailed(); + } + + void _q_mediaObjectDeleted() + { + Q_Q(QMediaPlaylist); + mediaObject = 0; + if (control != localPlaylistControl) + control = 0; + q->setMediaObject(0); + } + + QMediaObject *mediaObject; + + QMediaPlaylistControl *control; + QMediaPlaylistProvider *playlist() const { return control->playlistProvider(); } + + QMediaPlaylistControl *localPlaylistControl; + + bool readItems(QMediaPlaylistReader *reader); + bool writeItems(QMediaPlaylistWriter *writer); + + QMediaPlaylist::Error error; + QString errorString; + + QMediaPlaylist *q_ptr; +}; + + +class QLocalMediaPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + QLocalMediaPlaylistControl(QObject *parent) + :QMediaPlaylistControl(parent) + { + QMediaPlaylistProvider *playlist = new QLocalMediaPlaylistProvider(this); + m_navigator = new QMediaPlaylistNavigator(playlist,this); + m_navigator->setPlaybackMode(QMediaPlaylist::Linear); + + connect(m_navigator, SIGNAL(currentIndexChanged(int)), SIGNAL(currentIndexChanged(int))); + connect(m_navigator, SIGNAL(activated(QMediaContent)), SIGNAL(currentMediaChanged(QMediaContent))); + } + + virtual ~QLocalMediaPlaylistControl() {}; + + QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } + bool setPlaylistProvider(QMediaPlaylistProvider *mediaPlaylist) + { + m_navigator->setPlaylist(mediaPlaylist); + emit playlistProviderChanged(); + return true; + } + + int currentIndex() const { return m_navigator->currentIndex(); } + void setCurrentIndex(int position) { m_navigator->jump(position); } + int nextIndex(int steps) const { return m_navigator->nextIndex(steps); } + int previousIndex(int steps) const { return m_navigator->previousIndex(steps); } + + void next() { m_navigator->next(); } + void previous() { m_navigator->previous(); } + + QMediaPlaylist::PlaybackMode playbackMode() const { return m_navigator->playbackMode(); } + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) { m_navigator->setPlaybackMode(mode); } + +private: + QMediaPlaylistNavigator *m_navigator; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLIST_P_H diff --git a/src/multimedia/base/qmediaplaylistcontrol.cpp b/src/multimedia/base/qmediaplaylistcontrol.cpp new file mode 100644 index 0000000..2ae03ad --- /dev/null +++ b/src/multimedia/base/qmediaplaylistcontrol.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistControl + \ingroup multimedia-serv + + \preliminary + \brief The QMediaPlaylistControl class provides access to the playlist functionality of a + QMediaService. + + If a QMediaService contains an internal playlist it will implement QMediaPlaylistControl. This + control provides access to the contents of the \l {playlistProvider()}{playlist}, as well as the + \l {currentIndex()}{position} of the current media, and a means of navigating to the + \l {next()}{next} and \l {previous()}{previous} media. + + The functionality provided by the control is exposed to application code through the + QMediaPlaylist class. + + The interface name of QMediaPlaylistControl is \c com.nokia.Qt.QMediaPlaylistControl/1.0 as + defined in QMediaPlaylistControl_iid. + + \sa QMediaService::control(), QMediaPlayer +*/ + +/*! + \macro QMediaPlaylistControl_iid + + \c com.nokia.Qt.QMediaPlaylistControl/1.0 + + Defines the interface name of the QMediaPlaylistControl class. + + \relates QMediaPlaylistControl +*/ + +/*! + Create a new playlist control object with the given \a parent. +*/ +QMediaPlaylistControl::QMediaPlaylistControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroys the playlist control. +*/ +QMediaPlaylistControl::~QMediaPlaylistControl() +{ +} + + +/*! + \fn QMediaPlaylistControl::playlistProvider() const + + Returns the playlist used by this media player. +*/ + +/*! + \fn QMediaPlaylistControl::setPlaylistProvider(QMediaPlaylistProvider *playlist) + + Set the playlist of this media player to \a playlist. + + In many cases it is possible just to use the playlist + constructed by player, but sometimes replacing the whole + playlist allows to avoid copyting of all the items bettween playlists. + + Returns true if player can use this passed playlist; otherwise returns false. + +*/ + +/*! + \fn QMediaPlaylistControl::currentIndex() const + + Returns position of the current media source in the playlist. +*/ + +/*! + \fn QMediaPlaylistControl::setCurrentIndex(int position) + + Jump to the item at the given \a position. +*/ + +/*! + \fn QMediaPlaylistControl::nextIndex(int step) const + + Returns the index of item, which were current after calling next() + \a step times. + + Returned value depends on the size of playlist, current position + and playback mode. + + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::previousIndex(int step) const + + Returns the index of item, which were current after calling previous() + \a step times. + + \sa QMediaPlaylist::playbackMode +*/ + +/*! + \fn QMediaPlaylistControl::next() + + Moves to the next item in playlist. +*/ + +/*! + \fn QMediaPlaylistControl::previous() + + Returns to the previous item in playlist. +*/ + +/*! + \fn QMediaPlaylistControl::playbackMode() const + + Returns the playlist navigation mode. + + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) + + Sets the playback \a mode. + + \sa QMediaPlaylist::PlaybackMode +*/ + +/*! + \fn QMediaPlaylistControl::playlistProviderChanged() + + Signal emited when the playlist provider has changed. +*/ + +/*! + \fn QMediaPlaylistControl::currentIndexChanged(int position) + + Signal emited when the playlist \a position is changed. +*/ + +/*! + \fn QMediaPlaylistControl::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signal emited when the playback \a mode is changed. +*/ + +/*! + \fn QMediaPlaylistControl::currentMediaChanged(const QMediaContent& content) + + Signal emitted when current media changes to \a content. +*/ + +#include "moc_qmediaplaylistcontrol.cpp" +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaplaylistcontrol.h b/src/multimedia/base/qmediaplaylistcontrol.h new file mode 100644 index 0000000..228ee19 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistcontrol.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYLISTCONTROL_H +#define QMEDIAPLAYLISTCONTROL_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistProvider; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QMediaPlaylistControl(); + + virtual QMediaPlaylistProvider* playlistProvider() const = 0; + virtual bool setPlaylistProvider(QMediaPlaylistProvider *playlist) = 0; + + virtual int currentIndex() const = 0; + virtual void setCurrentIndex(int position) = 0; + virtual int nextIndex(int steps) const = 0; + virtual int previousIndex(int steps) const = 0; + + virtual void next() = 0; + virtual void previous() = 0; + + virtual QMediaPlaylist::PlaybackMode playbackMode() const = 0; + virtual void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) = 0; + +Q_SIGNALS: + void playlistProviderChanged(); + void currentIndexChanged(int position); + void currentMediaChanged(const QMediaContent&); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + +protected: + QMediaPlaylistControl(QObject* parent = 0); +}; + +#define QMediaPlaylistControl_iid "com.nokia.Qt.QMediaPlaylistControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlaylistControl, QMediaPlaylistControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTCONTROL_H diff --git a/src/multimedia/base/qmediaplaylistioplugin.cpp b/src/multimedia/base/qmediaplaylistioplugin.cpp new file mode 100644 index 0000000..5f11e38 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistioplugin.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistReader + \preliminary + \brief The QMediaPlaylistReader class provides an interface for reading a playlist file. + + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist reader. +*/ +QMediaPlaylistReader::~QMediaPlaylistReader() +{ +} + +/*! + \fn QMediaPlaylistReader::atEnd() const + + Identifies if a playlist reader has reached the end of its input. + + Returns true if the reader has reached the end; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistReader::readItem() + + Reads an item of media from a playlist file. + + Returns the read media, or a null QMediaContent if no more media is available. +*/ + +/*! + \fn QMediaPlaylistReader::close() + + Closes a playlist reader's input device. +*/ + +/*! + \class QMediaPlaylistWriter + \preliminary + \brief The QMediaPlaylistWriter class provides an interface for writing a playlist file. + + \sa QMediaPlaylistIOPlugin +*/ + +/*! + Destroys a media playlist writer. +*/ +QMediaPlaylistWriter::~QMediaPlaylistWriter() +{ +} + +/*! + \fn QMediaPlaylistWriter::writeItem(const QMediaContent &media) + + Writes an item of \a media to a playlist file. + + Returns true if the media was written succesfully; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistWriter::close() + + Finalizes the writing of a playlist and closes the output device. +*/ + +/*! + \class QMediaPlaylistIOPlugin + \brief The QMediaPlaylistIOPlugin class provides an interface for media playlist I/O plug-ins. +*/ + +/*! + Constructs a media playlist I/O plug-in with the given \a parent. +*/ +QMediaPlaylistIOPlugin::QMediaPlaylistIOPlugin(QObject *parent) + :QObject(parent) +{ +} + +/*! + Destroys a media playlist I/O plug-in. +*/ +QMediaPlaylistIOPlugin::~QMediaPlaylistIOPlugin() +{ +} + +/*! + \fn QMediaPlaylistIOPlugin::canRead(QIODevice *device, const QByteArray &format) const + + Identifies if plug-in can read \a format data from an I/O \a device. + + Returns true if the data can be read; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canRead(const QUrl& location, const QByteArray &format) const + + Identifies if a plug-in can read \a format data from a URL \a location. + + Returns true if the data can be read; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::canWrite(QIODevice *device, const QByteArray &format) const + + Identifies if a plug-in can write \a format data to an I/O \a device. + + Returns true if the data can be written; and false otherwise. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::keys() const + + Returns a list of format keys supported by a plug-in. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createReader(const QUrl& location, const QByteArray &format) + + Returns a new QMediaPlaylistReader which reads \a format data from a URL \a location. + + If the location or the format is unsupported this will return a null pointer. +*/ + +/*! + \fn QMediaPlaylistIOPlugin::createWriter(QIODevice *device, const QByteArray &format) + + Returns a new QMediaPlaylistWriter which writes \a format data to an I/O \a device. + + If the device is invalid or the format is unsupported this will return a null pointer. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaplaylistioplugin.cpp" + diff --git a/src/multimedia/base/qmediaplaylistioplugin.h b/src/multimedia/base/qmediaplaylistioplugin.h new file mode 100644 index 0000000..e55298d --- /dev/null +++ b/src/multimedia/base/qmediaplaylistioplugin.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYLISTIOPLUGIN_H +#define QMEDIAPLAYLISTIOPLUGIN_H + +#include +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QString; +class QUrl; +class QByteArray; +class QIODevice; +class QStringList; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistReader +{ +public: + virtual ~QMediaPlaylistReader(); + + virtual bool atEnd() const = 0; + virtual QMediaContent readItem() = 0; + virtual void close() = 0; +}; + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistWriter +{ +public: + virtual ~QMediaPlaylistWriter(); + + virtual bool writeItem(const QMediaContent &content) = 0; + virtual void close() = 0; +}; + +struct Q_MULTIMEDIA_EXPORT QMediaPlaylistIOInterface : public QFactoryInterface +{ + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +#define QMediaPlaylistIOInterface_iid "com.nokia.Qt.QMediaPlaylistIOInterface" +Q_DECLARE_INTERFACE(QMediaPlaylistIOInterface, QMediaPlaylistIOInterface_iid); + +class Q_MULTIMEDIA_EXPORT QMediaPlaylistIOPlugin : public QObject, public QMediaPlaylistIOInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaPlaylistIOInterface:QFactoryInterface) + +public: + explicit QMediaPlaylistIOPlugin(QObject *parent = 0); + virtual ~QMediaPlaylistIOPlugin(); + + virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const = 0; + virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const = 0; + + virtual bool canWrite(QIODevice *device, const QByteArray &format) const = 0; + + virtual QStringList keys() const = 0; + + virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) = 0; + virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) = 0; + + virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTIOPLUGIN_H diff --git a/src/multimedia/base/qmediaplaylistnavigator.cpp b/src/multimedia/base/qmediaplaylistnavigator.cpp new file mode 100644 index 0000000..3c22ea4 --- /dev/null +++ b/src/multimedia/base/qmediaplaylistnavigator.cpp @@ -0,0 +1,544 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include +#include +#include "qmediaobject_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistNullProvider : public QMediaPlaylistProvider +{ +public: + QMediaPlaylistNullProvider() :QMediaPlaylistProvider() {} + virtual ~QMediaPlaylistNullProvider() {} + virtual int mediaCount() const {return 0;} + virtual QMediaContent media(int) const { return QMediaContent(); } +}; + +Q_GLOBAL_STATIC(QMediaPlaylistNullProvider, _q_nullMediaPlaylist) + +class QMediaPlaylistNavigatorPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlaylistNavigator) +public: + QMediaPlaylistNavigatorPrivate() + :playlist(0), + currentPos(-1), + lastValidPos(-1), + playbackMode(QMediaPlaylist::Linear), + randomPositionsOffset(-1) + { + } + + QMediaPlaylistProvider *playlist; + int currentPos; + int lastValidPos; //to be used with CurrentItemOnce playback mode + QMediaPlaylist::PlaybackMode playbackMode; + QMediaContent currentItem; + + mutable QList randomModePositions; + mutable int randomPositionsOffset; + + int nextItemPos(int steps = 1) const; + int previousItemPos(int steps = 1) const; + + void _q_mediaInserted(int start, int end); + void _q_mediaRemoved(int start, int end); + void _q_mediaChanged(int start, int end); + + QMediaPlaylistNavigator *q_ptr; +}; + + +int QMediaPlaylistNavigatorPrivate::nextItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Linear: + { + int nextPos = currentPos+steps; + return nextPos < playlist->mediaCount() ? nextPos : -1; + } + case QMediaPlaylist::Loop: + return (currentPos+steps) % playlist->mediaCount(); + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomModePositions.size() < randomPositionsOffset+steps+1) + randomModePositions.append(-1); + int res = randomModePositions[randomPositionsOffset+steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset+steps] = res; + } + + return res; + } + } + + return -1; +} + +int QMediaPlaylistNavigatorPrivate::previousItemPos(int steps) const +{ + if (playlist->mediaCount() == 0) + return -1; + + if (steps == 0) + return currentPos; + + switch (playbackMode) { + case QMediaPlaylist::CurrentItemOnce: + return /*currentPos == -1 ? lastValidPos :*/ -1; + case QMediaPlaylist::CurrentItemInLoop: + return currentPos; + case QMediaPlaylist::Linear: + { + int prevPos = currentPos == -1 ? playlist->mediaCount() - steps : currentPos - steps; + return prevPos>=0 ? prevPos : -1; + } + case QMediaPlaylist::Loop: + { + int prevPos = currentPos - steps; + while (prevPos<0) + prevPos += playlist->mediaCount(); + return prevPos; + } + case QMediaPlaylist::Random: + { + //TODO: limit the history size + + if (randomPositionsOffset == -1) { + randomModePositions.clear(); + randomModePositions.append(currentPos); + randomPositionsOffset = 0; + } + + while (randomPositionsOffset-steps < 0) { + randomModePositions.prepend(-1); + randomPositionsOffset++; + } + + int res = randomModePositions[randomPositionsOffset-steps]; + if (res<0 || res >= playlist->mediaCount()) { + res = qrand() % playlist->mediaCount(); + randomModePositions[randomPositionsOffset-steps] = res; + } + + return res; + } + } + + return -1; +} + +/*! + \class QMediaPlaylistNavigator + \preliminary + \brief The QMediaPlaylistNavigator class provides navigation for a media playlist. + + \sa QMediaPlaylist, QMediaPlaylistProvider +*/ + + +/*! + Constructs a media playlist navigator for a \a playlist. + + The \a parent is passed to QObject. + */ +QMediaPlaylistNavigator::QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent) + : QObject(parent) + , d_ptr(new QMediaPlaylistNavigatorPrivate) +{ + d_ptr->q_ptr = this; + + setPlaylist(playlist ? playlist : _q_nullMediaPlaylist()); +} + +/*! + Destroys a media playlist navigator. + */ + +QMediaPlaylistNavigator::~QMediaPlaylistNavigator() +{ + delete d_ptr; +} + + +/*! \property QMediaPlaylistNavigator::playbackMode + Contains the playback mode. + */ +QMediaPlaylist::PlaybackMode QMediaPlaylistNavigator::playbackMode() const +{ + return d_func()->playbackMode; +} + +/*! + Sets the playback \a mode. + */ +void QMediaPlaylistNavigator::setPlaybackMode(QMediaPlaylist::PlaybackMode mode) +{ + Q_D(QMediaPlaylistNavigator); + if (d->playbackMode == mode) + return; + + if (mode == QMediaPlaylist::Random) { + d->randomPositionsOffset = 0; + d->randomModePositions.append(d->currentPos); + } else if (d->playbackMode == QMediaPlaylist::Random) { + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + } + + d->playbackMode = mode; + + emit playbackModeChanged(mode); + emit surroundingItemsChanged(); +} + +/*! + Returns the playlist being navigated. +*/ + +QMediaPlaylistProvider *QMediaPlaylistNavigator::playlist() const +{ + return d_func()->playlist; +} + +/*! + Sets the \a playlist to navigate. +*/ +void QMediaPlaylistNavigator::setPlaylist(QMediaPlaylistProvider *playlist) +{ + Q_D(QMediaPlaylistNavigator); + + if (d->playlist == playlist) + return; + + if (d->playlist) { + d->playlist->disconnect(this); + } + + if (playlist) { + d->playlist = playlist; + } else { + //assign to shared readonly null playlist + d->playlist = _q_nullMediaPlaylist(); + } + + connect(d->playlist, SIGNAL(mediaInserted(int,int)), SLOT(_q_mediaInserted(int,int))); + connect(d->playlist, SIGNAL(mediaRemoved(int,int)), SLOT(_q_mediaRemoved(int,int))); + connect(d->playlist, SIGNAL(mediaChanged(int,int)), SLOT(_q_mediaChanged(int,int))); + + d->randomPositionsOffset = -1; + d->randomModePositions.clear(); + + if (d->currentPos != -1) { + d->currentPos = -1; + emit currentIndexChanged(-1); + } + + if (!d->currentItem.isNull()) { + d->currentItem = QMediaContent(); + emit activated(d->currentItem); //stop playback + } +} + +/*! \property QMediaPlaylistNavigator::currentItem + + Contains the media at the current position in the playlist. + + \sa currentIndex() +*/ + +QMediaContent QMediaPlaylistNavigator::currentItem() const +{ + return itemAt(d_func()->currentPos); +} + +/*! \fn QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const + + Returns the media that is \a steps positions ahead of the current + position in the playlist. + + \sa nextIndex() +*/ +QMediaContent QMediaPlaylistNavigator::nextItem(int steps) const +{ + return itemAt(nextIndex(steps)); +} + +/*! + Returns the media that is \a steps positions behind the current + position in the playlist. + + \sa previousIndex() + */ +QMediaContent QMediaPlaylistNavigator::previousItem(int steps) const +{ + return itemAt(previousIndex(steps)); +} + +/*! + Returns the media at a \a position in the playlist. + */ +QMediaContent QMediaPlaylistNavigator::itemAt(int position) const +{ + return d_func()->playlist->media(position); +} + +/*! \property QMediaPlaylistNavigator::currentIndex + + Contains the position of the current media. + + If no media is current, the property contains -1. + + \sa nextIndex(), previousIndex() +*/ + +int QMediaPlaylistNavigator::currentIndex() const +{ + return d_func()->currentPos; +} + +/*! + Returns a position \a steps ahead of the current position + accounting for the playbackMode(). + + If the position is beyond the end of the playlist, this value + returned is -1. + + \sa currentIndex(), previousIndex(), playbackMode() +*/ + +int QMediaPlaylistNavigator::nextIndex(int steps) const +{ + return d_func()->nextItemPos(steps); +} + +/*! + + Returns a position \a steps behind the current position accounting + for the playbackMode(). + + If the position is prior to the beginning of the playlist this will + return -1. + + \sa currentIndex(), nextIndex(), playbackMode() +*/ +int QMediaPlaylistNavigator::previousIndex(int steps) const +{ + return d_func()->previousItemPos(steps); +} + +/*! + Advances to the next item in the playlist. + + \sa previous(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::next() +{ + Q_D(QMediaPlaylistNavigator); + + int nextPos = d->nextItemPos(); + + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset++; + + jump(nextPos); +} + +/*! + Returns to the previous item in the playlist, + + \sa next(), jump(), playbackMode() + */ +void QMediaPlaylistNavigator::previous() +{ + Q_D(QMediaPlaylistNavigator); + + int prevPos = d->previousItemPos(); + if ( playbackMode() == QMediaPlaylist::Random ) + d->randomPositionsOffset--; + + jump(prevPos); +} + +/*! + Jumps to a new \a position in the playlist. + */ +void QMediaPlaylistNavigator::jump(int position) +{ + Q_D(QMediaPlaylistNavigator); + + if (position<-1 || position>=d->playlist->mediaCount()) { + qWarning() << "QMediaPlaylistNavigator: Jump outside playlist range"; + position = -1; + } + + if (position != -1) + d->lastValidPos = position; + + if (playbackMode() == QMediaPlaylist::Random) { + if (d->randomModePositions[d->randomPositionsOffset] != position) { + d->randomModePositions.clear(); + d->randomModePositions.append(position); + d->randomPositionsOffset = 0; + } + } + + if (position != -1) + d->currentItem = d->playlist->media(position); + else + d->currentItem = QMediaContent(); + + if (position != d->currentPos) { + d->currentPos = position; + emit currentIndexChanged(d->currentPos); + emit surroundingItemsChanged(); + } + + emit activated(d->currentItem); +} + +/*! + \internal +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaInserted(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start) { + currentPos = end-start+1; + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaRemoved(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos > end) { + currentPos = currentPos - end-start+1; + q->jump(currentPos); + } else if (currentPos >= start) { + //current item was removed + currentPos = qMin(start, playlist->mediaCount()-1); + q->jump(currentPos); + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \internal +*/ +void QMediaPlaylistNavigatorPrivate::_q_mediaChanged(int start, int end) +{ + Q_Q(QMediaPlaylistNavigator); + + if (currentPos >= start && currentPos<=end) { + QMediaContent src = playlist->media(currentPos); + if (src != currentItem) { + currentItem = src; + emit q->activated(src); + } + } + + //TODO: check if they really changed + emit q->surroundingItemsChanged(); +} + +/*! + \fn QMediaPlaylistNavigator::activated(const QMediaContent &media) + + Signals that the current \a media has changed. +*/ + +/*! + \fn QMediaPlaylistNavigator::currentIndexChanged(int position) + + Signals the \a position of the current media has changed. +*/ + +/*! + \fn QMediaPlaylistNavigator::playbackModeChanged(QMediaPlaylist::PlaybackMode mode) + + Signals that the playback \a mode has changed. +*/ + +/*! + \fn QMediaPlaylistNavigator::surroundingItemsChanged() + + Signals that media immediately surrounding the current position has changed. +*/ + +#include "moc_qmediaplaylistnavigator.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaplaylistnavigator.h b/src/multimedia/base/qmediaplaylistnavigator.h new file mode 100644 index 0000000..73789af --- /dev/null +++ b/src/multimedia/base/qmediaplaylistnavigator.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYLISTNAVIGATOR_H +#define QMEDIAPLAYLISTNAVIGATOR_H + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylistNavigatorPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistNavigator : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMediaPlaylist::PlaybackMode playbackMode READ playbackMode WRITE setPlaybackMode NOTIFY playbackModeChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE jump NOTIFY currentIndexChanged) + Q_PROPERTY(QMediaContent currentItem READ currentItem NOTIFY currentItemChanged) + +public: + QMediaPlaylistNavigator(QMediaPlaylistProvider *playlist, QObject *parent = 0); + virtual ~QMediaPlaylistNavigator(); + + QMediaPlaylistProvider *playlist() const; + void setPlaylist(QMediaPlaylistProvider *playlist); + + QMediaPlaylist::PlaybackMode playbackMode() const; + + QMediaContent currentItem() const; + QMediaContent nextItem(int steps = 1) const; + QMediaContent previousItem(int steps = 1) const; + + QMediaContent itemAt(int position) const; + + int currentIndex() const; + int nextIndex(int steps = 1) const; + int previousIndex(int steps = 1) const; + +public Q_SLOTS: + void next(); + void previous(); + + void jump(int); + + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode); + +Q_SIGNALS: + void activated(const QMediaContent &content); + void currentIndexChanged(int); + void playbackModeChanged(QMediaPlaylist::PlaybackMode mode); + + void surroundingItemsChanged(); + +protected: + QMediaPlaylistNavigatorPrivate *d_ptr; + +private: + Q_DISABLE_COPY(QMediaPlaylistNavigator) + Q_DECLARE_PRIVATE(QMediaPlaylistNavigator) + + Q_PRIVATE_SLOT(d_func(), void _q_mediaInserted(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaRemoved(int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaChanged(int start, int end)) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTNAVIGATOR_H diff --git a/src/multimedia/base/qmediaplaylistprovider.cpp b/src/multimedia/base/qmediaplaylistprovider.cpp new file mode 100644 index 0000000..65105dc --- /dev/null +++ b/src/multimedia/base/qmediaplaylistprovider.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +#include +#include "qmediaplaylistprovider_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaPlaylistProvider + \preliminary + \brief The QMediaPlaylistProvider class provides an abstract list of media. + + \sa QMediaPlaylist +*/ + +/*! + Constructs a playlist provider with the given \a parent. +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QObject *parent) + :QObject(parent), d_ptr(new QMediaPlaylistProviderPrivate) +{ +} + +/*! + \internal +*/ +QMediaPlaylistProvider::QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent) + :QObject(parent), d_ptr(&dd) +{ +} + +/*! + Destroys a playlist provider. +*/ +QMediaPlaylistProvider::~QMediaPlaylistProvider() +{ + delete d_ptr; +} + +/*! + \fn QMediaPlaylistProvider::mediaCount() const; + + Returns the size of playlist. +*/ + +/*! + \fn QMediaPlaylistProvider::media(int index) const; + + Returns the media at \a index in the playlist. + + If the index is invalid this will return a null media content. +*/ + + +/*! + Loads a playlist from from a URL \a location. If no playlist \a format is specified the loader + will inspect the URL or probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from the locations URL protocol, + otherwise this will return false. +*/ +bool QMediaPlaylistProvider::load(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Loads a playlist from from an I/O \a device. If no playlist \a format is specified the loader + will probe the headers to guess the format. + + New items are appended to playlist. + + Returns true if the provider supports the format and loading from an I/O device, otherwise this + will return false. +*/ +bool QMediaPlaylistProvider::load(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to a URL \a location. If no playlist \a format is specified + the writer will inspect the URL to guess the format. + + Returns true if the playlist was saved succesfully; and false otherwise. + */ +bool QMediaPlaylistProvider::save(const QUrl &location, const char *format) +{ + Q_UNUSED(location); + Q_UNUSED(format); + return false; +} + +/*! + Saves the contents of a playlist to an I/O \a device in the specified \a format. + + Returns true if the playlist was saved succesfully; and false otherwise. +*/ +bool QMediaPlaylistProvider::save(QIODevice * device, const char *format) +{ + Q_UNUSED(device); + Q_UNUSED(format); + return false; +} + +/*! + Returns true if a playlist is read-only; otherwise returns false. +*/ +bool QMediaPlaylistProvider::isReadOnly() const +{ + return true; +} + +/*! + Append \a media to a playlist. + + Returns true if the media was appended; and false otherwise. +*/ +bool QMediaPlaylistProvider::addMedia(const QMediaContent &media) +{ + Q_UNUSED(media); + return false; +} + +/*! + Append multiple media \a items to a playlist. + + Returns true if the media items were appended; and false otherwise. +*/ +bool QMediaPlaylistProvider::addMedia(const QList &items) +{ + foreach(const QMediaContent &item, items) { + if (!addMedia(item)) + return false; + } + + return true; +} + +/*! + Inserts \a media into a playlist at \a position. + + Returns true if the media was inserted; and false otherwise. +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QMediaContent &media) +{ + Q_UNUSED(position); + Q_UNUSED(media); + return false; +} + +/*! + Inserts multiple media \a items into a playlist at \a position. + + Returns true if the media \a items were inserted; and false otherwise. +*/ +bool QMediaPlaylistProvider::insertMedia(int position, const QList &items) +{ + for (int i=0; i + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QString; + + +class QMediaPlaylistProviderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlaylistProvider : public QObject +{ + Q_OBJECT + +public: + QMediaPlaylistProvider(QObject *parent=0); + virtual ~QMediaPlaylistProvider(); + + virtual bool load(const QUrl &location, const char *format = 0); + virtual bool load(QIODevice * device, const char *format = 0); + virtual bool save(const QUrl &location, const char *format = 0); + virtual bool save(QIODevice * device, const char *format); + + virtual int mediaCount() const = 0; + virtual QMediaContent media(int index) const = 0; + + virtual bool isReadOnly() const; + + virtual bool addMedia(const QMediaContent &content); + virtual bool addMedia(const QList &contentList); + virtual bool insertMedia(int index, const QMediaContent &content); + virtual bool insertMedia(int index, const QList &content); + virtual bool removeMedia(int pos); + virtual bool removeMedia(int start, int end); + virtual bool clear(); + +public Q_SLOTS: + virtual void shuffle(); + +Q_SIGNALS: + void mediaAboutToBeInserted(int start, int end); + void mediaInserted(int start, int end); + + void mediaAboutToBeRemoved(int start, int end); + void mediaRemoved(int start, int end); + + void mediaChanged(int start, int end); + + void loaded(); + void loadFailed(QMediaPlaylist::Error, const QString& errorMessage); + +protected: + QMediaPlaylistProviderPrivate *d_ptr; + QMediaPlaylistProvider(QMediaPlaylistProviderPrivate &dd, QObject *parent); + +private: + Q_DECLARE_PRIVATE(QMediaPlaylistProvider) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTPROVIDER_H diff --git a/src/multimedia/base/qmediaplaylistprovider_p.h b/src/multimedia/base/qmediaplaylistprovider_p.h new file mode 100644 index 0000000..aaf6deb --- /dev/null +++ b/src/multimedia/base/qmediaplaylistprovider_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYLISTPROVIDER_P_H +#define QMEDIAPLAYLISTPROVIDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylistProviderPrivate +{ +public: + QMediaPlaylistProviderPrivate() + {} + virtual ~QMediaPlaylistProviderPrivate() + {} +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYLISTSOURCE_P_H diff --git a/src/multimedia/base/qmediapluginloader.cpp b/src/multimedia/base/qmediapluginloader.cpp new file mode 100644 index 0000000..8130413 --- /dev/null +++ b/src/multimedia/base/qmediapluginloader.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qmediapluginloader_p.h" +#include +#include +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + + +typedef QMap ObjectListMap; +Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins); + +QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity): + m_iid(iid) +{ + m_location = location + QLatin1String("/"); + load(); +} + +QStringList QMediaPluginLoader::keys() const +{ + return m_instances.keys(); +} + +QObject* QMediaPluginLoader::instance(QString const &key) +{ + return m_instances.value(key); +} + +QList QMediaPluginLoader::instances(QString const &key) +{ + return m_instances.values(key); +} + +//to be used for testing purposes only +void QMediaPluginLoader::setStaticPlugins(const QString &location, const QObjectList& objects) +{ + staticMediaPlugins()->insert(location + QLatin1String("/"), objects); +} + +void QMediaPluginLoader::load() +{ + if (!m_instances.isEmpty()) + return; + + if (staticMediaPlugins() && staticMediaPlugins()->contains(m_location)) { + qWarning() << "Load static plugins for" << m_location; + foreach(QObject *o, staticMediaPlugins()->value(m_location)) { + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast(o); + if (p != 0) { + foreach (QString const &key, p->keys()) + m_instances.insertMulti(key, o); + } + } + } + } else { + QStringList paths = QCoreApplication::libraryPaths(); + + foreach (QString const &path, paths) { + QString pluginPathName(path + m_location); + QDir pluginDir(pluginPathName); + + if (!pluginDir.exists()) + continue; + + foreach (QString pluginLib, pluginDir.entryList(QDir::Files)) { + QPluginLoader loader(pluginPathName + pluginLib); + + QObject *o = loader.instance(); + if (o != 0 && o->qt_metacast(m_iid) != 0) { + QFactoryInterface* p = qobject_cast(o); + if (p != 0) { + foreach (QString const &key, p->keys()) + m_instances.insertMulti(key, o); + } + + continue; + } else { + qWarning() << "QMediaPluginLoader: Failed to load plugin: " << pluginLib << loader.errorString(); + } + delete o; + loader.unload(); + } + } + } +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediapluginloader_p.h b/src/multimedia/base/qmediapluginloader_p.h new file mode 100644 index 0000000..351d2f1 --- /dev/null +++ b/src/multimedia/base/qmediapluginloader_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLUGINLOADER_H +#define QMEDIAPLUGINLOADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaServiceProviderPlugin; + +class Q_AUTOTEST_EXPORT QMediaPluginLoader +{ +public: + QMediaPluginLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + + QStringList keys() const; + QObject* instance(QString const &key); + QList instances(QString const &key); + + static void setStaticPlugins(const QString &location, const QObjectList& objects); + +private: + void load(); + + QByteArray m_iid; + QString m_location; + QMap m_instances; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLUGINLOADER_H diff --git a/src/multimedia/base/qmediaresource.cpp b/src/multimedia/base/qmediaresource.cpp new file mode 100644 index 0000000..ab18ce7 --- /dev/null +++ b/src/multimedia/base/qmediaresource.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaResource + \preliminary + \brief The QMediaResource class provides a description of a media resource. + \ingroup multimedia + + A media resource is composed of a \l {url()}{URL} containing the + location of the resource and a set of properties that describe the + format of the resource. The properties provide a means to assess a + resource without first attempting to load it, and in situations where + media be represented by multiple alternative representations provide a + means to select the appropriate resource. + + Media made available by a remote services can often be available in + multiple encodings or quality levels, this allows a client to select + an appropriate resource based on considerations such as codecs supported, + network bandwidth, and display constraints. QMediaResource includes + information such as the \l {mimeType()}{MIME type}, \l {audioCodec()}{audio} + and \l {videoCodec()}{video} codecs, \l {audioBitRate()}{audio} and + \l {videoBitRate()}{video} bit rates, and \l {resolution()}{resolution} + so these constraints and others can be evaluated. + + The only mandatory property of a QMediaResource is the url(). + + \sa QMediaContent +*/ + +/*! + \typedef QMediaResourceList + + Synonym for \c QList +*/ + +/*! + Constructs a null media resource. +*/ +QMediaResource::QMediaResource() +{ +} + +/*! + Constructs a media resource with the given \a mimeType from a \a url. +*/ +QMediaResource::QMediaResource(const QUrl &url, const QString &mimeType) +{ + values.insert(Url, qVariantFromValue(url)); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a copy of a media resource \a other. +*/ +QMediaResource::QMediaResource(const QMediaResource &other) + : values(other.values) +{ +} + +/*! + Assigns the value of \a other to a media resource. +*/ +QMediaResource &QMediaResource::operator =(const QMediaResource &other) +{ + values = other.values; + + return *this; +} + +/*! + Destroys a media resource. +*/ +QMediaResource::~QMediaResource() +{ +} + + +/*! + Compares a media resource to \a other. + + Returns true if the resources are identical, and false otherwise. +*/ +bool QMediaResource::operator ==(const QMediaResource &other) const +{ + return values == other.values; +} + +/*! + Compares a media resource to \a other. + + Returns true if they are different, and false otherwise. +*/ +bool QMediaResource::operator !=(const QMediaResource &other) const +{ + return values != other.values; +} + +/*! + Identifies if a media resource is null. + + Returns true if the resource is null, and false otherwise. +*/ +bool QMediaResource::isNull() const +{ + return values.isEmpty(); +} + +/*! + Returns the URL of a media resource. +*/ +QUrl QMediaResource::url() const +{ + return qvariant_cast(values.value(Url)); +} + +/*! + Returns the MIME type of a media resource. + + This may be null if the MIME type is unknown. +*/ +QString QMediaResource::mimeType() const +{ + return qvariant_cast(values.value(MimeType)); +} + +/*! + Returns the language of a media resource as an ISO 639-2 code. + + This may be null if the language is unknown. +*/ +QString QMediaResource::language() const +{ + return qvariant_cast(values.value(Language)); +} + +/*! + Sets the \a language of a media resource. +*/ +void QMediaResource::setLanguage(const QString &language) +{ + if (!language.isNull()) + values.insert(Language, language); + else + values.remove(Language); +} + +/*! + Returns the audio codec of a media resource. + + This may be null if the media resource does not contain an audio stream, or the codec is + unknown. +*/ +QString QMediaResource::audioCodec() const +{ + return qvariant_cast(values.value(AudioCodec)); +} + +/*! + Sets the audio \a codec of a media resource. +*/ +void QMediaResource::setAudioCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(AudioCodec, codec); + else + values.remove(AudioCodec); +} + +/*! + Returns the video codec of a media resource. + + This may be null if the media resource does not contain a video stream, or the codec is + unknonwn. +*/ +QString QMediaResource::videoCodec() const +{ + return qvariant_cast(values.value(VideoCodec)); +} + +/*! + Sets the video \a codec of media resource. +*/ +void QMediaResource::setVideoCodec(const QString &codec) +{ + if (!codec.isNull()) + values.insert(VideoCodec, codec); + else + values.remove(VideoCodec); +} + +/*! + Returns the size in bytes of a media resource. + + This may be zero if the size is unknown. +*/ +qint64 QMediaResource::dataSize() const +{ + return qvariant_cast(values.value(DataSize)); +} + +/*! + Sets the \a size in bytes of a media resource. +*/ +void QMediaResource::setDataSize(const qint64 size) +{ + if (size != 0) + values.insert(DataSize, size); + else + values.remove(DataSize); +} + +/*! + Returns the bit rate in bits per second of a media resource's audio stream. + + This may be zero if the bit rate is unknown, or the resource contains no audio stream. +*/ +int QMediaResource::audioBitRate() const +{ + return values.value(AudioBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. +*/ +void QMediaResource::setAudioBitRate(int rate) +{ + if (rate != 0) + values.insert(AudioBitRate, rate); + else + values.remove(AudioBitRate); +} + +/*! + Returns the audio sample rate of a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. +*/ +int QMediaResource::sampleRate() const +{ + return qvariant_cast(values.value(SampleRate)); +} + +/*! + Sets the audio \a sampleRate of a media resource. +*/ +void QMediaResource::setSampleRate(int sampleRate) +{ + if (sampleRate != 0) + values.insert(SampleRate, sampleRate); + else + values.remove(SampleRate); +} + +/*! + Returns the number of audio channels in a media resource. + + This may be zero if the sample size is unknown, or the resource contains no audio stream. +*/ +int QMediaResource::channelCount() const +{ + return qvariant_cast(values.value(ChannelCount)); +} + +/*! + Sets the number of audio \a channels in a media resource. +*/ +void QMediaResource::setChannelCount(int channels) +{ + if (channels != 0) + values.insert(ChannelCount, channels); + else + values.remove(ChannelCount); +} + +/*! + Returns the bit rate in bits per second of a media resource's video stream. + + This may be zero if the bit rate is unknown, or the resource contains no video stream. +*/ +int QMediaResource::videoBitRate() const +{ + return values.value(VideoBitRate).toInt(); +} + +/*! + Sets the bit \a rate in bits per second of a media resource's video stream. +*/ +void QMediaResource::setVideoBitRate(int rate) +{ + if (rate != 0) + values.insert(VideoBitRate, rate); + else + values.remove(VideoBitRate); +} + +/*! + Returns the resolution in pixels of a media resource. + + This may be null is the resolution is unknown, or the resource contains no pixel data (i.e. the + resource is an audio stream. +*/ +QSize QMediaResource::resolution() const +{ + return qvariant_cast(values.value(Resolution)); +} + +/*! + Sets the \a resolution in pixels of a media resource. +*/ +void QMediaResource::setResolution(const QSize &resolution) +{ + if (resolution.width() != -1 || resolution.height() != -1) + values.insert(Resolution, resolution); + else + values.remove(Resolution); +} + +/*! + Sets the \a width and \a height in pixels of a media resource. +*/ +void QMediaResource::setResolution(int width, int height) +{ + if (width != -1 || height != -1) + values.insert(Resolution, QSize(width, height)); + else + values.remove(Resolution); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediaresource.h b/src/multimedia/base/qmediaresource.h new file mode 100644 index 0000000..33b5a79 --- /dev/null +++ b/src/multimedia/base/qmediaresource.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIARESOURCE_H +#define QMEDIARESOURCE_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QMediaResource +{ +public: + QMediaResource(); + QMediaResource(const QUrl &url, const QString &mimeType = QString()); + QMediaResource(const QMediaResource &other); + QMediaResource &operator =(const QMediaResource &other); + ~QMediaResource(); + + bool isNull() const; + + bool operator ==(const QMediaResource &other) const; + bool operator !=(const QMediaResource &other) const; + + QUrl url() const; + QString mimeType() const; + + QString language() const; + void setLanguage(const QString &language); + + QString audioCodec() const; + void setAudioCodec(const QString &codec); + + QString videoCodec() const; + void setVideoCodec(const QString &codec); + + qint64 dataSize() const; + void setDataSize(const qint64 size); + + int audioBitRate() const; + void setAudioBitRate(int rate); + + int sampleRate() const; + void setSampleRate(int frequency); + + int channelCount() const; + void setChannelCount(int channels); + + int videoBitRate() const; + void setVideoBitRate(int rate); + + QSize resolution() const; + void setResolution(const QSize &resolution); + void setResolution(int width, int height); + + +private: + enum Property + { + Url, + MimeType, + Language, + AudioCodec, + VideoCodec, + DataSize, + AudioBitRate, + VideoBitRate, + SampleRate, + ChannelCount, + Resolution, + }; + QMap values; +}; + +typedef QList QMediaResourceList; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaResource)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaResourceList)) + +QT_END_HEADER + + +#endif diff --git a/src/multimedia/base/qmediaservice.cpp b/src/multimedia/base/qmediaservice.cpp new file mode 100644 index 0000000..e40688e --- /dev/null +++ b/src/multimedia/base/qmediaservice.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +#include +#include "qmediaservice_p.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +/*! + \class QMediaService + \brief The QMediaService class provides a common base class for media + service implementations. + \ingroup multimedia-serv + \preliminary + + Media services provide implementations of the functionality promised + by media objects, and allow multiple providers to implement a QMediaObject. + + To provide the functionality of a QMediaObject media services implement + QMediaControl interfaces. Services typically implement one core media + control which provides the core feature of a media object, and some + number of additional controls which provide either optional features of + the media object, or features of a secondary media object or peripheral + object. + + A pointer to media service's QMediaControl implementation can be + obtained by passing the control's interface name to the control() function. + + \code + QMediaPlayerControl *control = qobject_cast( + service->control("com.nokia.Qt.QMediaPlayerControl/1.0")); + \endcode + + Media objects can use services loaded dynamically from plug-ins or + implemented statically within an applications. Plug-in based services + should also implement the QMediaServiceProviderPlugin interface. Static + services should implement the QMediaServiceProvider interface. + + \sa QMediaObject, QMediaControl, QMediaServiceProvider, QMediaServiceProviderPlugin +*/ + +/*! + Construct a media service with the given \a parent. This class is meant as a + base class for Multimedia services so this constructor is protected. +*/ + +QMediaService::QMediaService(QObject *parent) + : QObject(parent) + , d_ptr(new QMediaServicePrivate) +{ + d_ptr->q_ptr = this; +} + +/*! + \internal +*/ +QMediaService::QMediaService(QMediaServicePrivate &dd, QObject *parent) + : QObject(parent) + , d_ptr(&dd) +{ + d_ptr->q_ptr = this; +} + +/*! + Destroys a media service. +*/ + +QMediaService::~QMediaService() +{ + delete d_ptr; +} + +/*! + \fn QMediaService::control(const char *interface) const + + Returns a pointer to the media control implementing \a interface. + + If the service does not implement the control a null pointer is returned instead. +*/ + +/*! + \fn QMediaService::control() const + + Returns a pointer to the media control of type T implemented by a media service. + + If the service does not implment the control a null pointer is returned instead. +*/ + +#include "moc_qmediaservice.cpp" + +QT_END_NAMESPACE + +QT_END_HEADER + diff --git a/src/multimedia/base/qmediaservice.h b/src/multimedia/base/qmediaservice.h new file mode 100644 index 0000000..c53a15f --- /dev/null +++ b/src/multimedia/base/qmediaservice.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QABSTRACTMEDIASERVICE_H +#define QABSTRACTMEDIASERVICE_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaServicePrivate; +class Q_MULTIMEDIA_EXPORT QMediaService : public QObject +{ + Q_OBJECT + +public: + ~QMediaService(); + + virtual QMediaControl* control(const char *name) const = 0; + +#ifndef QT_NO_MEMBER_TEMPLATES + template inline T control() const { + if (QObject *object = control(qmediacontrol_iid())) { + return qobject_cast(object); + } + return 0; + } +#endif + +protected: + QMediaService(QObject* parent); + QMediaService(QMediaServicePrivate &dd, QObject *parent); + + QMediaServicePrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QMediaService) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTMEDIASERVICE_H + diff --git a/src/multimedia/base/qmediaservice_p.h b/src/multimedia/base/qmediaservice_p.h new file mode 100644 index 0000000..5993a7e --- /dev/null +++ b/src/multimedia/base/qmediaservice_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QABSTRACTMEDIASERVICE_P_H +#define QABSTRACTMEDIASERVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAudioDeviceControl; + +class QMediaServicePrivate +{ +public: + QMediaServicePrivate(): q_ptr(0) {} + + QMediaService *q_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qmediaserviceprovider.cpp b/src/multimedia/base/qmediaserviceprovider.cpp new file mode 100644 index 0000000..37115e7 --- /dev/null +++ b/src/multimedia/base/qmediaserviceprovider.cpp @@ -0,0 +1,678 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include + +#include +#include +#include +#include "qmediapluginloader_p.h" +#include + + + +class QMediaServiceProviderHintPrivate : public QSharedData +{ +public: + QMediaServiceProviderHintPrivate(QMediaServiceProviderHint::Type type) + :type(type), features(0) + { + } + + QMediaServiceProviderHintPrivate(const QMediaServiceProviderHintPrivate &other) + :QSharedData(other), + type(other.type), + device(other.device), + mimeType(other.mimeType), + codecs(other.codecs), + features(other.features) + { + } + + ~QMediaServiceProviderHintPrivate() + { + } + + QMediaServiceProviderHint::Type type; + QByteArray device; + QString mimeType; + QStringList codecs; + QMediaServiceProviderHint::Features features; +}; + +/*! + \class QMediaServiceProviderHint + \preliminary + \brief The QMediaServiceProviderHint class describes what is required of a QMediaService. + + \ingroup multimedia-serv + + The QMediaServiceProvider class uses hints to select an appropriate media service. +*/ + +/*! + \enum QMediaServiceProviderHint::Feature + + Enumerates features a media service may provide. + + \value LowLatencyPlayback + The service is expected to play simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. + + \value RecordingSupport + The service provides audio or video recording functions. +*/ + +/*! + \enum QMediaServiceProviderHint::Type + + Enumerates the possible types of media service provider hint. + + \value Null En empty hint, use the default service. + \value ContentType Select media service most suitable for certain content type. + \value Device Select media service which supports certain device. + \value SupportedFeatures Select media service supporting the set of optional features. +*/ + + +/*! + Constructs an empty media service provider hint. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint() + :d(new QMediaServiceProviderHintPrivate(Null)) +{ +} + +/*! + Constructs a ContentType media service provider hint. + + This type of hint describes a service that is able to play content of a specific MIME \a type + encoded with one or more of the listed \a codecs. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QString &type, const QStringList& codecs) + :d(new QMediaServiceProviderHintPrivate(ContentType)) +{ + d->mimeType = type; + d->codecs = codecs; +} + +/*! + Constructs a Device media service provider hint. + + This type of hint describes a media service that utilizes a specific \a device. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QByteArray &device) + :d(new QMediaServiceProviderHintPrivate(Device)) +{ + d->device = device; +} + +/*! + Constructs a SupportedFeatures media service provider hint. + + This type of hint describes a service which supports a specific set of \a features. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(QMediaServiceProviderHint::Features features) + :d(new QMediaServiceProviderHintPrivate(SupportedFeatures)) +{ + d->features = features; +} + +/*! + Constructs a copy of the media service provider hint \a other. +*/ +QMediaServiceProviderHint::QMediaServiceProviderHint(const QMediaServiceProviderHint &other) + :d(other.d) +{ +} + +/*! + Destroys a media service provider hint. +*/ +QMediaServiceProviderHint::~QMediaServiceProviderHint() +{ +} + +/*! + Assigns the value \a other to a media service provider hint. +*/ +QMediaServiceProviderHint& QMediaServiceProviderHint::operator=(const QMediaServiceProviderHint &other) +{ + d = other.d; + return *this; +} + +/*! + Identifies if \a other is of equal value to a media service provider hint. + + Returns true if the hints are equal, and false if they are not. +*/ +bool QMediaServiceProviderHint::operator == (const QMediaServiceProviderHint &other) const +{ + return (d == other.d) || + (d->type == other.d->type && + d->device == other.d->device && + d->mimeType == other.d->mimeType && + d->codecs == other.d->codecs && + d->features == other.d->features); +} + +/*! + Identifies if \a other is not of equal value to a media service provider hint. + + Returns true if the hints are not equal, and false if they are. +*/ +bool QMediaServiceProviderHint::operator != (const QMediaServiceProviderHint &other) const +{ + return !(*this == other); +} + +/*! + Returns true if a media service provider is null. +*/ +bool QMediaServiceProviderHint::isNull() const +{ + return d->type == Null; +} + +/*! + Returns the type of a media service provider hint. +*/ +QMediaServiceProviderHint::Type QMediaServiceProviderHint::type() const +{ + return d->type; +} + +/*! + Returns the mime type of the media a service is expected to be able play. +*/ +QString QMediaServiceProviderHint::mimeType() const +{ + return d->mimeType; +} + +/*! + Returns a list of codes a media service is expected to be able to decode. +*/ +QStringList QMediaServiceProviderHint::codecs() const +{ + return d->codecs; +} + +/*! + Returns the name of a device a media service is expected to utilize. +*/ +QByteArray QMediaServiceProviderHint::device() const +{ + return d->device; +} + +/*! + Returns a set of features a media service is expected to provide. +*/ +QMediaServiceProviderHint::Features QMediaServiceProviderHint::features() const +{ + return d->features; +} + + +Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, loader, + (QMediaServiceProviderFactoryInterface_iid, QLatin1String("/mediaservices"), Qt::CaseInsensitive)) + + +class QPluginServiceProvider : public QMediaServiceProvider +{ + QMap pluginMap; + +public: + QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + { + QString key(type); + + QListplugins; + foreach (QObject *obj, loader()->instances(key)) { + QMediaServiceProviderPlugin *plugin = + qobject_cast(obj); + if (plugin) + plugins << plugin; + } + + if (!plugins.isEmpty()) { + QMediaServiceProviderPlugin *plugin = 0; + + switch (hint.type()) { + case QMediaServiceProviderHint::Null: + plugin = plugins[0]; + //special case for media player, if low latency was not asked, + //prefer services not offering it, since they are likely to support + //more formats + if (type == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(currentPlugin); + + if (!iface || !(iface->supportedFeatures(type) & + QMediaServiceProviderHint::LowLatencyPlayback)) { + plugin = currentPlugin; + break; + } + + } + } + break; + case QMediaServiceProviderHint::SupportedFeatures: + plugin = plugins[0]; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(currentPlugin); + + if (iface) { + if ((iface->supportedFeatures(type) & hint.features()) == hint.features()) { + plugin = currentPlugin; + break; + } + } + } + break; + case QMediaServiceProviderHint::Device: { + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast(currentPlugin); + + if (!iface) { + // the plugin may support the device, + // but this choice still can be overridden + plugin = currentPlugin; + } else { + if (iface->devices(type).contains(hint.device())) { + plugin = currentPlugin; + break; + } + } + } + } + break; + case QMediaServiceProviderHint::ContentType: { + QtMedia::SupportEstimate estimate = QtMedia::NotSupported; + foreach (QMediaServiceProviderPlugin *currentPlugin, plugins) { + QtMedia::SupportEstimate currentEstimate = QtMedia::MaybeSupported; + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast(currentPlugin); + + if (iface) + currentEstimate = iface->hasSupport(hint.mimeType(), hint.codecs()); + + if (currentEstimate > estimate) { + estimate = currentEstimate; + plugin = currentPlugin; + + if (currentEstimate == QtMedia::PreferedService) + break; + } + } + } + break; + } + + if (plugin != 0) { + QMediaService *service = plugin->create(key); + if (service != 0) + pluginMap.insert(service, plugin); + + return service; + } + } + + qWarning() << "defaultServiceProvider::requestService(): no service found for -" << key; + return 0; + } + + void releaseService(QMediaService *service) + { + if (service != 0) { + QMediaServiceProviderPlugin *plugin = pluginMap.take(service); + + if (plugin != 0) + plugin->release(service); + } + } + + QtMedia::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const + { + QList instances = loader()->instances(serviceType); + + if (instances.isEmpty()) + return QtMedia::NotSupported; + + bool allServicesProvideInterface = true; + QtMedia::SupportEstimate supportEstimate = QtMedia::NotSupported; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast(obj); + + //if low latency playback was asked, skip services known + //not to provide low latency playback + if (flags & QMediaPlayer::LowLatency) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(obj); + + if (iface && !(iface->supportedFeatures(serviceType) & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + } + + if (iface) + supportEstimate = qMax(supportEstimate, iface->hasSupport(mimeType, codecs)); + else + allServicesProvideInterface = false; + } + + //don't return PreferedService + supportEstimate = qMin(supportEstimate, QtMedia::ProbablySupported); + + //Return NotSupported only if no services are available of serviceType + //or all the services returned NotSupported, otherwise return at least MaybeSupported + if (!allServicesProvideInterface) + supportEstimate = qMax(QtMedia::MaybeSupported, supportEstimate); + + return supportEstimate; + } + + QStringList supportedMimeTypes(const QByteArray &serviceType, int flags) const + { + QList instances = loader()->instances(serviceType); + + QStringList supportedTypes; + + foreach(QObject *obj, instances) { + QMediaServiceSupportedFormatsInterface *iface = + qobject_cast(obj); + + // If low latency playback was asked for, skip MIME types from services known + // not to provide low latency playback + if (flags & QMediaPlayer::LowLatency) { + QMediaServiceFeaturesInterface *iface = + qobject_cast(obj); + + if (iface && !(iface->supportedFeatures(serviceType) & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + } + + if (iface) { + supportedTypes << iface->supportedMimeTypes(); + } + } + + // Multiple services may support the same MIME type + supportedTypes.removeDuplicates(); + + return supportedTypes; + } + + QList devices(const QByteArray &serviceType) const + { + QList res; + + foreach(QObject *obj, loader()->instances(serviceType)) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast(obj); + + if (iface) { + res.append(iface->devices(serviceType)); + } + } + + return res; + } + + QString deviceDescription(const QByteArray &serviceType, const QByteArray &device) + { + foreach(QObject *obj, loader()->instances(serviceType)) { + QMediaServiceSupportedDevicesInterface *iface = + qobject_cast(obj); + + if (iface) { + if (iface->devices(serviceType).contains(device)) + return iface->deviceDescription(serviceType, device); + } + } + + return QString(); + } +}; + +Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider); + +/*! + \class QMediaServiceProvider + \preliminary + \brief The QMediaServiceProvider class provides an abstract allocator for media services. +*/ + +/*! + \fn QMediaServiceProvider::requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) + + Requests an instance of a \a type service which best matches the given \a hint. + + Returns a pointer to the requested service, or a null pointer if there is no suitable service. + + The returned service must be released with releaseService when it is finished with. +*/ + +/*! + \fn QMediaServiceProvider::releaseService(QMediaService *service) + + Releases a media \a service requested with requestService(). +*/ + +/*! + \fn QtMedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, const QString &mimeType, const QStringList& codecs, int flags) const + + Returns how confident a media service provider is that is can provide a \a serviceType + service that is able to play media of a specific \a mimeType that is encoded using the listed + \a codecs while adhearing to constraints identified in \a flags. +*/ +QtMedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(mimeType); + Q_UNUSED(codecs); + Q_UNUSED(flags); + + return QtMedia::MaybeSupported; +} + +/*! + \fn QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const + + Returns a list of MIME types supported by the service provider for the specified \a serviceType. + + The resultant list is restricted to MIME types which can be supported given the constraints in \a flags. +*/ +QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const +{ + Q_UNUSED(serviceType); + Q_UNUSED(flags); + + return QStringList(); +} + +/*! + Returns the list of devices related to \a service type. +*/ +QList QMediaServiceProvider::devices(const QByteArray &service) const +{ + Q_UNUSED(service); + return QList(); +} + +/*! + Returns the description of \a device related to \a serviceType, + suitable to be displayed to user. +*/ +QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, const QByteArray &device) +{ + Q_UNUSED(serviceType); + Q_UNUSED(device); + return QString(); +} + +/*! + Returns a default provider of media services. +*/ +QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider() +{ + return pluginProvider(); +} + +/*! + \class QMediaServiceProviderPlugin + \preliminary + \brief The QMediaServiceProviderPlugin class interface provides an interface for QMediaService + plug-ins. + + A media service provider plug-in may implement one or more of + QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedDevicesInterface, + and QMediaServiceFeaturesInterface to identify the features it supports. +*/ + +/*! + \fn QMediaServiceProviderPlugin::keys() const + + Returns a list of keys for media services a plug-in can create. +*/ + +/*! + \fn QMediaServiceProviderPlugin::create(const QString &key) + + Constructs a new instance of the QMediaService identified by \a key. + + The QMediaService returned must be destroyed with release(). +*/ + +/*! + \fn QMediaServiceProviderPlugin::release(QMediaService *service) + + Destroys a media \a service constructed with create(). +*/ + + +/*! + \class QMediaServiceSupportedFormatsInterface + \brief The QMediaServiceSupportedFormatsInterface class interface + identifies if a media service plug-in supports a media format. + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::~QMediaServiceSupportedFormatsInterface() + + Destroys a media service supported formats interface. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::hasSupport(const QString &mimeType, const QStringList& codecs) const + + Returns the level of support a media service plug-in has for a \a mimeType and set of \a codecs. +*/ + +/*! + \fn QMediaServiceSupportedFormatsInterface::supportedMimeTypes() const + + Returns a list of MIME types supported by the media service plug-in. +*/ + +/*! + \class QMediaServiceSupportedDevicesInterface + \brief The QMediaServiceSupportedDevicesInterface class interface + identifies the devices supported by a media service plug-in. + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::~QMediaServiceSupportedDevicesInterface() + + Destroys a media service supported devices interface. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::devices(const QByteArray &service) const + + Returns a list of devices supported by a plug-in \a service. +*/ + +/*! + \fn QMediaServiceSupportedDevicesInterface::deviceDescription(const QByteArray &service, const QByteArray &device) + + Returns a description of a \a device supported by a plug-in \a service. +*/ + +/*! + \class QMediaServiceFeaturesInterface + \brief The QMediaServiceFeaturesInterface class interface identifies + features supported by a media service plug-in. + + A QMediaServiceProviderPlugin may implement this interface. +*/ + +/*! + \fn QMediaServiceFeaturesInterface::~QMediaServiceFeaturesInterface() + + Destroys a media service features interface. +*/ +/*! + \fn QMediaServiceFeaturesInterface::supportedFeatures(const QByteArray &service) const + + Returns a set of features supported by a plug-in \a service. +*/ + +#include "moc_qmediaserviceprovider.cpp" +#include "moc_qmediaserviceproviderplugin.cpp" diff --git a/src/multimedia/base/qmediaserviceprovider.h b/src/multimedia/base/qmediaserviceprovider.h new file mode 100644 index 0000000..46f63b5 --- /dev/null +++ b/src/multimedia/base/qmediaserviceprovider.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIASERVICEPROVIDER_H +#define QMEDIASERVICEPROVIDER_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaService; + +class QMediaServiceProviderHintPrivate; +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderHint +{ +public: + enum Type { Null, ContentType, Device, SupportedFeatures }; + + enum Feature { + LowLatencyPlayback = 0x01, + RecordingSupport = 0x02 + }; + Q_DECLARE_FLAGS(Features, Feature) + + QMediaServiceProviderHint(); + QMediaServiceProviderHint(const QString &mimeType, const QStringList& codecs); + QMediaServiceProviderHint(const QByteArray &device); + QMediaServiceProviderHint(Features features); + QMediaServiceProviderHint(const QMediaServiceProviderHint &other); + ~QMediaServiceProviderHint(); + + QMediaServiceProviderHint& operator=(const QMediaServiceProviderHint &other); + + bool operator == (const QMediaServiceProviderHint &other) const; + bool operator != (const QMediaServiceProviderHint &other) const; + + bool isNull() const; + + Type type() const; + + QString mimeType() const; + QStringList codecs() const; + + QByteArray device() const; + + Features features() const; + + //to be extended, if necessary + +private: + QSharedDataPointer d; +}; + +class Q_MULTIMEDIA_EXPORT QMediaServiceProvider : public QObject +{ + Q_OBJECT + +public: + virtual QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &hint = QMediaServiceProviderHint()) = 0; + virtual void releaseService(QMediaService *service) = 0; + + virtual QtMedia::SupportEstimate hasSupport(const QByteArray &serviceType, + const QString &mimeType, + const QStringList& codecs, + int flags = 0) const; + virtual QStringList supportedMimeTypes(const QByteArray &serviceType, int flags = 0) const; + + virtual QList devices(const QByteArray &serviceType) const; + virtual QString deviceDescription(const QByteArray &serviceType, const QByteArray &device); + + static QMediaServiceProvider* defaultServiceProvider(); +}; + +/*! + Service with support for media playback + Required Controls: QMediaPlayerControl + Optional Controls: QMediaPlaylistControl, QAudioDeviceControl + Video Output Controls (used by QWideoWidget and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_MEDIAPLAYER "com.nokia.qt.mediaplayer" + +/*! + Service with support for recording from audio sources + Required Controls: QAudioDeviceControl + Recording Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_AUDIOSOURCE "com.nokia.qt.audiosource" + +/*! + Service with support for camera use. + Required Controls: QCameraControl + Optional Controls: QCameraExposureControl, QCameraFocusControl, QImageProcessingControl + Still Capture Controls: QImageCaptureControl + Recording Controls (QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl, QVideoEncoderControl, QMediaContainerControl + Viewfinder Video Output Controls (used by QWideoWidget and QGraphicsVideoItem): + Required: QVideoOutputControl + Optional: QVideoWindowControl, QVideoRendererControl, QVideoWidgetControl +*/ +#define Q_MEDIASERVICE_CAMERA "com.nokia.qt.camera" + +/*! + Service with support for radio tuning. + Required Controls: QRadioTunerControl + Recording Controls (Optional, used by QMediaRecorder): + Required: QMediaRecorderControl + Recommended: QAudioEncoderControl + Optional: QMediaContainerControl +*/ +#define Q_MEDIASERVICE_RADIO "com.nokia.qt.radio" + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIASERVICEPROVIDER_H diff --git a/src/multimedia/base/qmediaserviceproviderplugin.h b/src/multimedia/base/qmediaserviceproviderplugin.h new file mode 100644 index 0000000..0381093 --- /dev/null +++ b/src/multimedia/base/qmediaserviceproviderplugin.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIASERVICEPROVIDERPLUGIN_H +#define QMEDIASERVICEPROVIDERPLUGIN_H + +#include +#include +#include + +#include + +#ifdef Q_MOC_RUN +# pragma Q_MOC_EXPAND_MACROS +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaService; + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceProviderFactoryInterface : public QFactoryInterface +{ + virtual QStringList keys() const = 0; + virtual QMediaService* create(QString const& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +#define QMediaServiceProviderFactoryInterface_iid \ + "com.nokia.Qt.QMediaServiceProviderFactoryInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceProviderFactoryInterface, QMediaServiceProviderFactoryInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedFormatsInterface +{ + virtual ~QMediaServiceSupportedFormatsInterface() {} + virtual QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const = 0; + virtual QStringList supportedMimeTypes() const = 0; +}; + +#define QMediaServiceSupportedFormatsInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedFormatsInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedFormatsInterface, QMediaServiceSupportedFormatsInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceSupportedDevicesInterface +{ + virtual ~QMediaServiceSupportedDevicesInterface() {} + virtual QList devices(const QByteArray &service) const = 0; + virtual QString deviceDescription(const QByteArray &service, const QByteArray &device) = 0; +}; + +#define QMediaServiceSupportedDevicesInterface_iid \ + "com.nokia.Qt.QMediaServiceSupportedDevicesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceSupportedDevicesInterface, QMediaServiceSupportedDevicesInterface_iid) + + +struct Q_MULTIMEDIA_EXPORT QMediaServiceFeaturesInterface +{ + virtual ~QMediaServiceFeaturesInterface() {} + virtual QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const = 0; +}; + +#define QMediaServiceFeaturesInterface_iid \ + "com.nokia.Qt.QMediaServiceFeaturesInterface/1.0" +Q_DECLARE_INTERFACE(QMediaServiceFeaturesInterface, QMediaServiceFeaturesInterface_iid) + +class Q_MULTIMEDIA_EXPORT QMediaServiceProviderPlugin : public QObject, public QMediaServiceProviderFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceProviderFactoryInterface:QFactoryInterface) + +public: + virtual QStringList keys() const = 0; + virtual QMediaService* create(const QString& key) = 0; + virtual void release(QMediaService *service) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIASERVICEPROVIDERPLUGIN_H diff --git a/src/multimedia/base/qmediatimerange.cpp b/src/multimedia/base/qmediatimerange.cpp new file mode 100644 index 0000000..38a8aea --- /dev/null +++ b/src/multimedia/base/qmediatimerange.cpp @@ -0,0 +1,706 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaTimeInterval + \brief The QMediaTimeInterval class represents a time interval with integer precision. + \ingroup multimedia + + An interval is specified by an inclusive start() and end() time. + These must be set in the constructor, as this is an immutable class. + The specific units of time represented by the class have not been defined - + it is suitable for any times which can be represented by a signed 64 bit integer. + + The isNormal() method determines if a time interval is normal + (a normal time interval has start() <= end()). An abnormal interval can be converted + in to a normal interval by calling the normalized() method. + + The contains() method determines if a specified time lies within + the time interval. + + The translated() method returns a time interval which has been translated + forwards or backwards through time by a specified offset. + + \sa QMediaTimeRange +*/ + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval() + + Constructs an empty interval. +*/ +QMediaTimeInterval::QMediaTimeInterval() + : s(0) + , e(0) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + + Constructs an interval with the specified \a start and \a end times. +*/ +QMediaTimeInterval::QMediaTimeInterval(qint64 start, qint64 end) + : s(start) + , e(end) +{ + +} + +/*! + \fn QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + + Constructs an interval by taking a copy of \a other. +*/ +QMediaTimeInterval::QMediaTimeInterval(const QMediaTimeInterval &other) + : s(other.s) + , e(other.e) +{ + +} + +/*! + \fn QMediaTimeInterval::start() const + + Returns the start time of the interval. + + \sa end() +*/ +qint64 QMediaTimeInterval::start() const +{ + return s; +} + +/*! + \fn QMediaTimeInterval::end() const + + Returns the end time of the interval. + + \sa start() +*/ +qint64 QMediaTimeInterval::end() const +{ + return e; +} + +/*! + \fn QMediaTimeInterval::contains(qint64 time) const + + Returns true if the time interval contains the specified \a time. + That is, start() <= time <= end(). +*/ +bool QMediaTimeInterval::contains(qint64 time) const +{ + return isNormal() ? (s <= time && time <= e) + : (e <= time && time <= s); +} + +/*! + \fn QMediaTimeInterval::isNormal() const + + Returns true if this time interval is normal. + A normal time interval has start() <= end(). + + \sa normalized() +*/ +bool QMediaTimeInterval::isNormal() const +{ + return s <= e; +} + +/*! + \fn QMediaTimeInterval::normalized() const + + Returns a normalized version of this interval. + + If the start() time of the interval is greater than the end() time, + then the returned interval has the start and end times swapped. +*/ +QMediaTimeInterval QMediaTimeInterval::normalized() const +{ + if(s > e) + return QMediaTimeInterval(e, s); + + return *this; +} + +/*! + \fn QMediaTimeInterval::translated(qint64 offset) const + + Returns a copy of this time interval, translated by a value of \a offset. + An interval can be moved forward through time with a positive offset, or backward + through time with a negative offset. +*/ +QMediaTimeInterval QMediaTimeInterval::translated(qint64 offset) const +{ + return QMediaTimeInterval(s + offset, e + offset); +} + +/*! + \fn operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is exactly equal to \a b. +*/ +bool operator==(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() == b.start() && a.end() == b.end(); +} + +/*! + \fn operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) + \relates QMediaTimeRange + + Returns true if \a a is not exactly equal to \a b. +*/ +bool operator!=(const QMediaTimeInterval &a, const QMediaTimeInterval &b) +{ + return a.start() != b.start() || a.end() != b.end(); +} + +class QMediaTimeRangePrivate : public QSharedData +{ +public: + + QMediaTimeRangePrivate(); + QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other); + QMediaTimeRangePrivate(const QMediaTimeInterval &interval); + + QList intervals; + + void addInterval(const QMediaTimeInterval &interval); + void removeInterval(const QMediaTimeInterval &interval); +}; + +QMediaTimeRangePrivate::QMediaTimeRangePrivate() + : QSharedData() +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeRangePrivate &other) + : QSharedData() + , intervals(other.intervals) +{ + +} + +QMediaTimeRangePrivate::QMediaTimeRangePrivate(const QMediaTimeInterval &interval) + : QSharedData() +{ + if(interval.isNormal()) + intervals << interval; +} + +void QMediaTimeRangePrivate::addInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + // Find a place to insert the interval + int i; + for (i = 0; i < intervals.count(); i++) { + // Insert before this element + if(interval.s < intervals[i].s) { + intervals.insert(i, interval); + break; + } + } + + // Interval needs to be added to the end of the list + if (i == intervals.count()) + intervals.append(interval); + + // Do we need to correct the element before us? + if(i > 0 && intervals[i - 1].e >= interval.s - 1) + i--; + + // Merge trailing ranges + while (i < intervals.count() - 1 + && intervals[i].e >= intervals[i + 1].s - 1) { + intervals[i].e = qMax(intervals[i].e, intervals[i + 1].e); + intervals.removeAt(i + 1); + } +} + +void QMediaTimeRangePrivate::removeInterval(const QMediaTimeInterval &interval) +{ + // Handle normalized intervals only + if(!interval.isNormal()) + return; + + for (int i = 0; i < intervals.count(); i++) { + QMediaTimeInterval r = intervals[i]; + + if (r.e < interval.s) { + // Before the removal interval + continue; + } else if (interval.e < r.s) { + // After the removal interval - stop here + break; + } else if (r.s < interval.s && interval.e < r.e) { + // Split case - a single range has a chunk removed + intervals[i].e = interval.s -1; + addInterval(QMediaTimeInterval(interval.e + 1, r.e)); + break; + } else if (r.s < interval.s) { + // Trimming Tail Case + intervals[i].e = interval.s - 1; + } else if (interval.e < r.e) { + // Trimming Head Case - we can stop after this + intervals[i].s = interval.e + 1; + break; + } else { + // Complete coverage case + intervals.removeAt(i); + --i; + } + } +} + +/*! + \class QMediaTimeRange + \brief The QMediaTimeRange class represents a set of zero or more disjoint + time intervals. + \ingroup multimedia + + \reentrant + + The earliestTime(), latestTime(), intervals() and isEmpty() + methods are used to get information about the current time range. + + The addInterval(), removeInterval() and clear() methods are used to modify + the current time range. + + When adding or removing intervals from the time range, existing intervals + within the range may be expanded, trimmed, deleted, merged or split to ensure + that all intervals within the time range remain distinct and disjoint. As a + consequence, all intervals added or removed from a time range must be + \l{QMediaTimeInterval::isNormal()}{normal}. + + \sa QMediaTimeInterval +*/ + +/*! + \fn QMediaTimeRange::QMediaTimeRange() + + Constructs an empty time range. +*/ +QMediaTimeRange::QMediaTimeRange() + : d(new QMediaTimeRangePrivate) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + + Constructs a time range that contains an initial interval from + \a start to \a end inclusive. + + If the interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(qint64 start, qint64 end) + : d(new QMediaTimeRangePrivate(QMediaTimeInterval(start, end))) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + + Constructs a time range that contains an intitial interval, \a interval. + + If \a interval is not \l{QMediaTimeInterval::isNormal()}{normal}, + the resulting time range will be empty. + + \sa addInterval() +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeInterval &interval) + : d(new QMediaTimeRangePrivate(interval)) +{ + +} + +/*! + \fn QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + + Constructs a time range by copying another time \a range. +*/ +QMediaTimeRange::QMediaTimeRange(const QMediaTimeRange &range) + : d(range.d) +{ + +} + +/*! + \fn QMediaTimeRange::~QMediaTimeRange() + + Destructor. +*/ +QMediaTimeRange::~QMediaTimeRange() +{ + +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeRange &other) + + Takes a copy of the \a other time range and returns itself. +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeRange &other) +{ + d = other.d; + return *this; +} + +/*! + \fn QMediaTimeRange::operator=(const QMediaTimeInterval &interval) + + Sets the time range to a single continuous interval, \a interval. +*/ +QMediaTimeRange &QMediaTimeRange::operator=(const QMediaTimeInterval &interval) +{ + d = new QMediaTimeRangePrivate(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::earliestTime() const + + Returns the earliest time within the time range. + + For empty time ranges, this value is equal to zero. + + \sa latestTime() +*/ +qint64 QMediaTimeRange::earliestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[0].s; + + return 0; +} + +/*! + \fn QMediaTimeRange::latestTime() const + + Returns the latest time within the time range. + + For empty time ranges, this value is equal to zero. + + \sa earliestTime() +*/ +qint64 QMediaTimeRange::latestTime() const +{ + if (!d->intervals.isEmpty()) + return d->intervals[d->intervals.count() - 1].e; + + return 0; +} + +/*! + \fn QMediaTimeRange::addInterval(qint64 start, qint64 end) + \overload + + Adds the interval specified by \a start and \a end + to the time range. + + \sa addInterval() +*/ +void QMediaTimeRange::addInterval(qint64 start, qint64 end) +{ + d->addInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range. + + Adding intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + If the specified interval is adjacent to, or overlaps existing + intervals within the time range, these intervals will be merged. + + This operation takes \l{linear time} + + \sa removeInterval() +*/ +void QMediaTimeRange::addInterval(const QMediaTimeInterval &interval) +{ + d->addInterval(interval); +} + +/*! + \fn QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) + + Adds each of the intervals in \a range to this time range. + + Equivalent to calling addInterval() for each interval in \a range. +*/ +void QMediaTimeRange::addTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->addInterval(i); + } +} + +/*! + \fn QMediaTimeRange::removeInterval(qint64 start, qint64 end) + \overload + + Removes the interval specified by \a start and \a end + from the time range. + + \sa removeInterval() +*/ +void QMediaTimeRange::removeInterval(qint64 start, qint64 end) +{ + d->removeInterval(QMediaTimeInterval(start, end)); +} + +/*! + \fn QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range. + + Removing intervals which are not \l{QMediaTimeInterval::isNormal()}{normal} + is invalid, and will be ignored. + + Intervals within the time range will be trimmed, split or deleted + such that no intervals within the time range include any part of the + target interval. + + This operation takes \l{linear time} + + \sa addInterval() +*/ +void QMediaTimeRange::removeInterval(const QMediaTimeInterval &interval) +{ + d->removeInterval(interval); +} + +/*! + \fn QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) + + Removes each of the intervals in \a range from this time range. + + Equivalent to calling removeInterval() for each interval in \a range. +*/ +void QMediaTimeRange::removeTimeRange(const QMediaTimeRange &range) +{ + foreach(const QMediaTimeInterval &i, range.intervals()) { + d->removeInterval(i); + } +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeRange &other) + + Adds each interval in \a other to the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeRange &other) +{ + addTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) + + Adds the specified \a interval to the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator+=(const QMediaTimeInterval &interval) +{ + addInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeRange &other) + + Removes each interval in \a other from the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeRange &other) +{ + removeTimeRange(other); + return *this; +} + +/*! + \fn QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) + + Removes the specified \a interval from the time range and returns the result. +*/ +QMediaTimeRange& QMediaTimeRange::operator-=(const QMediaTimeInterval &interval) +{ + removeInterval(interval); + return *this; +} + +/*! + \fn QMediaTimeRange::clear() + + Removes all intervals from the time range. + + \sa removeInterval() +*/ +void QMediaTimeRange::clear() +{ + d->intervals.clear(); +} + +/*! + \fn QMediaTimeRange::intervals() const + + Returns the list of intervals covered by this time range. +*/ +QList QMediaTimeRange::intervals() const +{ + return d->intervals; +} + +/*! + \fn QMediaTimeRange::isEmpty() const + + Returns true if there are no intervals within the time range. + + \sa intervals() +*/ +bool QMediaTimeRange::isEmpty() const +{ + return d->intervals.isEmpty(); +} + +/*! + \fn QMediaTimeRange::isContinuous() const + + Returns true if the time range consists of a continuous interval. + That is, there is one or fewer disjoint intervals within the time range. +*/ +bool QMediaTimeRange::isContinuous() const +{ + return (d->intervals.count() <= 1); +} + +/*! + \fn QMediaTimeRange::contains(qint64 time) const + + Returns true if the specified \a time lies within the time range. +*/ +bool QMediaTimeRange::contains(qint64 time) const +{ + for (int i = 0; i < d->intervals.count(); i++) { + if (d->intervals[i].contains(time)) + return true; + + if (time < d->intervals[i].s) + break; + } + + return false; +} + +/*! + \fn operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if all intervals in \a a are present in \a b. +*/ +bool operator==(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + if (a.intervals().count() != b.intervals().count()) + return false; + + for (int i = 0; i < a.intervals().count(); i++) + { + if(a.intervals()[i] != b.intervals()[i]) + return false; + } + + return true; +} + +/*! + \fn operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) + \relates QMediaTimeRange + + Returns true if one or more intervals in \a a are not present in \a b. +*/ +bool operator!=(const QMediaTimeRange &a, const QMediaTimeRange &b) +{ + return !(a == b); +} + +/*! + \fn operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing the union between \a r1 and \a r2. + */ +QMediaTimeRange operator+(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) += r2); +} + +/*! + \fn operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) + + Returns a time range containing \a r2 subtracted from \a r1. + */ +QMediaTimeRange operator-(const QMediaTimeRange &r1, const QMediaTimeRange &r2) +{ + return (QMediaTimeRange(r1) -= r2); +} + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmediatimerange.h b/src/multimedia/base/qmediatimerange.h new file mode 100644 index 0000000..d065368 --- /dev/null +++ b/src/multimedia/base/qmediatimerange.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QMEDIATIMERANGE_H +#define QMEDIATIMERANGE_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaTimeRangePrivate; + +class Q_MULTIMEDIA_EXPORT QMediaTimeInterval +{ +public: + QMediaTimeInterval(); + QMediaTimeInterval(qint64 start, qint64 end); + QMediaTimeInterval(const QMediaTimeInterval&); + + qint64 start() const; + qint64 end() const; + + bool contains(qint64 time) const; + + bool isNormal() const; + QMediaTimeInterval normalized() const; + QMediaTimeInterval translated(qint64 offset) const; + +private: + friend class QMediaTimeRangePrivate; + friend class QMediaTimeRange; + + qint64 s; + qint64 e; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeInterval&, const QMediaTimeInterval&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeInterval&, const QMediaTimeInterval&); + +class Q_MULTIMEDIA_EXPORT QMediaTimeRange +{ +public: + + QMediaTimeRange(); + QMediaTimeRange(qint64 start, qint64 end); + QMediaTimeRange(const QMediaTimeInterval&); + QMediaTimeRange(const QMediaTimeRange &range); + ~QMediaTimeRange(); + + QMediaTimeRange &operator=(const QMediaTimeRange&); + QMediaTimeRange &operator=(const QMediaTimeInterval&); + + qint64 earliestTime() const; + qint64 latestTime() const; + + QList intervals() const; + bool isEmpty() const; + bool isContinuous() const; + + bool contains(qint64 time) const; + + void addInterval(qint64 start, qint64 end); + void addInterval(const QMediaTimeInterval &interval); + void addTimeRange(const QMediaTimeRange&); + + void removeInterval(qint64 start, qint64 end); + void removeInterval(const QMediaTimeInterval &interval); + void removeTimeRange(const QMediaTimeRange&); + + QMediaTimeRange& operator+=(const QMediaTimeRange&); + QMediaTimeRange& operator+=(const QMediaTimeInterval&); + QMediaTimeRange& operator-=(const QMediaTimeRange&); + QMediaTimeRange& operator-=(const QMediaTimeInterval&); + + void clear(); + +private: + QSharedDataPointer d; +}; + +Q_MULTIMEDIA_EXPORT bool operator==(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT bool operator!=(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator+(const QMediaTimeRange&, const QMediaTimeRange&); +Q_MULTIMEDIA_EXPORT QMediaTimeRange operator-(const QMediaTimeRange&, const QMediaTimeRange&); + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIATIMERANGE_H diff --git a/src/multimedia/base/qmetadatacontrol.cpp b/src/multimedia/base/qmetadatacontrol.cpp new file mode 100644 index 0000000..e45bb0c --- /dev/null +++ b/src/multimedia/base/qmetadatacontrol.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + + +/*! + \class QMetaDataControl + \ingroup multimedia-serv + + \preliminary + \brief The QMetaDataControl class provides access to the meta-data of a + QMediaService's media. + + If a QMediaService can provide read or write access to the meta-data of + its current media it will implement QMetaDataControl. This control + provides functions for both retrieving and setting meta-data values. + Meta-data may be addressed by the well defined keys in the + QtMedia::MetaData enumeration using the metaData() functions, or by + string keys using the extendedMetaData() functions. + + The functionality provided by this control is exposed to application + code by the meta-data members of QMediaObject, and so meta-data access + is potentially available in any of the media object classes. Any media + service may implement QMetaDataControl. + + The interface name of QMetaDataControl is \c com.nokia.Qt.QMetaDataControl/1.0 as + defined in QMetaDataControl_iid. + + \sa QMediaService::control(), QMediaObject +*/ + +/*! + \macro QMetaDataControl_iid + + \c com.nokia.Qt.QMetaDataControl/1.0 + + Defines the interface name of the QMetaDataControl class. + + \relates QMetaDataControl +*/ + +/*! + Construct a QMetaDataControl with \a parent. This class is meant as a base class + for service specific meta data providers so this constructor is protected. +*/ + +QMetaDataControl::QMetaDataControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + Destroy the meta-data object. +*/ + +QMetaDataControl::~QMetaDataControl() +{ +} + +/*! + \fn bool QMetaDataControl::isMetaDataAvailable() const + + Identifies if meta-data is available from a media service. + + Returns true if the meta-data is available and false otherwise. +*/ + +/*! + \fn bool QMetaDataControl::isWritable() const + + Identifies if a media service's meta-data can be edited. + + Returns true if the meta-data is writable and false otherwise. +*/ + +/*! + \fn QVariant QMetaDataControl::metaData(QtMedia::MetaData key) const + + Returns the meta-data for the given \a key. +*/ + +/*! + \fn void QMetaDataControl::setMetaData(QtMedia::MetaData key, const QVariant &value) + + Sets the \a value of the meta-data element with the given \a key. +*/ + +/*! + \fn QMetaDataControl::availableMetaData() const + + Returns a list of keys there is meta-data available for. +*/ + +/*! + \fn QMetaDataControl::extendedMetaData(const QString &key) const + + Returns the metaData for an abitrary string \a key. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. +*/ + +/*! + \fn QMetaDataControl::setExtendedMetaData(const QString &key, const QVariant &value) + + Change the value of the meta-data element with an abitrary string \a key to \a value. + + The valid selection of keys for extended meta-data is determined by the provider and the meaning + and type may differ between providers. +*/ + +/*! + \fn QMetaDataControl::availableExtendedMetaData() const + + Returns a list of keys there is extended meta-data available for. +*/ + + +/*! + \fn void QMetaDataControl::metaDataChanged() + + Signal the changes of meta-data. +*/ + +/*! + \fn void QMetaDataControl::metaDataAvailableChanged(bool available) + + Signal the availability of meta-data has changed, \a available will + be true if the multimedia object has meta-data. +*/ + +/*! + \fn void QMetaDataControl::writableChanged(bool writable) + + Signal a change in the writable status of meta-data, \a writable will be + true if meta-data elements can be added or adjusted. +*/ + +#include "moc_qmetadatacontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qmetadatacontrol.h b/src/multimedia/base/qmetadatacontrol.h new file mode 100644 index 0000000..5609f10 --- /dev/null +++ b/src/multimedia/base/qmetadatacontrol.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMETADATACONTROL_H +#define QMETADATACONTROL_H + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class Q_MULTIMEDIA_EXPORT QMetaDataControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QMetaDataControl(); + + virtual bool isWritable() const = 0; + virtual bool isMetaDataAvailable() const = 0; + + virtual QVariant metaData(QtMedia::MetaData key) const = 0; + virtual void setMetaData(QtMedia::MetaData key, const QVariant &value) = 0; + virtual QList availableMetaData() const = 0; + + virtual QVariant extendedMetaData(const QString &key) const = 0; + virtual void setExtendedMetaData(const QString &key, const QVariant &value) = 0; + virtual QStringList availableExtendedMetaData() const = 0; + +Q_SIGNALS: + void metaDataChanged(); + + void writableChanged(bool writable); + void metaDataAvailableChanged(bool available); + +protected: + QMetaDataControl(QObject *parent = 0); +}; + +#define QMetaDataControl_iid "com.nokia.Qt.QMetaDataControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMetaDataControl, QMetaDataControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QMETADATAPROVIDER_H diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp new file mode 100644 index 0000000..feeb42f --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -0,0 +1,1456 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qpaintervideosurface_p.h" + +#include + +#include +#include +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#endif + +#include + + +QT_BEGIN_NAMESPACE + +class QVideoSurfacePainter +{ +public: + virtual ~QVideoSurfacePainter(); + + virtual QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const = 0; + + virtual bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const = 0; + + virtual QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) = 0; + virtual void stop() = 0; + + virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; + + virtual QAbstractVideoSurface::Error paint( + const QRect &target, QPainter *painter, const QRect &source) = 0; + + virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; +}; + +QVideoSurfacePainter::~QVideoSurfacePainter() +{ +} + +class QVideoSurfaceRasterPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceRasterPainter(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + QAbstractVideoSurface::Error paint( + const QRect &target, QPainter *painter, const QRect &source); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +private: + QList m_imagePixelFormats; + QVideoFrame m_frame; + QSize m_imageSize; + QImage::Format m_imageFormat; + QVideoSurfaceFormat::Direction m_scanLineDirection; +}; + +QVideoSurfaceRasterPainter::QVideoSurfaceRasterPainter() + : m_imageFormat(QImage::Format_Invalid) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 +#ifndef QT_OPENGL_ES // The raster formats should be a subset of the GL formats. + << QVideoFrame::Format_RGB24 +#endif + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB565; +} + +QList QVideoSurfaceRasterPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return handleType == QAbstractVideoBuffer::NoHandle + ? m_imagePixelFormats + : QList(); +} + +bool QVideoSurfaceRasterPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + return format.handleType() == QAbstractVideoBuffer::NoHandle + && m_imagePixelFormats.contains(format.pixelFormat()) + && !format.frameSize().isEmpty(); +} + +QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::start(const QVideoSurfaceFormat &format) +{ + m_frame = QVideoFrame(); + m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + m_imageSize = format.frameSize(); + m_scanLineDirection = format.scanLineDirection(); + + return format.handleType() == QAbstractVideoBuffer::NoHandle + && m_imageFormat != QImage::Format_Invalid + && !m_imageSize.isEmpty() + ? QAbstractVideoSurface::NoError + : QAbstractVideoSurface::UnsupportedFormatError; +} + +void QVideoSurfaceRasterPainter::stop() +{ + m_frame = QVideoFrame(); +} + +QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + return QAbstractVideoSurface::NoError; +} + +QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::paint( + const QRect &target, QPainter *painter, const QRect &source) +{ + if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + QImage image( + m_frame.bits(), + m_imageSize.width(), + m_imageSize.height(), + m_frame.bytesPerLine(), + m_imageFormat); + + if (m_scanLineDirection == QVideoSurfaceFormat::BottomToTop) { + const QTransform oldTransform = painter->transform(); + + painter->scale(1, -1); + painter->translate(0, -target.bottom()); + painter->drawImage( + QRect(target.x(), 0, target.width(), target.height()), image, source); + painter->setTransform(oldTransform); + } else { + painter->drawImage(target, image, source); + } + + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } else { + painter->fillRect(target, Qt::black); + } + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceRasterPainter::updateColors(int, int, int, int) +{ +} + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +#ifndef Q_WS_MAC +# ifndef APIENTRYP +# ifdef APIENTRY +# define APIENTRYP APIENTRY * +# else +# define APIENTRY +# define APIENTRYP * +# endif +# endif +#else +# define APIENTRY +# define APIENTRYP * +#endif + +#ifndef GL_TEXTURE0 +# define GL_TEXTURE0 0x84C0 +# define GL_TEXTURE1 0x84C1 +# define GL_TEXTURE2 0x84C2 +#endif +#ifndef GL_PROGRAM_ERROR_STRING_ARB +# define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#endif + +#ifndef GL_UNSIGNED_SHORT_5_6_5 +# define GL_UNSIGNED_SHORT_5_6_5 33635 +#endif + +class QVideoSurfaceGLPainter : public QVideoSurfacePainter +{ +public: + QVideoSurfaceGLPainter(QGLContext *context); + ~QVideoSurfaceGLPainter(); + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const; + + QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); + + void updateColors(int brightness, int contrast, int hue, int saturation); + +protected: + void initRgbTextureInfo(GLenum internalFormat, GLuint format, GLenum type, const QSize &size); + void initYuv420PTextureInfo(const QSize &size); + void initYv12TextureInfo(const QSize &size); + +#ifndef QT_OPENGL_ES + typedef void (APIENTRY *_glActiveTexture) (GLenum); + _glActiveTexture glActiveTexture; +#endif + + QList m_imagePixelFormats; + QList m_glPixelFormats; + QMatrix4x4 m_colorMatrix; + QVideoFrame m_frame; + + QGLContext *m_context; + QAbstractVideoBuffer::HandleType m_handleType; + QVideoSurfaceFormat::Direction m_scanLineDirection; + GLenum m_textureFormat; + GLuint m_textureInternalFormat; + GLenum m_textureType; + int m_textureCount; + GLuint m_textureIds[3]; + int m_textureWidths[3]; + int m_textureHeights[3]; + int m_textureOffsets[3]; + bool m_yuv; +}; + +QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QGLContext *context) + : m_context(context) + , m_handleType(QAbstractVideoBuffer::NoHandle) + , m_scanLineDirection(QVideoSurfaceFormat::TopToBottom) + , m_textureFormat(0) + , m_textureInternalFormat(0) + , m_textureType(0) + , m_textureCount(0) + , m_yuv(false) +{ +#ifndef QT_OPENGL_ES + glActiveTexture = (_glActiveTexture)m_context->getProcAddress(QLatin1String("glActiveTexture")); +#endif +} + +QVideoSurfaceGLPainter::~QVideoSurfaceGLPainter() +{ +} + +QList QVideoSurfaceGLPainter::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + switch (handleType) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats; + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats; + default: + return QList(); + } +} + +bool QVideoSurfaceGLPainter::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *) const +{ + if (format.frameSize().isEmpty()) { + return false; + } else { + switch (format.handleType()) { + case QAbstractVideoBuffer::NoHandle: + return m_imagePixelFormats.contains(format.pixelFormat()); + case QAbstractVideoBuffer::GLTextureHandle: + return m_glPixelFormats.contains(format.pixelFormat()); + default: + return false; + } + } +} + +QAbstractVideoSurface::Error QVideoSurfaceGLPainter::setCurrentFrame(const QVideoFrame &frame) +{ + m_frame = frame; + + if (m_handleType == QAbstractVideoBuffer::GLTextureHandle) { + m_textureIds[0] = frame.handle().toInt(); + } else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { + m_context->makeCurrent(); + + for (int i = 0; i < m_textureCount; ++i) { + glBindTexture(GL_TEXTURE_2D, m_textureIds[i]); + glTexImage2D( + GL_TEXTURE_2D, + 0, + m_textureInternalFormat, + m_textureWidths[i], + m_textureHeights[i], + 0, + m_textureFormat, + m_textureType, + m_frame.bits() + m_textureOffsets[i]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + m_frame.unmap(); + } else if (m_frame.isValid()) { + return QAbstractVideoSurface::IncorrectFormatError; + } + + return QAbstractVideoSurface::NoError; +} + +void QVideoSurfaceGLPainter::updateColors(int brightness, int contrast, int hue, int saturation) +{ + const qreal b = brightness / 200.0; + const qreal c = contrast / 100.0 + 1.0; + const qreal h = hue / 200.0; + const qreal s = saturation / 100.0 + 1.0; + + const qreal cosH = qCos(M_PI * h); + const qreal sinH = qSin(M_PI * h); + + const qreal h11 = -0.4728 * cosH + 0.7954 * sinH + 1.4728; + const qreal h21 = -0.9253 * cosH - 0.0118 * sinH + 0.9523; + const qreal h31 = 0.4525 * cosH + 0.8072 * sinH - 0.4524; + + const qreal h12 = 1.4728 * cosH - 1.3728 * sinH - 1.4728; + const qreal h22 = 1.9253 * cosH + 0.5891 * sinH - 0.9253; + const qreal h32 = -0.4525 * cosH - 1.9619 * sinH + 0.4525; + + const qreal h13 = 1.4728 * cosH - 0.2181 * sinH - 1.4728; + const qreal h23 = 0.9253 * cosH + 1.1665 * sinH - 0.9253; + const qreal h33 = 0.5475 * cosH - 1.3846 * sinH + 0.4525; + + const qreal sr = (1.0 - s) * 0.3086; + const qreal sg = (1.0 - s) * 0.6094; + const qreal sb = (1.0 - s) * 0.0820; + + const qreal sr_s = sr + s; + const qreal sg_s = sg + s; + const qreal sb_s = sr + s; + + const float m4 = (s + sr + sg + sb) * (0.5 - 0.5 * c + b); + + m_colorMatrix(0, 0) = c * (sr_s * h11 + sg * h21 + sb * h31); + m_colorMatrix(0, 1) = c * (sr_s * h12 + sg * h22 + sb * h32); + m_colorMatrix(0, 2) = c * (sr_s * h13 + sg * h23 + sb * h33); + m_colorMatrix(0, 3) = m4; + + m_colorMatrix(1, 0) = c * (sr * h11 + sg_s * h21 + sb * h31); + m_colorMatrix(1, 1) = c * (sr * h12 + sg_s * h22 + sb * h32); + m_colorMatrix(1, 2) = c * (sr * h13 + sg_s * h23 + sb * h33); + m_colorMatrix(1, 3) = m4; + + m_colorMatrix(2, 0) = c * (sr * h11 + sg * h21 + sb_s * h31); + m_colorMatrix(2, 1) = c * (sr * h12 + sg * h22 + sb_s * h32); + m_colorMatrix(2, 2) = c * (sr * h13 + sg * h23 + sb_s * h33); + m_colorMatrix(2, 3) = m4; + + m_colorMatrix(3, 0) = 0.0; + m_colorMatrix(3, 1) = 0.0; + m_colorMatrix(3, 2) = 0.0; + m_colorMatrix(3, 3) = 1.0; + + if (m_yuv) { + m_colorMatrix = m_colorMatrix * QMatrix4x4( + 1.0, 0.000, 1.140, -0.5700, + 1.0, -0.394, -0.581, 0.4875, + 1.0, 2.028, 0.000, -1.0140, + 0.0, 0.000, 0.000, 1.0000); + } +} + +void QVideoSurfaceGLPainter::initRgbTextureInfo( + GLenum internalFormat, GLuint format, GLenum type, const QSize &size) +{ + m_yuv = false; + m_textureInternalFormat = internalFormat; + m_textureFormat = format; + m_textureType = type; + m_textureCount = 1; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; +} + +void QVideoSurfaceGLPainter::initYuv420PTextureInfo(const QSize &size) +{ + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = size.width() / 2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = size.width() * size.height(); + m_textureWidths[2] = size.width() / 2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = size.width() * size.height() * 5 / 4; +} + +void QVideoSurfaceGLPainter::initYv12TextureInfo(const QSize &size) +{ + m_yuv = true; + m_textureInternalFormat = GL_LUMINANCE; + m_textureFormat = GL_LUMINANCE; + m_textureType = GL_UNSIGNED_BYTE; + m_textureCount = 3; + m_textureWidths[0] = size.width(); + m_textureHeights[0] = size.height(); + m_textureOffsets[0] = 0; + m_textureWidths[1] = size.width() / 2; + m_textureHeights[1] = size.height() / 2; + m_textureOffsets[1] = size.width() * size.height() * 5 / 4; + m_textureWidths[2] = size.width() / 2; + m_textureHeights[2] = size.height() / 2; + m_textureOffsets[2] = size.width() * size.height(); +} + +#ifndef QT_OPENGL_ES + +# ifndef GL_FRAGMENT_PROGRAM_ARB +# define GL_FRAGMENT_PROGRAM_ARB 0x8804 +# define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +# endif + +// Paints an RGB32 frame +static const char *qt_arbfp_xrgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP xrgb;\n" + "TEX xrgb.xyz, fragment.texcoord[0], texture[0], 2D;\n" + "MOV xrgb.w, matrix[3].w;\n" + "DP4 result.color.x, xrgb.zyxw, matrix[0];\n" + "DP4 result.color.y, xrgb.zyxw, matrix[1];\n" + "DP4 result.color.z, xrgb.zyxw, matrix[2];\n" + "END"; + +// Paints an ARGB frame. +static const char *qt_arbfp_argbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP argb;\n" + "TEX argb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV argb.w, matrix[3].w;\n" + "DP4 result.color.x, argb.zyxw, matrix[0];\n" + "DP4 result.color.y, argb.zyxw, matrix[1];\n" + "DP4 result.color.z, argb.zyxw, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints an RGB(A) frame. +static const char *qt_arbfp_rgbShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP rgb;\n" + "TEX rgb, fragment.texcoord[0], texture[0], 2D;\n" + "MOV rgb.w, matrix[3].w;\n" + "DP4 result.color.x, rgb, matrix[0];\n" + "DP4 result.color.y, rgb, matrix[1];\n" + "DP4 result.color.z, rgb, matrix[2];\n" + "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n" + "END"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_arbfp_yuvPlanarShaderProgram = + "!!ARBfp1.0\n" + "PARAM matrix[4] = { program.local[0..2]," + "{ 0.0, 0.0, 0.0, 1.0 } };\n" + "TEMP yuv;\n" + "TEX yuv.x, fragment.texcoord[0], texture[0], 2D;\n" + "TEX yuv.y, fragment.texcoord[0], texture[1], 2D;\n" + "TEX yuv.z, fragment.texcoord[0], texture[2], 2D;\n" + "MOV yuv.w, matrix[3].w;\n" + "DP4 result.color.x, yuv, matrix[0];\n" + "DP4 result.color.y, yuv, matrix[1];\n" + "DP4 result.color.z, yuv, matrix[2];\n" + "END"; + + +class QVideoSurfaceArbFpPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceArbFpPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint(const QRect &target, QPainter *painter, const QRect &source); + +private: + typedef void (APIENTRY *_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *); + typedef void (APIENTRY *_glBindProgramARB) (GLenum, GLuint); + typedef void (APIENTRY *_glDeleteProgramsARB) (GLsizei, const GLuint *); + typedef void (APIENTRY *_glGenProgramsARB) (GLsizei, GLuint *); + typedef void (APIENTRY *_glProgramLocalParameter4fARB) ( + GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat); + typedef void (APIENTRY *_glActiveTexture) (GLenum); + + _glProgramStringARB glProgramStringARB; + _glBindProgramARB glBindProgramARB; + _glDeleteProgramsARB glDeleteProgramsARB; + _glGenProgramsARB glGenProgramsARB; + _glProgramLocalParameter4fARB glProgramLocalParameter4fARB; + + GLuint m_programId; + QSize m_frameSize; +}; + +QVideoSurfaceArbFpPainter::QVideoSurfaceArbFpPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_programId(0) +{ + glProgramStringARB = (_glProgramStringARB) m_context->getProcAddress( + QLatin1String("glProgramStringARB")); + glBindProgramARB = (_glBindProgramARB) m_context->getProcAddress( + QLatin1String("glBindProgramARB")); + glDeleteProgramsARB = (_glDeleteProgramsARB) m_context->getProcAddress( + QLatin1String("glDeleteProgramsARB")); + glGenProgramsARB = (_glGenProgramsARB) m_context->getProcAddress( + QLatin1String("glGenProgramsARB")); + glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) m_context->getProcAddress( + QLatin1String("glProgramLocalParameter4fARB")); + + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *program = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_xrgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_argbShaderProgram; + break; + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + program = qt_arbfp_argbShaderProgram; + break; + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + program = qt_arbfp_rgbShaderProgram; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + program = qt_arbfp_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + program = qt_arbfp_rgbShaderProgram; + break; + default: + break; + } + } + + if (!program) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else { + glGenProgramsARB(1, &m_programId); + + GLenum glError = glGetError(); + if (glError != GL_NO_ERROR) { + qWarning("QPainterVideoSurface: ARBfb Shader allocation error %x", int(glError)); + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + glProgramStringARB( + GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + qstrlen(program), + reinterpret_cast(program)); + + if ((glError = glGetError()) != GL_NO_ERROR) { + const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB); + + qWarning("QPainterVideoSurface: ARBfp Shader compile error %x, %s", + int(glError), + reinterpret_cast(errorString)); + glDeleteProgramsARB(1, &m_programId); + + m_textureCount = 0; + m_programId = 0; + + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + } + } + + return error; +} + +void QVideoSurfaceArbFpPainter::stop() +{ + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + glDeleteProgramsARB(1, &m_programId); + + m_textureCount = 0; + m_programId = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::paint( + const QRect &target, QPainter *painter, const QRect &source) +{ + if (m_frame.isValid()) { + painter->beginNativePainting(); + + const float txLeft = float(source.left()) / float(m_frameSize.width()); + const float txRight = float(source.right()) / float(m_frameSize.width()); + const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.top()) / float(m_frameSize.height()) + : float(source.bottom()) / float(m_frameSize.height()); + const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.bottom()) / float(m_frameSize.height()) + : float(source.top()) / float(m_frameSize.height()); + + + const float tx_array[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + const float v_array[] = + { + target.left() , target.bottom() + 1, + target.right() + 1, target.bottom() + 1, + target.left() , target.top(), + target.right() + 1, target.top() + }; + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId); + + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 0, + m_colorMatrix(0, 0), + m_colorMatrix(0, 1), + m_colorMatrix(0, 2), + m_colorMatrix(0, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 1, + m_colorMatrix(1, 0), + m_colorMatrix(1, 1), + m_colorMatrix(1, 2), + m_colorMatrix(1, 3)); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + 2, + m_colorMatrix(2, 0), + m_colorMatrix(2, 1), + m_colorMatrix(2, 2), + m_colorMatrix(2, 3)); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + } + + glVertexPointer(2, GL_FLOAT, 0, v_array); + glTexCoordPointer(2, GL_FLOAT, 0, tx_array); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + + painter->endNativePainting(); + } + return QAbstractVideoSurface::NoError; +} + +#endif + +static const char *qt_glsl_vertexShaderProgram = + "attribute highp vec4 vertexCoordArray;\n" + "attribute highp vec2 textureCoordArray;\n" + "uniform highp mat4 positionMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = positionMatrix * vertexCoordArray;\n" + " textureCoord = textureCoordArray;\n" + "}\n"; + +// Paints an RGB32 frame +static const char *qt_glsl_xrgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + +// Paints an ARGB frame. +static const char *qt_glsl_argbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints an RGB(A) frame. +static const char *qt_glsl_rgbShaderProgram = + "uniform sampler2D texRgb;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).rgb, 1.0);\n" + " color = colorMatrix * color;\n" + " gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n" + "}\n"; + +// Paints a YUV420P or YV12 frame. +static const char *qt_glsl_yuvPlanarShaderProgram = + "uniform sampler2D texY;\n" + "uniform sampler2D texU;\n" + "uniform sampler2D texV;\n" + "uniform mediump mat4 colorMatrix;\n" + "varying highp vec2 textureCoord;\n" + "void main(void)\n" + "{\n" + " highp vec4 color = vec4(\n" + " texture2D(texY, textureCoord.st).r,\n" + " texture2D(texU, textureCoord.st).r,\n" + " texture2D(texV, textureCoord.st).r,\n" + " 1.0);\n" + " gl_FragColor = colorMatrix * color;\n" + "}\n"; + + +class QVideoSurfaceGlslPainter : public QVideoSurfaceGLPainter +{ +public: + QVideoSurfaceGlslPainter(QGLContext *context); + + QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); + void stop(); + + QAbstractVideoSurface::Error paint(const QRect &target, QPainter *painter, const QRect &source); + +private: + QGLShaderProgram m_program; + QSize m_frameSize; +}; + +QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context) + : QVideoSurfaceGLPainter(context) + , m_program(context) +{ + m_imagePixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32 +#ifndef QT_OPENGL_ES + << QVideoFrame::Format_RGB24 +#endif + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_YUV420P; + m_glPixelFormats + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurfaceFormat &format) +{ + Q_ASSERT(m_textureCount == 0); + + QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError; + + m_context->makeCurrent(); + + const char *fragmentProgram = 0; + + if (format.handleType() == QAbstractVideoBuffer::NoHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_xrgbShaderProgram; + break; + case QVideoFrame::Format_ARGB32: + initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_argbShaderProgram; + break; +#ifndef QT_OPENGL_ES + case QVideoFrame::Format_RGB24: + initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; +#endif + case QVideoFrame::Format_RGB565: + initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize()); + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + case QVideoFrame::Format_YV12: + initYv12TextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + case QVideoFrame::Format_YUV420P: + initYuv420PTextureInfo(format.frameSize()); + fragmentProgram = qt_glsl_yuvPlanarShaderProgram; + break; + default: + break; + } + } else if (format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB32: + case QVideoFrame::Format_ARGB32: + m_yuv = false; + m_textureCount = 1; + fragmentProgram = qt_glsl_rgbShaderProgram; + break; + default: + break; + } + } + + if (!fragmentProgram) { + error = QAbstractVideoSurface::UnsupportedFormatError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_vertexShaderProgram)) { + qWarning("QPainterVideoSurface: Vertex shader compile error %s", + qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + } else if (!m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentProgram)) { + qWarning("QPainterVideoSurface: Shader compile error %s", qPrintable(m_program.log())); + error = QAbstractVideoSurface::ResourceError; + m_program.removeAllShaders(); + } else if(!m_program.link()) { + qWarning("QPainterVideoSurface: Shader link error %s", qPrintable(m_program.log())); + m_program.removeAllShaders(); + error = QAbstractVideoSurface::ResourceError; + } else { + m_handleType = format.handleType(); + m_scanLineDirection = format.scanLineDirection(); + m_frameSize = format.frameSize(); + + if (m_handleType == QAbstractVideoBuffer::NoHandle) + glGenTextures(m_textureCount, m_textureIds); + } + + return error; +} + +void QVideoSurfaceGlslPainter::stop() +{ + m_context->makeCurrent(); + + if (m_handleType != QAbstractVideoBuffer::GLTextureHandle) + glDeleteTextures(m_textureCount, m_textureIds); + m_program.removeAllShaders(); + + m_textureCount = 0; + m_handleType = QAbstractVideoBuffer::NoHandle; +} + +QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( + const QRect &target, QPainter *painter, const QRect &source) +{ + if (m_frame.isValid()) { + painter->beginNativePainting(); + + const int width = QGLContext::currentContext()->device()->width(); + const int height = QGLContext::currentContext()->device()->height(); + + const QTransform transform = painter->deviceTransform(); + + const GLfloat wfactor = 2.0 / width; + const GLfloat hfactor = -2.0 / height; + + const GLfloat positionMatrix[4][4] = + { + { + /*(0,0)*/ wfactor * transform.m11() - transform.m13(), + /*(0,1)*/ hfactor * transform.m12() + transform.m13(), + /*(0,2)*/ 0.0, + /*(0,3)*/ transform.m13() + }, { + /*(1,0)*/ wfactor * transform.m21() - transform.m23(), + /*(1,1)*/ hfactor * transform.m22() + transform.m23(), + /*(1,2)*/ 0.0, + /*(1,3)*/ transform.m23() + }, { + /*(2,0)*/ 0.0, + /*(2,1)*/ 0.0, + /*(2,2)*/ -1.0, + /*(2,3)*/ 0.0 + }, { + /*(3,0)*/ wfactor * transform.dx() - transform.m33(), + /*(3,1)*/ hfactor * transform.dy() + transform.m33(), + /*(3,2)*/ 0.0, + /*(3,3)*/ transform.m33() + } + }; + + const GLfloat vertexCoordArray[] = + { + target.left() , target.bottom() + 1, + target.right() + 1, target.bottom() + 1, + target.left() , target.top(), + target.right() + 1, target.top() + }; + + const GLfloat txLeft = float(source.left()) / float(m_frameSize.width()); + const GLfloat txRight = float(source.right()) / float(m_frameSize.width()); + const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.top()) / float(m_frameSize.height()) + : float(source.bottom()) / float(m_frameSize.height()); + const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom + ? float(source.bottom()) / float(m_frameSize.height()) + : float(source.top()) / float(m_frameSize.height()); + + const GLfloat textureCoordArray[] = + { + txLeft , txBottom, + txRight, txBottom, + txLeft , txTop, + txRight, txTop + }; + + m_program.bind(); + + m_program.enableAttributeArray("vertexCoordArray"); + m_program.enableAttributeArray("textureCoordArray"); + m_program.setAttributeArray("vertexCoordArray", vertexCoordArray, 2); + m_program.setAttributeArray("textureCoordArray", textureCoordArray, 2); + m_program.setUniformValue("positionMatrix", positionMatrix); + + if (m_textureCount == 3) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_textureIds[1]); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_textureIds[2]); + glActiveTexture(GL_TEXTURE0); + + m_program.setUniformValue("texY", 0); + m_program.setUniformValue("texU", 1); + m_program.setUniformValue("texV", 2); + } else { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureIds[0]); + + m_program.setUniformValue("texRgb", 0); + } + m_program.setUniformValue("colorMatrix", m_colorMatrix); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_program.release(); + + painter->endNativePainting(); + } + return QAbstractVideoSurface::NoError; +} + +#endif + +/*! + \class QPainterVideoSurface + \internal +*/ + +/*! +*/ +QPainterVideoSurface::QPainterVideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_painter(0) +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + , m_glContext(0) + , m_shaderTypes(NoShaders) + , m_shaderType(NoShaders) +#endif + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_pixelFormat(QVideoFrame::Format_Invalid) + , m_colorsDirty(true) + , m_ready(false) +{ +} + +/*! +*/ +QPainterVideoSurface::~QPainterVideoSurface() +{ + if (isActive()) + m_painter->stop(); + + delete m_painter; +} + +/*! +*/ +QList QPainterVideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (!m_painter) + const_cast(this)->createPainter(); + + return m_painter->supportedPixelFormats(handleType); +} + +/*! +*/ +bool QPainterVideoSurface::isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar) const +{ + if (!m_painter) + const_cast(this)->createPainter(); + + return m_painter->isFormatSupported(format, similar); +} + +/*! +*/ +bool QPainterVideoSurface::start(const QVideoSurfaceFormat &format) +{ + if (isActive()) + m_painter->stop(); + + if (!m_painter) + createPainter(); + + if (format.frameSize().isEmpty()) { + setError(UnsupportedFormatError); + } else { + QAbstractVideoSurface::Error error = m_painter->start(format); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + } else { + m_pixelFormat = format.pixelFormat(); + m_frameSize = format.frameSize(); + m_sourceRect = format.viewport(); + m_colorsDirty = true; + m_ready = true; + + return QAbstractVideoSurface::start(format); + } + } + + QAbstractVideoSurface::stop(); + + return false; +} + +/*! +*/ +void QPainterVideoSurface::stop() +{ + if (isActive()) { + m_painter->stop(); + m_ready = false; + + QAbstractVideoSurface::stop(); + } +} + +/*! +*/ +bool QPainterVideoSurface::present(const QVideoFrame &frame) +{ + if (!m_ready) { + if (!isActive()) + setError(StoppedError); + } else if (frame.isValid() + && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { + setError(IncorrectFormatError); + + stop(); + } else { + QAbstractVideoSurface::Error error = m_painter->setCurrentFrame(frame); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } else { + m_ready = false; + + emit frameChanged(); + + return true; + } + } + return false; +} + +/*! +*/ +int QPainterVideoSurface::brightness() const +{ + return m_brightness; +} + +/*! +*/ +void QPainterVideoSurface::setBrightness(int brightness) +{ + m_brightness = brightness; + + m_colorsDirty = true; +} + +/*! +*/ +int QPainterVideoSurface::contrast() const +{ + return m_contrast; +} + +/*! +*/ +void QPainterVideoSurface::setContrast(int contrast) +{ + m_contrast = contrast; + + m_colorsDirty = true; +} + +/*! +*/ +int QPainterVideoSurface::hue() const +{ + return m_hue; +} + +/*! +*/ +void QPainterVideoSurface::setHue(int hue) +{ + m_hue = hue; + + m_colorsDirty = true; +} + +/*! +*/ +int QPainterVideoSurface::saturation() const +{ + return m_saturation; +} + +/*! +*/ +void QPainterVideoSurface::setSaturation(int saturation) +{ + m_saturation = saturation; + + m_colorsDirty = true; +} + +/*! +*/ +bool QPainterVideoSurface::isReady() const +{ + return m_ready; +} + +/*! +*/ +void QPainterVideoSurface::setReady(bool ready) +{ + m_ready = ready; +} + +/*! +*/ +void QPainterVideoSurface::paint(QPainter *painter, const QRect &rect) +{ + if (!isActive()) { + painter->fillRect(rect, QBrush(Qt::black)); + } else { + if (m_colorsDirty) { + m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); + m_colorsDirty = false; + } + + QAbstractVideoSurface::Error error = m_painter->paint(rect, painter, m_sourceRect); + + if (error != QAbstractVideoSurface::NoError) { + setError(error); + + stop(); + } + } +} + +/*! + \fn QPainterVideoSurface::frameChanged() +*/ + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + +/*! +*/ +const QGLContext *QPainterVideoSurface::glContext() const +{ + return m_glContext; +} + +/*! +*/ +void QPainterVideoSurface::setGLContext(QGLContext *context) +{ + if (m_glContext == context) + return; + + m_glContext = context; + + m_shaderTypes = NoShaders; + + if (m_glContext) { + m_glContext->makeCurrent(); + + const QByteArray extensions(reinterpret_cast(glGetString(GL_EXTENSIONS))); +#ifndef QT_OPENGL_ES + + if (extensions.contains("ARB_fragment_program")) + m_shaderTypes |= FragmentProgramShader; +#endif + + if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext) + && extensions.contains("ARB_shader_objects")) + m_shaderTypes |= GlslShader; + } + + ShaderType type = (m_shaderType & m_shaderTypes) + ? m_shaderType + : NoShaders; + + if (type != m_shaderType || type != NoShaders) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } + emit supportedFormatsChanged(); + } +} + +/*! + \enum QPainterVideoSurface::ShaderType + + \value NoShaders + \value FragmentProgramShader + \value HlslShader +*/ + +/*! + \typedef QPainterVideoSurface::ShaderTypes +*/ + +/*! +*/ +QPainterVideoSurface::ShaderTypes QPainterVideoSurface::supportedShaderTypes() const +{ + return m_shaderTypes; +} + +/*! +*/ +QPainterVideoSurface::ShaderType QPainterVideoSurface::shaderType() const +{ + return m_shaderType; +} + +/*! +*/ +void QPainterVideoSurface::setShaderType(ShaderType type) +{ + if (!(type & m_shaderTypes)) + type = NoShaders; + + if (type != m_shaderType) { + m_shaderType = type; + + if (isActive()) { + m_painter->stop(); + delete m_painter; + m_painter = 0; + m_ready = false; + + setError(ResourceError); + QAbstractVideoSurface::stop(); + } else { + delete m_painter; + m_painter = 0; + } + emit supportedFormatsChanged(); + } +} + +#endif + +void QPainterVideoSurface::createPainter() +{ + Q_ASSERT(!m_painter); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + switch (m_shaderType) { +#ifndef QT_OPENGL_ES + case FragmentProgramShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceArbFpPainter(m_glContext); + break; +#endif + case GlslShader: + Q_ASSERT(m_glContext); + m_glContext->makeCurrent(); + m_painter = new QVideoSurfaceGlslPainter(m_glContext); + break; + default: + m_painter = new QVideoSurfaceRasterPainter; + break; + } +#else + m_painter = new QVideoSurfaceRasterPainter; +#endif +} + +QT_END_NAMESPACE + +#include "moc_qpaintervideosurface_p.cpp" + + diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h new file mode 100644 index 0000000..2a146d0 --- /dev/null +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QPAINTERVIDEOSURFACE_P_H +#define QPAINTERVIDEOSURFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVideoSurfacePainter; +class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + explicit QPainterVideoSurface(QObject *parent = 0); + ~QPainterVideoSurface(); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool isFormatSupported( + const QVideoSurfaceFormat &format, QVideoSurfaceFormat *similar = 0) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + bool isReady() const; + void setReady(bool ready); + + void paint(QPainter *painter, const QRect &rect); + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + const QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + enum ShaderType + { + NoShaders = 0x00, + FragmentProgramShader = 0x01, + GlslShader = 0x02 + }; + + Q_DECLARE_FLAGS(ShaderTypes, ShaderType) + + ShaderTypes supportedShaderTypes() const; + + ShaderType shaderType() const; + void setShaderType(ShaderType type); +#endif + +Q_SIGNALS: + void frameChanged(); + +private: + void createPainter(); + + QVideoSurfacePainter *m_painter; +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + QGLContext *m_glContext; + ShaderTypes m_shaderTypes; + ShaderType m_shaderType; +#endif + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + + QVideoFrame::PixelFormat m_pixelFormat; + QSize m_frameSize; + QRect m_sourceRect; + bool m_colorsDirty; + bool m_ready; +}; + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +Q_DECLARE_OPERATORS_FOR_FLAGS(QPainterVideoSurface::ShaderTypes) +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qtmedianamespace.h b/src/multimedia/base/qtmedianamespace.h new file mode 100644 index 0000000..c3b4896 --- /dev/null +++ b/src/multimedia/base/qtmedianamespace.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QTMEDIANAMESPACE_H +#define QTMEDIANAMESPACE_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +namespace QtMedia +{ + enum MetaData + { + // Common + Title, + SubTitle, + Author, + Comment, + Description, + Category, + Genre, + Year, + Date, + UserRating, + Keywords, + Language, + Publisher, + Copyright, + ParentalRating, + RatingOrganisation, + + // Media + Size, + MediaType, + Duration, + + // Audio + AudioBitRate, + AudioCodec, + AverageLevel, + ChannelCount, + PeakValue, + SampleRate, + + // Music + AlbumTitle, + AlbumArtist, + ContributingArtist, + Composer, + Conductor, + Lyrics, + Mood, + TrackNumber, + TrackCount, + + CoverArtUrlSmall, + CoverArtUrlLarge, + + // Image/Video + Resolution, + PixelAspectRatio, + + // Video + VideoFrameRate, + VideoBitRate, + VideoCodec, + + PosterUrl, + + // Movie + ChapterNumber, + Director, + LeadPerformer, + Writer, + + // Photos + CameraManufacturer, + CameraModel, + Event, + Subject, + Orientation, + ExposureTime, + FNumber, + ExposureProgram, + ISOSpeedRatings, + ExposureBiasValue, + DateTimeOriginal, + DateTimeDigitized, + SubjectDistance, + MeteringMode, + LightSource, + Flash, + FocalLength, + ExposureMode, + WhiteBalance, + DigitalZoomRatio, + FocalLengthIn35mmFilm, + SceneCaptureType, + GainControl, + Contrast, + Saturation, + Sharpness, + DeviceSettingDescription + }; + + enum SupportEstimate + { + NotSupported, + MaybeSupported, + ProbablySupported, + PreferedService + }; + + enum EncodingQuality + { + VeryLowQuality, + LowQuality, + NormalQuality, + HighQuality, + VeryHighQuality + }; + + enum EncodingMode + { + ConstantQualityEncoding, + ConstantBitRateEncoding, + AverageBitRateEncoding, + TwoPassEncoding + }; + + enum AvailabilityError + { + NoError, + ServiceMissingError, + BusyError, + ResourceError + }; + +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qtmedianamespace.qdoc b/src/multimedia/base/qtmedianamespace.qdoc new file mode 100644 index 0000000..0fb39f5 --- /dev/null +++ b/src/multimedia/base/qtmedianamespace.qdoc @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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$ +** +****************************************************************************/ + +/*! + \namespace QtMedia + \ingroup multimedia + + \brief The QtMedia namespace contains miscellaneous identifiers used throughout the Qt Media + library. +*/ + +/*! + \enum QtMedia::MetaData + + This enum provides identifiers for meta-data attributes. + + Common attributes + \value Title The title of the media. QString. + \value SubTitle The sub-title of the media. QString. + \value Author The authors of the media. QStringList. + \value Comment A user comment about the media. QString. + \value Description A description of the media. QString + \value Category The category of the media. QStringList. + \value Genre The genre of the media. QStringList. + \value Year The year of release of the media. int. + \value Date The date of the media. QDate. + \value UserRating A user rating of the media. int [0..100]. + \value Keywords A list of keywords describing the media. QStringList. + \value Language The language of media, as an ISO 639-2 code. + + \value Publisher The publisher of the media. QString. + \value Copyright The media's copyright notice. QString. + \value ParentalRating The parental rating of the media. QString. + \value RatingOrganisation The organisation responsible for the parental rating of the media. + QString. + + Media attributes + \value Size The size in bytes of the media. qint64 + \value MediaType The type of the media (audio, video, etc). QString. + \value Duration The duration in millseconds of the media. qint64. + + Audio attributes + \value AudioBitRate The bit rate of the media's audio stream in bits per second. int. + \value AudioCodec The codec of the media's audio stream. QString. + \value AverageLevel The average volume level of the media. int. + \value ChannelCount The number of channels in the media's audio stream. int. + \value PeakValue The peak volume of the media's audio stream. int + \value SampleRate The sample rate of the media's audio stream in hertz. int + + Music attributes + \value AlbumTitle The title of the album the media belongs to. QString. + \value AlbumArtist The principal artist of the album the media belongs to. QString. + \value ContributingArtist The artists contributing to the media. QStringList. + \value Composer The composer of the media. QStringList. + \value Conductor The conductor of the media. QString. + \value Lyrics The lyrics to the media. QString. + \value Mood The mood of the media. QString. + \value TrackNumber The track number of the media. int. + \value TrackCount The number of tracks on the album containing the media. int. + + \value CoverArtUrlSmall The URL of a small cover art image. QUrl. + \value CoverArtUrlLarge The URL of a large cover art image. QUrl. + + Image and video attributes + \value Resolution The dimensions of an image or video. QSize. + \value PixelAspectRatio The pixel aspect ratio of an image or video. QSize. + + Video attributes + \value VideoFrameRate The frame rate of the media's video stream. qreal. + \value VideoBitRate The bit rate of the media's video stream in bits per second. int. + \value VideoCodec The codec of the media's video stream. QString. + + \value PosterUrl The URL of a poster image. QUrl. + + Movie attributes + \value ChapterNumber The chapter number of the media. int. + \value Director The director of the media. QString. + \value LeadPerformer The lead performer in the media. QStringList. + \value Writer The writer of the media. QStringList. + + Photo attributes. + \value CameraManufacturer The manufacturer of the camera used to capture the media. QString. + \value CameraModel The model of the camera used to capture the media. QString. + \value Event The event during which the media was captured. QString. + \value Subject The subject of the media. QString. + \value Orientation Orientation of image. + \value ExposureTime Exposure time, given in seconds. + \value FNumber The F Number. + \value ExposureProgram + The class of the program used by the camera to set exposure when the picture is taken. + \value ISOSpeedRatings + Indicates the ISO Speed and ISO Latitude of the camera or input device as specified in ISO 12232. + \value ExposureBiasValue + The exposure bias. + The unit is the APEX (Additive System of Photographic Exposure) setting. + \value DateTimeOriginal The date and time when the original image data was generated. + \value DateTimeDigitized The date and time when the image was stored as digital data. + \value SubjectDistance The distance to the subject, given in meters. + \value MeteringMode The metering mode. + \value LightSource + The kind of light source. + \value Flash + Status of flash when the image was shot. + \value FocalLength + The actual focal length of the lens, in mm. + \value ExposureMode + Indicates the exposure mode set when the image was shot. + \value WhiteBalance + Indicates the white balance mode set when the image was shot. + \value DigitalZoomRatio + Indicates the digital zoom ratio when the image was shot. + \value FocalLengthIn35mmFilm + Indicates the equivalent focal length assuming a 35mm film camera, in mm. + \value SceneCaptureType + Indicates the type of scene that was shot. + It can also be used to record the mode in which the image was shot. + \value GainControl + Indicates the degree of overall image gain adjustment. + \value Contrast + Indicates the direction of contrast processing applied by the camera when the image was shot. + \value Saturation + Indicates the direction of saturation processing applied by the camera when the image was shot. + \value Sharpness + Indicates the direction of sharpness processing applied by the camera when the image was shot. + \value DeviceSettingDescription + Exif tag, indicates information on the picture-taking conditions of a particular camera model. QString +*/ + +/*! + \enum QtMedia::SupportEstimate + + Enumerates the levels of support a media service provider may have for a feature. + + \value NotSupported The feature is not supported. + \value MaybeSupported The feature may be supported. + \value ProbablySupported The feature is probably supported. + \value PreferedService The service is the preferred provider of a service. +*/ + +/*! + \enum QtMedia::EncodingQuality + + Enumerates quality encoding levels. + + \value VeryLowQuality + \value LowQuality + \value NormalQuality + \value HighQuality + \value VeryHighQuality +*/ + +/*! + \enum QtMedia::EncodingMode + + Enumerates encoding modes. + + \value ConstantQualityEncoding + \value ConstantBitRateEncoding + \value AverageBitRateEncoding + \value TwoPassEncoding +*/ + +/*! + \enum QtMedia::AvailabilityError + + Enumerates Service status errors. + + \value NoError + \value ServiceMissingError + \value ResourceError + \value BusyError +*/ diff --git a/src/multimedia/base/qvideodevicecontrol.cpp b/src/multimedia/base/qvideodevicecontrol.cpp new file mode 100644 index 0000000..21db500 --- /dev/null +++ b/src/multimedia/base/qvideodevicecontrol.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoDeviceControl + \preliminary + \brief The QVideoDeviceControl class provides an video device selector media control. + \ingroup multimedia-serv + + The QVideoDeviceControl class provides descriptions of the video devices + available on a system and allows one to be selected as the endpoint of + a media service. + + The interface name of QVideoDeviceControl is \c com.nokia.Qt.VideoDeviceControl as + defined in QVideoDeviceControl_iid. +*/ + +/*! + \macro QVideoDeviceControl_iid + + \c com.nokia.Qt.VideoDeviceControl + + Defines the interface name of the QVideoDeviceControl class. + + \relates QVideoDeviceControl +*/ + +/*! + Constructs a video device control with the given \a parent. +*/ +QVideoDeviceControl::QVideoDeviceControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video device control. +*/ +QVideoDeviceControl::~QVideoDeviceControl() +{ +} + +/*! + \fn QVideoDeviceControl::deviceCount() const + + Returns the number of available video devices; +*/ + +/*! + \fn QVideoDeviceControl::deviceName(int index) const + + Returns the name of the video device at \a index. +*/ + +/*! + \fn QVideoDeviceControl::deviceDescription(int index) const + + Returns a description of the video device at \a index. +*/ + +/*! + \fn QVideoDeviceControl::deviceIcon(int index) const + + Returns an icon for the video device at \a index. +*/ + +/*! + \fn QVideoDeviceControl::defaultDevice() const + + Returns the index of the default video device. +*/ + +/*! + \fn QVideoDeviceControl::selectedDevice() const + + Returns the index of the selected video device. +*/ + +/*! + \fn QVideoDeviceControl::setSelectedDevice(int index) + + Sets the selected video device \a index. +*/ + +/*! + \fn QVideoDeviceControl::devicesChanged() + + Signals that the list of available video devices has changed. +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(int index) + + Signals that the selected video device \a index has changed. +*/ + +/*! + \fn QVideoDeviceControl::selectedDeviceChanged(const QString &name) + + Signals that the selected video device \a name has changed. +*/ + +QT_END_NAMESPACE + +QT_END_HEADER + +#include "moc_qvideodevicecontrol.cpp" + + diff --git a/src/multimedia/base/qvideodevicecontrol.h b/src/multimedia/base/qvideodevicecontrol.h new file mode 100644 index 0000000..ce99fd1 --- /dev/null +++ b/src/multimedia/base/qvideodevicecontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEODEVICECONTROL_H +#define QVIDEODEVICECONTROL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class Q_MULTIMEDIA_EXPORT QVideoDeviceControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoDeviceControl(); + + virtual int deviceCount() const = 0; + + virtual QString deviceName(int index) const = 0; + virtual QString deviceDescription(int index) const = 0; + virtual QIcon deviceIcon(int index) const = 0; + + virtual int defaultDevice() const = 0; + virtual int selectedDevice() const = 0; + +public Q_SLOTS: + virtual void setSelectedDevice(int index) = 0; + +Q_SIGNALS: + void selectedDeviceChanged(int index); + void selectedDeviceChanged(const QString &deviceName); + void devicesChanged(); + +protected: + QVideoDeviceControl(QObject *parent = 0); +}; + +#define QVideoDeviceControl_iid "com.nokia.Qt.QVideoDeviceControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoDeviceControl, QVideoDeviceControl_iid) + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QVIDEODEVICECONTROL_H diff --git a/src/multimedia/base/qvideooutputcontrol.cpp b/src/multimedia/base/qvideooutputcontrol.cpp new file mode 100644 index 0000000..a904385 --- /dev/null +++ b/src/multimedia/base/qvideooutputcontrol.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoOutputControl + \preliminary + + \brief The QVideoOutputControl class provides a means of selecting the + active video output control. + + \ingroup multimedia-serv + + There are multiple controls which a QMediaService may use to output + video ony one of which may be active at one time, QVideoOutputControl + is the means by which this active control is selected. + + The possible output controls are QVideoRendererControl, + QVideoWindowControl, and QVideoWidgetControl. + + The interface name of QVideoOutputControl is \c com.nokia.Qt.QVideoOutputControl/1.0 as + defined in QVideoOutputControl_iid. + + \sa QMediaService::control(), QVideoWidget, QVideoRendererControl, + QVideoWindowControl, QVideoWidgetControl +*/ + +/*! + \macro QVideoOutputControl_iid + + \c com.nokia.Qt.QVideoOutputControl/1.0 + + Defines the interface name of the QVideoOutputControl class. + + \relates QVideoOutputControl +*/ + +/*! + \enum QVideoOutputControl::Output + + Identifies the possible render targets of a video output. + + \value NoOutput Video is not rendered. + \value WindowOutput Video is rendered to the target of a QVideoWindowControl. + \value RendererOutput Video is rendered to the target of a QVideoRendererControl. + \value WidgetOutput Video is rendered to a QWidget provided by QVideoWidgetControl. + \value UserOutput Start value for user defined video targets. + \value MaxUserOutput End value for user defined video targets. +*/ + +/*! + Constructs a new video output control with the given \a parent. +*/ +QVideoOutputControl::QVideoOutputControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video output control. +*/ +QVideoOutputControl::~QVideoOutputControl() +{ +} + +/*! + \fn QList QVideoOutputControl::availableOutputs() const + + Returns a list of available video output targets. +*/ + +/*! + \fn QVideoOutputControl::output() const + + Returns the current video output target. +*/ + +/*! + \fn QVideoOutputControl::setOutput(Output output) + + Sets the current video \a output target. +*/ + +/*! + \fn QVideoOutputControl::availableOutputsChanged(const QList &outputs) + + Signals that available set of video \a outputs has changed. +*/ + +#include "moc_qvideooutputcontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideooutputcontrol.h b/src/multimedia/base/qvideooutputcontrol.h new file mode 100644 index 0000000..805da58 --- /dev/null +++ b/src/multimedia/base/qvideooutputcontrol.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEOOUTPUTCONTROL_H +#define QVIDEOOUTPUTCONTROL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QVideoOutputControl : public QMediaControl +{ + Q_OBJECT + +public: + enum Output + { + NoOutput, + WindowOutput, + RendererOutput, + WidgetOutput, + UserOutput = 100, + MaxUserOutput = 1000 + }; + + ~QVideoOutputControl(); + + virtual QList availableOutputs() const = 0; + + virtual Output output() const = 0; + virtual void setOutput(Output output) = 0; + +Q_SIGNALS: + void availableOutputsChanged(const QList &outputs); + +protected: + QVideoOutputControl(QObject *parent = 0); +}; + +#define QVideoOutputControl_iid "com.nokia.Qt.QVideoOutputControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoOutputControl, QVideoOutputControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideorenderercontrol.cpp b/src/multimedia/base/qvideorenderercontrol.cpp new file mode 100644 index 0000000..4e7b3da --- /dev/null +++ b/src/multimedia/base/qvideorenderercontrol.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoRendererControl + \preliminary + + \brief The QVideoRendererControl class provides a control for rendering + to a video surface. + + \ingroup multimedia-serv + + Using the surface() property of QVideoRendererControl a QAbstractVideoSurface + may be set as the video render target of a QMediaService. + + \code + QVideoRendererControl *rendererControl = mediaService->control(); + rendererControl->setSurface(myVideoSurface); + \endcode + + QVideoRendererControl is one of number of possible video output controls, + in order to receive video it must be made the active video output + control by setting the output property of QVideoOutputControl to + \l {QVideoOutputControl::RendererOutput}{RendererOutput}. Consequently any + QMediaService that implements QVideoRendererControl must also implement + QVideoOutputControl. + + \code + QVideoOutputControl *outputControl = mediaService->control(); + outputControl->setOutput(QVideoOutputControl::RendererOutput); + \endcode + + The interface name of QVideoRendererControl is \c com.nokia.Qt.QVideoRendererControl/1.0 as + defined in QVideoRendererControl_iid. + + \sa QMediaService::control(), QVideoOutputControl, QVideoWidget +*/ + +/*! + \macro QVideoRendererControl_iid + + \c com.nokia.Qt.QVideoRendererControl/1.0 + + Defines the interface name of the QVideoRendererControl class. + + \relates QVideoRendererControl +*/ + +/*! + Constructs a new video renderer media end point with the given \a parent. +*/ +QVideoRendererControl::QVideoRendererControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video renderer media end point. +*/ +QVideoRendererControl::~QVideoRendererControl() +{ +} + +/*! + \fn QVideoRendererControl::surface() const + + Returns the surface a video producer renders to. +*/ + +/*! + \fn QVideoRendererControl::setSurface(QAbstractVideoSurface *surface) + + Sets the \a surface a video producer renders to. +*/ + +#include "moc_qvideorenderercontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideorenderercontrol.h b/src/multimedia/base/qvideorenderercontrol.h new file mode 100644 index 0000000..f5ba83e --- /dev/null +++ b/src/multimedia/base/qvideorenderercontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEORENDERERCONTROL_H +#define QVIDEORENDERERCONTROL_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QAbstractVideoSurface; + +class Q_MULTIMEDIA_EXPORT QVideoRendererControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoRendererControl(); + + virtual QAbstractVideoSurface *surface() const = 0; + virtual void setSurface(QAbstractVideoSurface *surface) = 0; + +protected: + QVideoRendererControl(QObject *parent = 0); +}; + +#define QVideoRendererControl_iid "com.nokia.Qt.QVideoRendererControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoRendererControl, QVideoRendererControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QVIDEORENDERERCONTROL_H diff --git a/src/multimedia/base/qvideowidget.cpp b/src/multimedia/base/qvideowidget.cpp new file mode 100644 index 0000000..31cfd8d --- /dev/null +++ b/src/multimedia/base/qvideowidget.cpp @@ -0,0 +1,916 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qvideowidget_p.h" + +#include +#include +#include +#include +#include + +#include "qpaintervideosurface_p.h" +#include +#include +#include + +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +QVideoWidgetControlBackend::QVideoWidgetControlBackend( + QVideoWidgetControl *control, QWidget *widget) + : m_widgetControl(control) +{ + connect(control, SIGNAL(brightnessChanged(int)), widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), widget, SLOT(_q_fullScreenChanged(bool))); + + QBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(control->videoWidget()); + + widget->setLayout(layout); +} + +void QVideoWidgetControlBackend::setBrightness(int brightness) +{ + m_widgetControl->setBrightness(brightness); +} + +void QVideoWidgetControlBackend::setContrast(int contrast) +{ + m_widgetControl->setContrast(contrast); +} + +void QVideoWidgetControlBackend::setHue(int hue) +{ + m_widgetControl->setHue(hue); +} + +void QVideoWidgetControlBackend::setSaturation(int saturation) +{ + m_widgetControl->setSaturation(saturation); +} + +void QVideoWidgetControlBackend::setFullScreen(bool fullScreen) +{ + m_widgetControl->setFullScreen(fullScreen); +} + + +QVideoWidget::AspectRatioMode QVideoWidgetControlBackend::aspectRatioMode() const +{ + return m_widgetControl->aspectRatioMode(); +} + +void QVideoWidgetControlBackend::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_widgetControl->setAspectRatioMode(mode); +} + +QRendererVideoWidgetBackend::QRendererVideoWidgetBackend( + QVideoRendererControl *control, QWidget *widget) + : m_rendererControl(control) + , m_widget(widget) + , m_surface(new QPainterVideoSurface) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_updatePaintDevice(true) +{ + connect(this, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(this, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(this, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(this, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(m_surface, SIGNAL(frameChanged()), m_widget, SLOT(update())); + connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + m_widget, SLOT(_q_dimensionsChanged())); + + m_rendererControl->setSurface(m_surface); +} + +QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() +{ + delete m_surface; +} + +void QRendererVideoWidgetBackend::clearSurface() +{ + m_rendererControl->setSurface(0); +} + +void QRendererVideoWidgetBackend::setBrightness(int brightness) +{ + m_surface->setBrightness(brightness); + + emit brightnessChanged(brightness); +} + +void QRendererVideoWidgetBackend::setContrast(int contrast) +{ + m_surface->setContrast(contrast); + + emit contrastChanged(contrast); +} + +void QRendererVideoWidgetBackend::setHue(int hue) +{ + m_surface->setHue(hue); + + emit hueChanged(hue); +} + +void QRendererVideoWidgetBackend::setSaturation(int saturation) +{ + m_surface->setSaturation(saturation); + + emit saturationChanged(saturation); +} + +QVideoWidget::AspectRatioMode QRendererVideoWidgetBackend::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QRendererVideoWidgetBackend::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + m_widget->updateGeometry(); +} + +void QRendererVideoWidgetBackend::setFullScreen(bool) +{ +} + +QSize QRendererVideoWidgetBackend::sizeHint() const +{ + return m_surface->surfaceFormat().sizeHint(); +} + +void QRendererVideoWidgetBackend::showEvent() +{ +} + +void QRendererVideoWidgetBackend::hideEvent(QHideEvent *) +{ +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + m_updatePaintDevice = true; + m_surface->setGLContext(0); +#endif +} + +void QRendererVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ +} + +void QRendererVideoWidgetBackend::moveEvent(QMoveEvent *) +{ +} + +void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + QPainter painter(m_widget); + + if (m_surface->isActive()) { + m_surface->paint(&painter, displayRect()); + + m_surface->setReady(true); + } else { + painter.fillRect(event->rect(), m_widget->palette().background()); + + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if (m_updatePaintDevice && (painter.paintEngine()->type() == QPaintEngine::OpenGL + || painter.paintEngine()->type() == QPaintEngine::OpenGL2)) { + m_updatePaintDevice = false; + + m_surface->setGLContext(const_cast(QGLContext::currentContext())); + if (m_surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + } +#endif + } +} + +QRect QRendererVideoWidgetBackend::displayRect() const +{ + QRect displayRect = m_widget->rect(); + + if (m_aspectRatioMode != QVideoWidget::IgnoreAspectRatio) { + QVideoSurfaceFormat format = m_surface->surfaceFormat(); + + QSize aspectRatio = format.pixelAspectRatio(); + + QSize size = format.viewport().size(); + size.rwidth() *= aspectRatio.width(); + size.rheight() *= aspectRatio.height(); + size.scale(displayRect.size(), Qt::KeepAspectRatio); + + QPoint center = displayRect.center(); + + displayRect = QRect(QPoint(0, 0), size); + displayRect.moveCenter(center); + } + + return displayRect; +} + +QWindowVideoWidgetBackend::QWindowVideoWidgetBackend(QVideoWindowControl *control, QWidget *widget) + : m_windowControl(control) + , m_widget(widget) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) +{ + connect(control, SIGNAL(brightnessChanged(int)), m_widget, SLOT(_q_brightnessChanged(int))); + connect(control, SIGNAL(contrastChanged(int)), m_widget, SLOT(_q_contrastChanged(int))); + connect(control, SIGNAL(hueChanged(int)), m_widget, SLOT(_q_hueChanged(int))); + connect(control, SIGNAL(saturationChanged(int)), m_widget, SLOT(_q_saturationChanged(int))); + connect(control, SIGNAL(fullScreenChanged(bool)), m_widget, SLOT(_q_fullScreenChanged(bool))); + connect(control, SIGNAL(nativeSizeChanged()), m_widget, SLOT(_q_dimensionsChanged())); +} + +QWindowVideoWidgetBackend::~QWindowVideoWidgetBackend() +{ +} + +void QWindowVideoWidgetBackend::setBrightness(int brightness) +{ + m_windowControl->setBrightness(brightness); +} + +void QWindowVideoWidgetBackend::setContrast(int contrast) +{ + m_windowControl->setContrast(contrast); +} + +void QWindowVideoWidgetBackend::setHue(int hue) +{ + m_windowControl->setHue(hue); +} + +void QWindowVideoWidgetBackend::setSaturation(int saturation) +{ + m_windowControl->setSaturation(saturation); +} + +void QWindowVideoWidgetBackend::setFullScreen(bool fullScreen) +{ + m_windowControl->setFullScreen(fullScreen); +} + +QVideoWidget::AspectRatioMode QWindowVideoWidgetBackend::aspectRatioMode() const +{ + return m_windowControl->aspectRatioMode(); +} + +void QWindowVideoWidgetBackend::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_windowControl->setAspectRatioMode(mode); +} + +QSize QWindowVideoWidgetBackend::sizeHint() const +{ + return m_windowControl->nativeSize(); +} + +void QWindowVideoWidgetBackend::showEvent() +{ + m_windowControl->setWinId(m_widget->winId()); + + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::hideEvent(QHideEvent *) +{ +} + +void QWindowVideoWidgetBackend::moveEvent(QMoveEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::resizeEvent(QResizeEvent *) +{ + m_windowControl->setDisplayRect(m_widget->rect()); +} + +void QWindowVideoWidgetBackend::paintEvent(QPaintEvent *event) +{ + m_windowControl->repaint(); + + event->accept(); +} + +void QVideoWidgetPrivate::setCurrentControl(QVideoWidgetControlInterface *control) +{ + if (currentControl != control) { + currentControl = control; + + currentControl->setBrightness(brightness); + currentControl->setContrast(contrast); + currentControl->setHue(hue); + currentControl->setSaturation(saturation); + currentControl->setAspectRatioMode(aspectRatioMode); + } +} + +void QVideoWidgetPrivate::show() +{ + if (outputControl) { + if (widgetBackend != 0) { + setCurrentControl(widgetBackend); + outputControl->setOutput(QVideoOutputControl::WidgetOutput); + } else if (windowBackend != 0 && (q_func()->window() == 0 + || !q_func()->window()->testAttribute(Qt::WA_DontShowOnScreen))) { + windowBackend->showEvent(); + currentBackend = windowBackend; + setCurrentControl(windowBackend); + outputControl->setOutput(QVideoOutputControl::WindowOutput); + } else if (rendererBackend != 0) { + rendererBackend->showEvent(); + currentBackend = rendererBackend; + setCurrentControl(rendererBackend); + outputControl->setOutput(QVideoOutputControl::RendererOutput); + } else { + outputControl->setOutput(QVideoOutputControl::NoOutput); + } + } +} + +void QVideoWidgetPrivate::clearService() +{ + if (service) { + QObject::disconnect(service, SIGNAL(destroyed()), q_func(), SLOT(_q_serviceDestroyed())); + + if (outputControl) + outputControl->setOutput(QVideoOutputControl::NoOutput); + + if (widgetBackend) { + QLayout *layout = q_func()->layout(); + + for (QLayoutItem *item = layout->takeAt(0); item; item = layout->takeAt(0)) { + item->widget()->setParent(0); + delete item; + } + delete layout; + + delete widgetBackend; + widgetBackend = 0; + } + + delete windowBackend; + windowBackend = 0; + + if (rendererBackend) { + rendererBackend->clearSurface(); + + delete rendererBackend; + rendererBackend = 0; + } + + currentBackend = 0; + currentControl = 0; + outputControl = 0; + service = 0; + } +} + +void QVideoWidgetPrivate::_q_serviceDestroyed() +{ + if (widgetBackend) { + delete q_func()->layout(); + + delete widgetBackend; + widgetBackend = 0; + } + + delete windowBackend; + windowBackend = 0; + + delete rendererBackend; + rendererBackend = 0; + + currentControl = 0; + currentBackend = 0; + outputControl = 0; + service = 0; +} + +void QVideoWidgetPrivate::_q_mediaObjectDestroyed() +{ + mediaObject = 0; + clearService(); +} + +void QVideoWidgetPrivate::_q_brightnessChanged(int b) +{ + if (b != brightness) + emit q_func()->brightnessChanged(brightness = b); +} + +void QVideoWidgetPrivate::_q_contrastChanged(int c) +{ + if (c != contrast) + emit q_func()->contrastChanged(contrast = c); +} + +void QVideoWidgetPrivate::_q_hueChanged(int h) +{ + if (h != hue) + emit q_func()->hueChanged(hue = h); +} + +void QVideoWidgetPrivate::_q_saturationChanged(int s) +{ + if (s != saturation) + emit q_func()->saturationChanged(saturation = s); +} + + +void QVideoWidgetPrivate::_q_fullScreenChanged(bool fullScreen) +{ + if (!fullScreen && q_func()->isFullScreen()) + q_func()->showNormal(); +} + +void QVideoWidgetPrivate::_q_dimensionsChanged() +{ + q_func()->updateGeometry(); +} + +/*! + \class QVideoWidget + \preliminary + + \brief The QVideoWidget class provides a widget which presents video + produced by a media object. + \ingroup multimedia + + Attaching a QVideoWidget to a QMediaObject allows it to display the + video or image output of that media object. A QVideoWidget is attached + to media object by passing a pointer to the QMediaObject in its + constructor, and detached by destroying the QVideoWidget. + + \code + player = new QMediaPlayer; + + widget = new QVideoWidget(player); + widget->show(); + + player->setMedia(QUrl("http://example.com/movie.mp4")); + player->play(); + \endcode + + \bold {Note}: Only a single display output can be attached to a media + object at one time. + + \sa QMediaObject, QMediaPlayer, QGraphicsVideoItem +*/ + +/*! + \enum QVideoWidget::AspectRatioMode + + Specfies how video is scaled with respect to its aspect ratio. + + \value IgnoreAspectRatio The video is scaled to fill the widget ignoring its aspect ratio. + \value KeepAspectRatio The video is scaled to the largest rectangle that will fit within the + widget's dimensions while still retaining its original aspect ratio. +*/ + +/*! + Constructs a new video widget. + + The \a parent is passed to QWidget. +*/ +QVideoWidget::QVideoWidget(QWidget *parent) + : QWidget(parent, 0) + , d_ptr(new QVideoWidgetPrivate) +{ + d_ptr->q_ptr = this; + + QPalette palette = QWidget::palette(); + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); +} + +/*! + Destroys a video widget. +*/ +QVideoWidget::~QVideoWidget() +{ + setMediaObject(0); + delete d_ptr; +} + +/*! + \property QVideoWidget::mediaObject + \brief the media object which provides the video displayed by a widget. +*/ + +QMediaObject *QVideoWidget::mediaObject() const +{ + return d_func()->mediaObject; +} + +void QVideoWidget::setMediaObject(QMediaObject *object) +{ + Q_D(QVideoWidget); + + if (object == d->mediaObject) + return; + + if (d->mediaObject) { + disconnect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + d->mediaObject->unbind(this); + } + + d->clearService(); + + d->mediaObject = object; + + if (d->mediaObject) { + d->service = d->mediaObject->service(); + + connect(d->mediaObject, SIGNAL(destroyed()), this, SLOT(_q_mediaObjectDestroyed())); + d->mediaObject->bind(this); + } + + if (d->service) { + connect(d->service, SIGNAL(destroyed()), SLOT(_q_serviceDestroyed())); + + d->outputControl = qobject_cast( + d->service->control(QVideoOutputControl_iid)); + + QVideoWidgetControl *widgetControl = qobject_cast( + d->service->control(QVideoWidgetControl_iid)); + + if (widgetControl != 0) { + d->widgetBackend = new QVideoWidgetControlBackend(widgetControl, this); + } else { + QVideoWindowControl *windowControl = qobject_cast( + d->service->control(QVideoWindowControl_iid)); + + if (windowControl != 0) + d->windowBackend = new QWindowVideoWidgetBackend(windowControl, this); + + QVideoRendererControl *rendererControl = qobject_cast( + d->service->control(QVideoRendererControl_iid)); + + if (rendererControl != 0) + d->rendererBackend = new QRendererVideoWidgetBackend(rendererControl, this); + } + + if (isVisible()) + d->show(); + } +} + +/*! + \property QVideoWidget::aspectRatioMode + \brief how video is scaled with respect to its aspect ratio. +*/ + +QVideoWidget::AspectRatioMode QVideoWidget::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QVideoWidget::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + Q_D(QVideoWidget); + + if (d->currentControl) { + d->currentControl->setAspectRatioMode(mode); + d->aspectRatioMode = d->currentControl->aspectRatioMode(); + } else { + d->aspectRatioMode = mode; + } +} + +/*! + \property QVideoWidget::fullScreen + \brief whether video display is confined to a window or is fullScreen. +*/ + +void QVideoWidget::setFullScreen(bool fullScreen) +{ + Q_D(QVideoWidget); + + if (fullScreen) { + Qt::WindowFlags flags = windowFlags(); + + d->nonFullScreenFlags = flags & (Qt::Window | Qt::SubWindow); + flags |= Qt::Window; + flags &= ~Qt::SubWindow; + setWindowFlags(flags); + + showFullScreen(); + } else { + showNormal(); + } +} + +/*! + \fn QVideoWidget::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen mode of a video widget has changed. + + \sa fullScreen +*/ + +/*! + \property QVideoWidget::brightness + \brief an adjustment to the brightness of displayed video. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +int QVideoWidget::brightness() const +{ + return d_func()->brightness; +} + +void QVideoWidget::setBrightness(int brightness) +{ + Q_D(QVideoWidget); + + int boundedBrightness = qBound(-100, brightness, 100); + + if (d->currentControl) + d->currentControl->setBrightness(boundedBrightness); + else if (d->brightness != boundedBrightness) + emit brightnessChanged(d->brightness = boundedBrightness); +} + +/*! + \fn QVideoWidget::brightnessChanged(int brightness) + + Signals that a video widgets's \a brightness adjustment has changed. + + \sa brightness +*/ + +/*! + \property QVideoWidget::contrast + \brief an adjustment to the contrast of displayed video. + + Valid contrast values range between -100 and 100, the default is 0. + +*/ + +int QVideoWidget::contrast() const +{ + return d_func()->contrast; +} + +void QVideoWidget::setContrast(int contrast) +{ + Q_D(QVideoWidget); + + int boundedContrast = qBound(-100, contrast, 100); + + if (d->currentControl) + d->currentControl->setContrast(boundedContrast); + else if (d->contrast != boundedContrast) + emit contrastChanged(d->contrast = boundedContrast); +} + +/*! + \fn QVideoWidget::contrastChanged(int contrast) + + Signals that a video widgets's \a contrast adjustment has changed. + + \sa contrast +*/ + +/*! + \property QVideoWidget::hue + \brief an adjustment to the hue of displayed video. + + Valid hue values range between -100 and 100, the default is 0. +*/ + +int QVideoWidget::hue() const +{ + return d_func()->hue; +} + +void QVideoWidget::setHue(int hue) +{ + Q_D(QVideoWidget); + + int boundedHue = qBound(-100, hue, 100); + + if (d->currentControl) + d->currentControl->setHue(boundedHue); + else if (d->hue != boundedHue) + emit hueChanged(d->hue = boundedHue); +} + +/*! + \fn QVideoWidget::hueChanged(int hue) + + Signals that a video widgets's \a hue has changed. + + \sa hue +*/ + +/*! + \property QVideoWidget::saturation + \brief an adjustment to the saturation of displayed video. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +int QVideoWidget::saturation() const +{ + return d_func()->saturation; +} + +void QVideoWidget::setSaturation(int saturation) +{ + Q_D(QVideoWidget); + + int boundedSaturation = qBound(-100, saturation, 100); + + if (d->currentControl) + d->currentControl->setSaturation(boundedSaturation); + else if (d->saturation != boundedSaturation) + emit saturationChanged(d->saturation = boundedSaturation); + +} + +/*! + \fn QVideoWidget::saturationChanged(int saturation) + + Signals that a video widgets's \a saturation has changed. + + \sa saturation +*/ + +/*! + Returns the size hint for the current back end, + if there is one, or else the size hint from QWidget. + */ +QSize QVideoWidget::sizeHint() const +{ + Q_D(const QVideoWidget); + + if (d->currentBackend) + return d->currentBackend->sizeHint(); + else + return QWidget::sizeHint(); + + +} + +/*! + \reimp + \internal + */ +bool QVideoWidget::event(QEvent *event) +{ + Q_D(QVideoWidget); + + if (event->type() == QEvent::WindowStateChange) { + Qt::WindowFlags flags = windowFlags(); + + if (windowState() & Qt::WindowFullScreen) { + if (d->currentControl) + d->currentControl->setFullScreen(true); + + if (!d->wasFullScreen) + emit fullScreenChanged(d->wasFullScreen = true); + } else { + if (d->currentControl) + d->currentControl->setFullScreen(false); + + if (d->wasFullScreen) { + flags &= ~(Qt::Window | Qt::SubWindow); //clear the flags... + flags |= d->nonFullScreenFlags; //then we reset the flags (window and subwindow) + setWindowFlags(flags); + + emit fullScreenChanged(d->wasFullScreen = false); + } + } + } + return QWidget::event(event); +} + +/*! + Handles the show \a event. + */ +void QVideoWidget::showEvent(QShowEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::showEvent(event); + + d->show(); + +} + +/*! + + Handles the hide \a event. +*/ +void QVideoWidget::hideEvent(QHideEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->hideEvent(event); + + if (d->outputControl) + d->outputControl->setOutput(QVideoOutputControl::NoOutput); + + QWidget::hideEvent(event); +} + +/*! + Handles the resize \a event. + */ +void QVideoWidget::resizeEvent(QResizeEvent *event) +{ + Q_D(QVideoWidget); + + QWidget::resizeEvent(event); + + if (d->currentBackend) + d->currentBackend->resizeEvent(event); +} + +/*! + Handles the move \a event. + */ +void QVideoWidget::moveEvent(QMoveEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->moveEvent(event); +} + +/*! + Handles the paint \a event. + */ +void QVideoWidget::paintEvent(QPaintEvent *event) +{ + Q_D(QVideoWidget); + + if (d->currentBackend) + d->currentBackend->paintEvent(event); +} + +#include "moc_qvideowidget.cpp" +#include "moc_qvideowidget_p.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideowidget.h b/src/multimedia/base/qvideowidget.h new file mode 100644 index 0000000..4e6cf2e --- /dev/null +++ b/src/multimedia/base/qvideowidget.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEOWIDGET_H +#define QVIDEOWIDGET_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaObject; + +class QVideoWidgetPrivate; +class Q_MULTIMEDIA_EXPORT QVideoWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) + Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged) + Q_PROPERTY(AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode NOTIFY aspectRatioModeChanged) + Q_PROPERTY(int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) + Q_PROPERTY(int contrast READ contrast WRITE setContrast NOTIFY contrastChanged) + Q_PROPERTY(int hue READ hue WRITE setHue NOTIFY hueChanged) + Q_PROPERTY(int saturation READ saturation WRITE setSaturation NOTIFY saturationChanged) + Q_ENUMS(AspectRatio) + +public: + enum AspectRatioMode { IgnoreAspectRatio, KeepAspectRatio }; + + QVideoWidget(QWidget *parent = 0); + ~QVideoWidget(); + + QMediaObject *mediaObject() const; + void setMediaObject(QMediaObject *object); + +#ifdef Q_QDOC + bool isFullScreen() const; +#endif + + AspectRatioMode aspectRatioMode() const; + + int brightness() const; + int contrast() const; + int hue() const; + int saturation() const; + + QSize sizeHint() const; + +public Q_SLOTS: + void setFullScreen(bool fullScreen); + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + bool event(QEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +protected: + QVideoWidgetPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QVideoWidget) + Q_PRIVATE_SLOT(d_func(), void _q_serviceDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_mediaObjectDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_brightnessChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_contrastChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_hueChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_saturationChanged(int)) + Q_PRIVATE_SLOT(d_func(), void _q_fullScreenChanged(bool)) + Q_PRIVATE_SLOT(d_func(), void _q_dimensionsChanged()); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideowidget_p.h b/src/multimedia/base/qvideowidget_p.h new file mode 100644 index 0000000..4227afd --- /dev/null +++ b/src/multimedia/base/qvideowidget_p.h @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEOWIDGET_P_H +#define QVIDEOWIDGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#ifndef QT_NO_OPENGL +#include +#endif + +#include "qpaintervideosurface_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QVideoWidgetControlInterface +{ +public: + virtual ~QVideoWidgetControlInterface() {} + + virtual void setBrightness(int brightness) = 0; + virtual void setContrast(int contrast) = 0; + virtual void setHue(int hue) = 0; + virtual void setSaturation(int saturation) = 0; + + virtual void setFullScreen(bool fullScreen) = 0; + + virtual QVideoWidget::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) = 0; +}; + +class QVideoWidgetBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT + +public: + virtual QSize sizeHint() const = 0; + + virtual void showEvent() = 0; + virtual void hideEvent(QHideEvent *event) = 0; + virtual void resizeEvent(QResizeEvent *event) = 0; + virtual void moveEvent(QMoveEvent *event) = 0; + virtual void paintEvent(QPaintEvent *event) = 0; +}; + +class QVideoWidgetControl; + +class QVideoWidgetControlBackend : public QObject, public QVideoWidgetControlInterface +{ + Q_OBJECT +public: + QVideoWidgetControlBackend(QVideoWidgetControl *control, QWidget *widget); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + +private: + QVideoWidgetControl *m_widgetControl; +}; + + +class QVideoRendererControl; + +class QRendererVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QRendererVideoWidgetBackend(QVideoRendererControl *control, QWidget *widget); + ~QRendererVideoWidgetBackend(); + + void clearSurface(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +private: + QRect displayRect() const; + + QVideoRendererControl *m_rendererControl; + QWidget *m_widget; + QPainterVideoSurface *m_surface; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QSize m_aspectRatio; + bool m_updatePaintDevice; +}; + +class QVideoWindowControl; + +class QWindowVideoWidgetBackend : public QVideoWidgetBackend +{ + Q_OBJECT +public: + QWindowVideoWidgetBackend(QVideoWindowControl *control, QWidget *widget); + ~QWindowVideoWidgetBackend(); + + void setBrightness(int brightness); + void setContrast(int contrast); + void setHue(int hue); + void setSaturation(int saturation); + + void setFullScreen(bool fullScreen); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + QSize sizeHint() const; + + void showEvent(); + void hideEvent(QHideEvent *event); + void resizeEvent(QResizeEvent *event); + void moveEvent(QMoveEvent *event); + void paintEvent(QPaintEvent *event); + +private: + QVideoWindowControl *m_windowControl; + QWidget *m_widget; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QSize m_pixelAspectRatio; +}; + +class QMediaService; +class QVideoOutputControl; + +class QVideoWidgetPrivate +{ + Q_DECLARE_PUBLIC(QVideoWidget) +public: + QVideoWidgetPrivate() + : q_ptr(0) + , mediaObject(0) + , service(0) + , outputControl(0) + , widgetBackend(0) + , windowBackend(0) + , rendererBackend(0) + , currentControl(0) + , currentBackend(0) + , brightness(0) + , contrast(0) + , hue(0) + , saturation(0) + , aspectRatioMode(QVideoWidget::KeepAspectRatio) + , nonFullScreenFlags(0) + , wasFullScreen(false) + { + } + + QVideoWidget *q_ptr; + QMediaObject *mediaObject; + QMediaService *service; + QVideoOutputControl *outputControl; + QVideoWidgetControlBackend *widgetBackend; + QWindowVideoWidgetBackend *windowBackend; + QRendererVideoWidgetBackend *rendererBackend; + QVideoWidgetControlInterface *currentControl; + QVideoWidgetBackend *currentBackend; + int brightness; + int contrast; + int hue; + int saturation; + QVideoWidget::AspectRatioMode aspectRatioMode; + Qt::WindowFlags nonFullScreenFlags; + bool wasFullScreen; + + void setCurrentControl(QVideoWidgetControlInterface *control); + void show(); + void clearService(); + + void _q_serviceDestroyed(); + void _q_mediaObjectDestroyed(); + void _q_brightnessChanged(int brightness); + void _q_contrastChanged(int contrast); + void _q_hueChanged(int hue); + void _q_saturationChanged(int saturation); + void _q_fullScreenChanged(bool fullScreen); + void _q_dimensionsChanged(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideowidgetcontrol.cpp b/src/multimedia/base/qvideowidgetcontrol.cpp new file mode 100644 index 0000000..bd7ce4e --- /dev/null +++ b/src/multimedia/base/qvideowidgetcontrol.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include "qmediacontrol_p.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWidgetControl + \preliminary + + \brief The QVideoWidgetControl class provides a media control which + implements a video widget. + + \ingroup multimedia-serv + + The videoWidget() property of QVideoWidgetControl provides a pointer to + a video widget implemented by the control's media service. This widget + is owned by the media service and so care should be taken not to delete it. + + \code + QVideoWidgetControl *widgetControl = mediaService->control(); + + layout->addWidget(widgetControl->widget()); + \endcode + + QVideoWidgetControl is one of number of possible video output controls, + in order to receive video it must be made the active video output + control by setting the output property of QVideoOutputControl to \l {QVideoOutputControl::WidgetOutput}{WidgetOutput}. Consequently any + QMediaService that implements QVideoWidgetControl must also implement + QVideoOutputControl. + + The interface name of QVideoWidgetControl is \c com.nokia.Qt.QVideoWidgetControl/1.0 as + defined in QVideoWidgetControl_iid. + + \sa QMediaService::control(), QVideoOutputControl, QVideoWidget +*/ + +/*! + \macro QVideoWidgetControl_iid + + \c com.nokia.Qt.QVideoWidgetControl/1.0 + + Defines the interface name of the QVideoWidgetControl class. + + \relates QVideoWidgetControl +*/ + +/*! + Constructs a new video widget control with the given \a parent. +*/ +QVideoWidgetControl::QVideoWidgetControl(QObject *parent) + :QMediaControl(parent) +{ +} + +/*! + Destroys a video widget control. +*/ +QVideoWidgetControl::~QVideoWidgetControl() +{ +} + +/*! + \fn QVideoWidgetControl::isFullScreen() const + + Returns true if the video is shown using the complete screen. +*/ + +/*! + \fn QVideoWidgetControl::setFullScreen(bool fullScreen) + + Sets whether a video widget is in \a fullScreen mode. +*/ + +/*! + \fn QVideoWidgetControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video widget has changed. +*/ + +/*! + \fn QVideoWidgetControl::aspectRatioMode() const + + Returns how video is scaled to fit the widget with respect to its aspect ratio. +*/ + +/*! + \fn QVideoWidgetControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the widget with + respect to its aspect ratio. +*/ + +/*! + \fn QVideoWidgetControl::brightness() const + + Returns the brightness adjustment applied to a video. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::brightnessChanged(int brightness) + + Signals that a video widget's \a brightness adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::contrast() const + + Returns the contrast adjustment applied to a video. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::setContrast(int contrast) + + Sets the contrast adjustment for a video widget to \a contrast. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + + +/*! + \fn QVideoWidgetControl::contrastChanged(int contrast) + + Signals that a video widget's \a contrast adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::hue() const + + Returns the hue adjustment applied to a video widget. + + Value hue values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::setHue(int hue) + + Sets a \a hue adjustment for a video widget. + + Valid hue values range between -100 and 100, the default is 0. +*/ + + +/*! + \fn QVideoWidgetControl::hueChanged(int hue) + + Signals that a video widget's \a hue adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::saturation() const + + Returns the saturation adjustment applied to a video widget. + + Value saturation values range between -100 and 100, the default is 0. +*/ + + +/*! + \fn QVideoWidgetControl::setSaturation(int saturation) + + Sets a \a saturation adjustment for a video widget. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWidgetControl::saturationChanged(int saturation) + + Signals that a video widget's \a saturation adjustment has changed. +*/ + +/*! + \fn QVideoWidgetControl::videoWidget() + + Returns the QWidget. +*/ + +#include "moc_qvideowidgetcontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideowidgetcontrol.h b/src/multimedia/base/qvideowidgetcontrol.h new file mode 100644 index 0000000..6981e89 --- /dev/null +++ b/src/multimedia/base/qvideowidgetcontrol.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEOWIDGETCONTROL_H +#define QVIDEOWIDGETCONTROL_H + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QVideoWidgetControlPrivate; + +class Q_MULTIMEDIA_EXPORT QVideoWidgetControl : public QMediaControl +{ + Q_OBJECT + +public: + virtual ~QVideoWidgetControl(); + + virtual QWidget *videoWidget() = 0; + + virtual QVideoWidget::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + +protected: + QVideoWidgetControl(QObject *parent = 0); +}; + +#define QVideoWidgetControl_iid "com.nokia.Qt.QVideoWidgetControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWidgetControl, QVideoWidgetControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/base/qvideowindowcontrol.cpp b/src/multimedia/base/qvideowindowcontrol.cpp new file mode 100644 index 0000000..a23cb4b --- /dev/null +++ b/src/multimedia/base/qvideowindowcontrol.cpp @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + + +QT_BEGIN_NAMESPACE + +/*! + \class QVideoWindowControl + \preliminary + \ingroup multimedia-serv + \brief The QVideoWindowControl class provides a media control for rendering video to a window. + + + The winId() property QVideoWindowControl allows a platform specific + window ID to be set as the video render target of a QMediaService. The + displayRect() property is used to set the region of the window the + video should be rendered to, and the aspectRatioMode() property + indicates how the video should be scaled to fit the displayRect(). + + \code + QVideoWindowControl *windowControl = mediaService->control(); + windowControl->setWinId(widget->winId()); + windowControl->setDisplayRect(widget->rect()); + windowControl->setAspectRatioMode(QVideoWidget::KeepAspectRatio); + \endcode + + QVideoWindowControl is one of number of possible video output controls, + in order to receive video it must be made the active video output + control by setting the output property of QVideoOutputControl to \l {QVideoOutputControl::WindowOutput}{WindowOutput}. + Consequently any QMediaService that implements QVideoWindowControl must + also implement QVideoOutputControl. + + \code + QVideoOutputControl *outputControl = mediaService->control(); + outputControl->setOutput(QVideoOutputControl::WindowOutput); + \endcode + + The interface name of QVideoWindowControl is \c com.nokia.Qt.QVideoWindowControl/1.0 as + defined in QVideoWindowControl_iid. + + \sa QMediaService::control(), QVideoOutputControl, QVideoWidget +*/ + +/*! + \macro QVideoWindowControl_iid + + \c com.nokia.Qt.QVideoWindowControl/1.0 + + Defines the interface name of the QVideoWindowControl class. + + \relates QVideoWindowControl +*/ + +/*! + Constructs a new video window control with the given \a parent. +*/ +QVideoWindowControl::QVideoWindowControl(QObject *parent) + : QMediaControl(parent) +{ +} + +/*! + Destroys a video window control. +*/ +QVideoWindowControl::~QVideoWindowControl() +{ +} + +/*! + \fn QVideoWindowControl::winId() const + + Returns the ID of the window a video overlay end point renders to. +*/ + +/*! + \fn QVideoWindowControl::setWinId(WId id) + + Sets the \a id of the window a video overlay end point renders to. +*/ + +/*! + \fn QVideoWindowControl::displayRect() const + Returns the sub-rect of a window where video is displayed. +*/ + +/*! + \fn QVideoWindowControl::setDisplayRect(const QRect &rect) + Sets the sub-\a rect of a window where video is displayed. +*/ + +/*! + \fn QVideoWindowControl::isFullScreen() const + + Identifies if a video overlay is a fullScreen overlay. + + Returns true if the video overlay is fullScreen, and false otherwise. +*/ + +/*! + \fn QVideoWindowControl::setFullScreen(bool fullScreen) + + Sets whether a video overlay is a \a fullScreen overlay. +*/ + +/*! + \fn QVideoWindowControl::fullScreenChanged(bool fullScreen) + + Signals that the \a fullScreen state of a video overlay has changed. +*/ + +/*! + \fn QVideoWindowControl::repaint() + + Repaints the last frame. +*/ + +/*! + \fn QVideoWindowControl::nativeSize() const + + Returns a suggested size for the video display based on the resolution and aspect ratio of the + video. +*/ + +/*! + \fn QVideoWindowControl::nativeSizeChanged() + + Signals that the native dimensions of the video have changed. +*/ + + +/*! + \fn QVideoWindowControl::aspectRatioMode() const + + Returns how video is scaled to fit the display region with respect to its aspect ratio. +*/ + +/*! + \fn QVideoWindowControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) + + Sets the aspect ratio \a mode which determines how video is scaled to the fit the display region + with respect to its aspect ratio. +*/ + +/*! + \fn QVideoWindowControl::brightness() const + + Returns the brightness adjustment applied to a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setBrightness(int brightness) + + Sets a \a brightness adjustment for a video overlay. + + Valid brightness values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::brightnessChanged(int brightness) + + Signals that a video overlay's \a brightness adjustment has changed. +*/ + +/*! + \fn QVideoWindowControl::contrast() const + + Returns the contrast adjustment applied to a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setContrast(int contrast) + + Sets the \a contrast adjustment for a video overlay. + + Valid contrast values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::contrastChanged(int contrast) + + Signals that a video overlay's \a contrast adjustment has changed. +*/ + +/*! + \fn QVideoWindowControl::hue() const + + Returns the hue adjustment applied to a video overlay. + + Value hue values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setHue(int hue) + + Sets a \a hue adjustment for a video overlay. + + Valid hue values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::hueChanged(int hue) + + Signals that a video overlay's \a hue adjustment has changed. +*/ + +/*! + \fn QVideoWindowControl::saturation() const + + Returns the saturation adjustment applied to a video overlay. + + Value saturation values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::setSaturation(int saturation) + Sets a \a saturation adjustment for a video overlay. + + Valid saturation values range between -100 and 100, the default is 0. +*/ + +/*! + \fn QVideoWindowControl::saturationChanged(int saturation) + + Signals that a video overlay's \a saturation adjustment has changed. +*/ + +#include "moc_qvideowindowcontrol.cpp" + +QT_END_NAMESPACE + diff --git a/src/multimedia/base/qvideowindowcontrol.h b/src/multimedia/base/qvideowindowcontrol.h new file mode 100644 index 0000000..9ee96ab --- /dev/null +++ b/src/multimedia/base/qvideowindowcontrol.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QVIDEOWINDOWCONTROL_H +#define QVIDEOWINDOWCONTROL_H + +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class Q_MULTIMEDIA_EXPORT QVideoWindowControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QVideoWindowControl(); + + virtual WId winId() const = 0; + virtual void setWinId(WId id) = 0; + + virtual QRect displayRect() const = 0; + virtual void setDisplayRect(const QRect &rect) = 0; + + virtual bool isFullScreen() const = 0; + virtual void setFullScreen(bool fullScreen) = 0; + + virtual void repaint() = 0; + + virtual QSize nativeSize() const = 0; + + virtual QVideoWidget::AspectRatioMode aspectRatioMode() const = 0; + virtual void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) = 0; + + virtual int brightness() const = 0; + virtual void setBrightness(int brightness) = 0; + + virtual int contrast() const = 0; + virtual void setContrast(int contrast) = 0; + + virtual int hue() const = 0; + virtual void setHue(int hue) = 0; + + virtual int saturation() const = 0; + virtual void setSaturation(int saturation) = 0; + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); + void nativeSizeChanged(); + +protected: + QVideoWindowControl(QObject *parent = 0); +}; + +#define QVideoWindowControl_iid "com.nokia.Qt.QVideoWindowControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QVideoWindowControl, QVideoWindowControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro index c729103..106d3ab 100644 --- a/src/multimedia/multimedia.pro +++ b/src/multimedia/multimedia.pro @@ -10,5 +10,8 @@ include(../qbase.pri) include(audio/audio.pri) include(video/video.pri) +include(base/base.pri) +include(playback/playback.pri) +include(qml/qml.pri) -symbian: TARGET.UID3 = 0x2001E627 \ No newline at end of file +symbian: TARGET.UID3 = 0x2001E627 diff --git a/src/multimedia/playback/playback.pri b/src/multimedia/playback/playback.pri new file mode 100644 index 0000000..09a81c9 --- /dev/null +++ b/src/multimedia/playback/playback.pri @@ -0,0 +1,11 @@ + +HEADERS += \ + $$PWD/qmediaplayer.h \ + $$PWD/qmediaplayercontrol.h + +SOURCES += \ + $$PWD/qmediaplayer.cpp \ + $$PWD/qmediaplayercontrol.cpp + + + diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp new file mode 100644 index 0000000..878af0a --- /dev/null +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -0,0 +1,930 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +/*! + \class QMediaPlayer + \brief The QMediaPlayer class allows the playing of a media source. + \ingroup multimedia + + \preliminary + + The QMediaPlayer class is a high level media playback class. It can be used + to playback such content as songs, movies and internet radio. The content + to playback is specified as a QMediaContent, which can be thought of as a + main or canonical URL with addition information attached. When provided + with a QMediaContent playback may be able to commence. + + \code + player = new QMediaPlayer; + connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64))); + player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3")); + player->setVolume(50); + player->play(); + \endcode + + QVideoWidget can be used with QMediaPlayer for video rendering and QMediaPlaylist + for accessing playlist functionality. + + \code + player = new QMediaPlayer; + + playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + playlist->append(QUrl("http://example.com/movie1.mp4")); + playlist->append(QUrl("http://example.com/movie2.mp4")); + + widget = new QVideoWidget; + widget->setMediaObject(player); + widget->show(); + + player->play(); + \endcode + + \sa QMediaObject, QMediaService, QVideoWidget, QMediaPlaylist +*/ + +namespace +{ +class MediaPlayerRegisterMetaTypes +{ +public: + MediaPlayerRegisterMetaTypes() + { + qRegisterMetaType("QMediaPlayer::State"); + qRegisterMetaType("QMediaPlayer::MediaStatus"); + qRegisterMetaType("QMediaPlayer::Error"); + } +} _registerPlayerMetaTypes; +} + +class QMediaPlayerPrivate : public QMediaObjectPrivate +{ + Q_DECLARE_NON_CONST_PUBLIC(QMediaPlayer) + +public: + QMediaPlayerPrivate() + : provider(0) + , control(0) + , playlistControl(0) + , state(QMediaPlayer::StoppedState) + , error(QMediaPlayer::NoError) + , filterStates(false) + , playlist(0) + {} + + QMediaServiceProvider *provider; + QMediaPlayerControl* control; + QMediaPlaylistControl* playlistControl; + QMediaPlayer::State state; + QMediaPlayer::Error error; + QString errorString; + bool filterStates; + + QMediaPlaylist *playlist; + QPointer videoWidget; + QPointer videoItem; + + void _q_stateChanged(QMediaPlayer::State state); + void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status); + void _q_error(int error, const QString &errorString); + void _q_updateMedia(const QMediaContent&); + void _q_playlistDestroyed(); +}; + +void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps) +{ + Q_Q(QMediaPlayer); + + if (filterStates) + return; + + if (playlist + && !playlistControl //service should do this itself + && ps != state && ps == QMediaPlayer::StoppedState + && control->mediaStatus() == QMediaPlayer::EndOfMedia) { + playlist->next(); + ps = control->state(); + } + + if (ps != state) { + state = ps; + + if (ps == QMediaPlayer::PlayingState) + q->addPropertyWatch("position"); + else + q->removePropertyWatch("position"); + + emit q->stateChanged(ps); + } +} + +void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + Q_Q(QMediaPlayer); + + switch (status) { + case QMediaPlayer::StalledMedia: + case QMediaPlayer::BufferingMedia: + q->addPropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + default: + q->removePropertyWatch("bufferStatus"); + emit q->mediaStatusChanged(status); + break; + } + +} + +void QMediaPlayerPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaPlayer); + + this->error = QMediaPlayer::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media) +{ + const QMediaPlayer::State currentState = state; + + filterStates = true; + control->setMedia(media, 0); + + if (!media.isNull()) { + switch (currentState) { + case QMediaPlayer::PlayingState: + control->play(); + break; + case QMediaPlayer::PausedState: + control->pause(); + break; + default: + break; + } + } + filterStates = false; + + state = control->state(); + + if (state != currentState) + emit q_func()->stateChanged(state); +} + +void QMediaPlayerPrivate::_q_playlistDestroyed() +{ + playlist = 0; + + control->setMedia(QMediaContent(), 0); +} + +static QMediaService *playerService(QMediaPlayer::Flags flags, QMediaServiceProvider *provider) +{ + if (flags && QMediaPlayer::LowLatency) + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER, + QMediaServiceProviderHint(QMediaServiceProviderHint::LowLatencyPlayback)); + else + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); +} + + +/*! + Construct a QMediaPlayer that uses the playback service from \a provider, + parented to \a parent and with \a flags. + + If a playback service is not specified the system default will be used. +*/ + +QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags, QMediaServiceProvider *provider): + QMediaObject(*new QMediaPlayerPrivate, + parent, + playerService(flags,provider)) +{ + Q_D(QMediaPlayer); + + d->provider = provider; + + if (d->service == 0) { + d->error = ServiceMissingError; + } else { + d->control = qobject_cast(d->service->control(QMediaPlayerControl_iid)); + d->playlistControl = qobject_cast(d->service->control(QMediaPlaylistControl_iid)); + if (d->control != 0) { + connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SIGNAL(mediaChanged(QMediaContent))); + connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State))); + connect(d->control, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(d->control, SIGNAL(error(int,QString)), SLOT(_q_error(int,QString))); + + connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(d->control, SIGNAL(positionChanged(qint64)), SIGNAL(positionChanged(qint64))); + connect(d->control, SIGNAL(videoAvailableChanged(bool)), SIGNAL(videoAvailableChanged(bool))); + connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(d->control, SIGNAL(seekableChanged(bool)), SIGNAL(seekableChanged(bool))); + connect(d->control, SIGNAL(playbackRateChanged(qreal)), SIGNAL(playbackRateChanged(qreal))); + + if (d->control->state() == PlayingState) + addPropertyWatch("position"); + + if (d->control->mediaStatus() == StalledMedia || d->control->mediaStatus() == BufferingMedia) + addPropertyWatch("bufferStatus"); + } + } +} + + +/*! + Destroys the player object. +*/ + +QMediaPlayer::~QMediaPlayer() +{ + Q_D(QMediaPlayer); + + d->provider->releaseService(d->service); +} + +QMediaContent QMediaPlayer::media() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->media(); + + return QMediaContent(); +} + +/*! + Returns the stream source of media data. + + This is only valid if a stream was passed to setMedia(). + + \sa setMedia() +*/ + +const QIODevice *QMediaPlayer::mediaStream() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStream(); + + return 0; +} + +QMediaPlayer::State QMediaPlayer::state() const +{ + return d_func()->state; +} + +QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->mediaStatus(); + + return QMediaPlayer::UnknownMediaStatus; +} + +qint64 QMediaPlayer::duration() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->duration(); + + return -1; +} + +qint64 QMediaPlayer::position() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->position(); + + return 0; +} + +int QMediaPlayer::volume() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->volume(); + + return 0; +} + +bool QMediaPlayer::isMuted() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isMuted(); + + return false; +} + +int QMediaPlayer::bufferStatus() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->bufferStatus(); + + return 0; +} + +bool QMediaPlayer::isVideoAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isVideoAvailable(); + + return false; +} + +bool QMediaPlayer::isSeekable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isSeekable(); + + return false; +} + +qreal QMediaPlayer::playbackRate() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->playbackRate(); + + return 0.0; +} + +/*! + Returns the current error state. +*/ + +QMediaPlayer::Error QMediaPlayer::error() const +{ + return d_func()->error; +} + +QString QMediaPlayer::errorString() const +{ + return d_func()->errorString; +} + +//public Q_SLOTS: +/*! + Start or resume playing the current source. +*/ + +void QMediaPlayer::play() +{ + Q_D(QMediaPlayer); + + if (d->control == 0) { + QMetaObject::invokeMethod(this, "_q_error", Qt::QueuedConnection); + Q_ARG(int, QMediaPlayer::ServiceMissingError), + Q_ARG(QString, tr("The QMediaPlayer object does not have a valid service")); + return; + } + + //if playlist control is available, the service should advance itself + if (d->playlist && !d->playlistControl && d->playlist->currentIndex() == -1 && !d->playlist->isEmpty()) + d->playlist->setCurrentIndex(0); + + // Reset error conditions + d->error = NoError; + d->errorString = QString(); + + d->control->play(); +} + +/*! + Pause playing the current source. +*/ + +void QMediaPlayer::pause() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->pause(); +} + +/*! + Stop playing, and reset the play position to the beginning. +*/ + +void QMediaPlayer::stop() +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->stop(); +} + +void QMediaPlayer::setPosition(qint64 position) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || !isSeekable()) + return; + + d->control->setPosition(qBound(qint64(0), duration(), position)); +} + +void QMediaPlayer::setVolume(int v) +{ + Q_D(QMediaPlayer); + + if (d->control == 0) + return; + + int clamped = qBound(0, v, 100); + if (clamped == volume()) + return; + + d->control->setVolume(clamped); +} + +void QMediaPlayer::setMuted(bool muted) +{ + Q_D(QMediaPlayer); + + if (d->control == 0 || muted == isMuted()) + return; + + d->control->setMuted(muted); +} + +void QMediaPlayer::setPlaybackRate(qreal rate) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d->control->setPlaybackRate(rate); +} + +/*! + Sets the current \a media source. + + If a \a stream is supplied; media data will be read from it instead of resolving the media + source. In this case the media source may still be used to resolve additional information + about the media such as mime type. + + Setting the media to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. +*/ + +void QMediaPlayer::setMedia(const QMediaContent &media, QIODevice *stream) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) + d_func()->control->setMedia(media, stream); +} + +/*! + \internal +*/ + +void QMediaPlayer::bind(QObject *obj) +{ + Q_D(QMediaPlayer); + + if (d->control != 0) { + QMediaPlaylist *playlist = qobject_cast(obj); + + if (playlist) { + if (d->playlist) + d->playlist->setMediaObject(0); + + d->playlist = playlist; + connect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + connect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + + setMedia(playlist->currentMedia()); + + return; + } + + QVideoWidget *videoWidget = qobject_cast(obj); + QGraphicsVideoItem *videoItem = qobject_cast(obj); + + if (videoWidget || videoItem) { + //detach the current video output + if (d->videoWidget) { + d->videoWidget->setMediaObject(0); + d->videoWidget = 0; + } + + if (d->videoItem) { + d->videoItem->setMediaObject(0); + d->videoItem = 0; + } + } + + if (videoWidget) + d->videoWidget = videoWidget; + + if (videoItem) + d->videoItem = videoItem; + } +} + +/*! + \internal +*/ + +void QMediaPlayer::unbind(QObject *obj) +{ + Q_D(QMediaPlayer); + + if (obj == d->videoWidget) { + d->videoWidget = 0; + } else if (obj == d->videoItem) { + d->videoItem = 0; + } else if (obj == d->playlist) { + disconnect(d->playlist, SIGNAL(currentMediaChanged(QMediaContent)), + this, SLOT(_q_updateMedia(QMediaContent))); + disconnect(d->playlist, SIGNAL(destroyed()), this, SLOT(_q_playlistDestroyed())); + d->playlist = 0; + setMedia(QMediaContent()); + } +} + +/*! + Returns the level of support a media player has for a \a mimeType and a set of \a codecs. + + The \a flags argument allows additional requirements such as performance indicators to be + specified. +*/ +QtMedia::SupportEstimate QMediaPlayer::hasSupport(const QString &mimeType, + const QStringList& codecs, + Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + mimeType, + codecs, + flags); +} + +/*! + Returns a list of MIME types supported by the media player. + + The \a flags argument causes the resultant list to be restricted to MIME types which can be supported + given additional requirements, such as performance indicators. +*/ +QStringList QMediaPlayer::supportedMimeTypes(Flags flags) +{ + return QMediaServiceProvider::defaultServiceProvider()->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), + flags); +} + + +// Enums +/*! + \enum QMediaPlayer::State + + Defines the current state of a media player. + + \value PlayingState The media player is currently playing content. + \value PausedState The media player has paused playback, playback of the current track will + resume from the position the player was paused at. + \value StoppedState The media player is not playing content, playback will begin from the start + of the current track. +*/ + +/*! + \enum QMediaPlayer::MediaStatus + + Defines the status of a media player's current media. + + \value UnknownMediaStatus The status of the media cannot be determined. + \value NoMedia The is no current media. The player is in the StoppedState. + \value LoadingMedia The current media is being loaded. The player may be in any state. + \value LoadedMedia The current media has been loaded. The player is in the StoppedState. + \value StalledMedia Playback of the current media has stalled due to insufficient buffering or + some other temporary interruption. The player is in the PlayingState or PausedState. + \value BufferingMedia The player is buffering data but has enough data buffered for playback to + continue for the immediate future. The player is in the PlayingState or PausedState. + \value BufferedMedia The player has fully buffered the current media. The player is in the + PlayingState or PausedState. + \value EndOfMedia Playback has reached the end of the current media. The player is in the + StoppedState. + \value InvalidMedia The current media cannot be played. The player is in the StoppedState. +*/ + +/*! + \enum QMediaPlayer::Error + + Defines a media player error condition. + + \value NoError No error has occurred. + \value ResourceError A media resource couldn't be resolved. + \value FormatError The format of a media resource isn't (fully) supported. Playback may still + be possible, but without an audio or video component. + \value NetworkError A network error occurred. + \value AccessDeniedError There are not the appropriate permissions to play a media resource. + \value ServiceMissingError A valid playback service was not found, playback cannot proceed. +*/ + +// Signals +/*! + \fn QMediaPlayer::error(QMediaPlayer::Error error) + + Signals that an \a error condition has occurred. + + \sa errorString() +*/ + +/*! + \fn void QMediaPlayer::stateChanged(State state) + + Signal the \a state of the Player object has changed. +*/ + +/*! + \fn QMediaPlayer::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \sa mediaStatus() +*/ + +/*! + \fn void QMediaPlayer::mediaChanged(const QMediaContent &media); + + Signals that the current playing content will be obtained from \a media. + + \sa media() +*/ + +/*! + \fn void QMediaPlayer::playbackRateChanged(qreal rate); + + Signals the playbackRate has changed to \a rate. +*/ + +/*! + \fn void QMediaPlayer::seekableChanged(bool seekable); + + Signals the \a seekable status of the player object has changed. +*/ + +// Properties +/*! + \property QMediaPlayer::state + \brief the media player's playback state. + + By default this property is QMediaPlayer::Stopped + + \sa mediaStatus(), play(), pause(), stop() +*/ + +/*! + \property QMediaPlayer::error + \brief a string describing the last error condition. + + \sa error() +*/ + +/*! + \property QMediaPlayer::media + \brief the active media source being used by the player object. + + The player object will use the QMediaContent for selection of the content to + be played. + + By default this property has a null QMediaContent. + + Setting this property to a null QMediaContent will cause the player to discard all + information relating to the current media source and to cease all I/O operations related + to that media. + + \sa QMediaContent +*/ + +/*! + \property QMediaPlayer::mediaStatus + \brief the status of the current media stream. + + The stream status describes how the playback of the current stream is + progressing. + + By default this property is QMediaPlayer::NoMedia + + \sa state +*/ + +/*! + \property QMediaPlayer::duration + \brief the duration of the current media. + + The value is the total playback time in milliseconds of the current media. + The value may change across the life time of the QMediaPlayer object and + may not be available when initial playback begins, connect to the + durationChanged() signal to receive status notifications. +*/ + +/*! + \property QMediaPlayer::position + \brief the playback position of the current media. + + The value is the current playback position, expressed in milliseconds since + the beginning of the media. Periodically changes in the position will be + indicated with the signal positionChanged(), the interval between updates + can be set with QMediaObject's method setNotifyInterval(). +*/ + +/*! + \property QMediaPlayer::volume + \brief the current playback volume. + + The playback volume is a linear in effect and the value can range from 0 - + 100, values outside this range will be clamped. +*/ + +/*! + \property QMediaPlayer::muted + \brief the muted state of the current media. + + The value will be true if the playback volume is muted; otherwise false. +*/ + +/*! + \property QMediaPlayer::bufferStatus + \brief the percentage of the temporary buffer filled before playback begins. + + When the player object is buffering; this property holds the percentage of + the temporary buffer that is filled. The buffer will need to reach 100% + filled before playback can resume, at which time the MediaStatus will be + BufferedMedia. + + \sa mediaStatus() +*/ + +/*! + \property QMediaPlayer::videoAvailable + \brief the video availability status for the current media. + + If available, the QVideoWidget class can be used to view the video. As the + life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + videoAvailableChanged signal can be used to monitor it's status. + + \sa QVideoWidget, QMediaContent +*/ + +/*! + \property QMediaPlayer::seekable + \brief the seek-able status of the current media + + If seeking is supported this property will be true; false otherwise. The + status of this property may change across the life time of the QMediaPlayer + object, use the seekableChanged signal to monitor changes. +*/ + +/*! + \property QMediaPlayer::playbackRate + \brief the playback rate of the current media. + + This value is a multiplier applied to the media's standard play rate. By + default this value is 1.0, indicating that the media is playing at the + standard pace. Values higher than 1.0 will increase the rate of play. + Values less than zero can be set and indicate the media will rewind at the + multiplier of the standard pace. + + Not all playback services support change of the playback rate. It is + framework defined as to the status and quality of audio and video + while fast forwarding or rewinding. +*/ + +/*! + \fn void QMediaPlayer::durationChanged(qint64 duration) + + Signal the duration of the content has changed to \a duration, expressed in milliseconds. +*/ + +/*! + \fn void QMediaPlayer::positionChanged(qint64 position) + + Signal the position of the content has changed to \a position, expressed in + milliseconds. +*/ + +/*! + \fn void QMediaPlayer::volumeChanged(int volume) + + Signal the playback volume has changed to \a volume. +*/ + +/*! + \fn void QMediaPlayer::mutedChanged(bool muted) + + Signal the mute state has changed to \a muted. +*/ + +/*! + \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable) + + Signal the availability of visual content has changed to \a videoAvailable. +*/ + +/*! + \fn void QMediaPlayer::bufferStatusChanged(int percentFilled) + + Signal the amount of the local buffer filled as a percentage by \a percentFilled. +*/ + +/*! + \enum QMediaPlayer::Flag + + \value LowLatency + The player is expected to be used with simple audio formats, + but playback should start without significant delay. + Such playback service can be used for beeps, ringtones, etc. +*/ + +#include "moc_qmediaplayer.cpp" + +QT_END_NAMESPACE + +QT_END_NAMESPACE + diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h new file mode 100644 index 0000000..4de2b5e --- /dev/null +++ b/src/multimedia/playback/qmediaplayer.h @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYER_H +#define QMEDIAPLAYER_H + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylist; + +class QMediaPlayerPrivate; +class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(QMediaContent media READ media WRITE setMedia NOTIFY mediaChanged) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(qint64 position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int bufferStatus READ bufferStatus NOTIFY bufferStatusChanged) + Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(MediaStatus mediaStatus READ mediaStatus NOTIFY mediaStatusChanged) + Q_PROPERTY(QString error READ errorString) + Q_ENUMS(State) + Q_ENUMS(MediaStatus) + +public: + enum State + { + StoppedState, + PlayingState, + PausedState + }; + + enum MediaStatus + { + UnknownMediaStatus, + NoMedia, + LoadingMedia, + LoadedMedia, + StalledMedia, + BufferingMedia, + BufferedMedia, + EndOfMedia, + InvalidMedia + }; + + enum Flag + { + LowLatency = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + enum Error + { + NoError, + ResourceError, + FormatError, + NetworkError, + AccessDeniedError, + ServiceMissingError + }; + + QMediaPlayer(QObject *parent = 0, Flags flags = 0, QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider()); + ~QMediaPlayer(); + + static QtMedia::SupportEstimate hasSupport(const QString &mimeType, + const QStringList& codecs = QStringList(), + Flags flags = 0); + static QStringList supportedMimeTypes(Flags flags = 0); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + + State state() const; + MediaStatus mediaStatus() const; + + qint64 duration() const; + qint64 position() const; + + int volume() const; + bool isMuted() const; + bool isVideoAvailable() const; + + int bufferStatus() const; + + bool isSeekable() const; + qreal playbackRate() const; + + Error error() const; + QString errorString() const; + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + + void setPosition(qint64 position); + void setVolume(int volume); + void setMuted(bool muted); + + void setPlaybackRate(qreal rate); + + void setMedia(const QMediaContent &media, QIODevice *stream = 0); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + + void bufferStatusChanged(int percentFilled); + + void seekableChanged(bool seekable); + void playbackRateChanged(qreal rate); + + void error(QMediaPlayer::Error error); + +public: + virtual void bind(QObject*); + virtual void unbind(QObject*); + +private: + Q_DISABLE_COPY(QMediaPlayer) + Q_DECLARE_PRIVATE(QMediaPlayer) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaPlayer::State)) + Q_PRIVATE_SLOT(d_func(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateMedia(const QMediaContent&)) + Q_PRIVATE_SLOT(d_func(), void _q_playlistDestroyed()) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlayer::State)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlayer::MediaStatus)) +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QMediaPlayer::Error)) + +QT_END_HEADER + +#endif // QMEDIAPLAYER_H diff --git a/src/multimedia/playback/qmediaplayercontrol.cpp b/src/multimedia/playback/qmediaplayercontrol.cpp new file mode 100644 index 0000000..90e3a8c --- /dev/null +++ b/src/multimedia/playback/qmediaplayercontrol.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 +#include +#include + + +QT_BEGIN_NAMESPACE + + +/*! + \class QMediaPlayerControl + \ingroup multimedia-serv + + \preliminary + \brief The QMediaPlayerControl class provides access to the media playing + functionality of a QMediaService. + + If a QMediaService can play media is will implement QMediaPlayerControl. + This control provides a means to set the \l {setMedia()}{media} to play, + \l {play()}{start}, \l {pause()} {pause} and \l {stop()}{stop} playback, + \l {setPosition()}{seek}, and control the \l {setVolume()}{volume}. + It also provides feedback on the \l {duration()}{duration} of the media, + the current \l {position()}{position}, and \l {bufferStatus()}{buffering} + progress. + + The functionality provided by this control is exposed to application + code through the QMediaPlayer class. + + The interface name of QMediaPlayerControl is \c com.nokia.Qt.QMediaPlayerControl/1.0 as + defined in QMediaPlayerControl_iid. + + \sa QMediaService::control(), QMediaPlayer +*/ + +/*! + \macro QMediaPlayerControl_iid + + \c com.nokia.Qt.QMediaPlayerControl/1.0 + + Defines the interface name of the QMediaPlayerControl class. + + \relates QMediaPlayerControl +*/ + +/*! + Destroys a media player control. +*/ +QMediaPlayerControl::~QMediaPlayerControl() +{ +} + +/*! + Constructs a new media player control with the given \a parent. +*/ +QMediaPlayerControl::QMediaPlayerControl(QObject *parent): + QMediaControl(*new QMediaControlPrivate, parent) +{ +} + +/*! + \fn QMediaPlayerControl::state() const + + Returns the state of a player control. +*/ + +/*! + \fn QMediaPlayerControl::stateChanged(QMediaPlayer::State state) + + Signals that the \a state of a player control has changed. + + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::mediaStatus() const + + Returns the status of the current media. +*/ + +/*! + \fn QMediaPlayerControl::mediaStatusChanged(QMediaPlayer::MediaStatus status) + + Signals that the \a status of the current media has changed. + + \sa mediaStatus() +*/ + + +/*! + \fn QMediaPlayerControl::duration() const + + Returns the duration of the current media in milliseconds. +*/ + +/*! + \fn QMediaPlayerControl::durationChanged(qint64 duration) + + Signals that the \a duration of the current media has changed. + + \sa duration() +*/ + +/*! + \fn QMediaPlayerControl::position() const + + Returns the current playback position in milliseconds. +*/ + +/*! + \fn QMediaPlayerControl::setPosition(qint64 position) + + Sets the playback \a position of the current media. This will initiate a seek and it may take + some time for playback to reach the position set. +*/ + +/*! + \fn QMediaPlayerControl::positionChanged(qint64 position) + + Signals the playback \a position has changed. + + This is only emitted in when there has been a discontinous change in the playback postion, such + as a seek or the position being reset. + + \sa position() +*/ + +/*! + \fn QMediaPlayerControl::volume() const + + Returns the audio volume of a player control. +*/ + +/*! + \fn QMediaPlayerControl::setVolume(int volume) + + Sets the audio \a volume of a player control. +*/ + +/*! + \fn QMediaPlayerControl::volumeChanged(int volume) + + Signals the audio \a volume of a player control has changed. + + \sa volume() +*/ + +/*! + \fn QMediaPlayerControl::isMuted() const + + Returns the mute state of a player control. +*/ + +/*! + \fn QMediaPlayerControl::setMuted(bool mute) + + Sets the \a mute state of a player control. +*/ + +/*! + \fn QMediaPlayerControl::mutedChanged(bool mute) + + Signals a change in the \a mute status of a player control. + + \sa isMuted() +*/ + +/*! + \fn QMediaPlayerControl::bufferStatus() const + + Returns the buffering progress of the current media. Progress is measured in the percentage + of the buffer filled. +*/ + +/*! + \fn QMediaPlayerControl::bufferStatusChanged(int progress) + + Signals that buffering \a progress has changed. + + \sa bufferStatus() +*/ + +/*! + \fn QMediaPlayerControl::isVideoAvailable() const + + Identifies if there is video output available for the current media. + + Returns true if video output is available and false otherwise. +*/ + +/*! + \fn QMediaPlayerControl::videoAvailableChanged(bool video) + + Signals that there has been a change in the availability of \a video output. + + \sa isVideoAvailable() +*/ + +/*! + \fn QMediaPlayerControl::isSeekable() const + + Identifies if the current media is seekable. + + Returns true if it possible to seek within the current media, and false otherwise. +*/ + +/*! + \fn QMediaPlayerControl::seekableChanged(bool seekable) + + Signals that the \a seekable state of a player control has changed. + + \sa isSeekable() +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRanges() const + + Returns a range of times in milliseconds that can be played back. + + Usually for local files this is a continuous interval equal to [0..duration()] + or an empty time range if seeking is not supported, but for network sources + it refers to the buffered parts of the media. +*/ + +/*! + \fn QMediaPlayerControl::availablePlaybackRangesChanged(const QMediaTimeRange &ranges) + + Signals that the available media playback \a ranges have changed. + + \sa QMediaPlayerControl::availablePlaybackRanges() +*/ + +/*! + \fn qreal QMediaPlayerControl::playbackRate() const + + Returns the rate of playback. +*/ + +/*! + \fn QMediaPlayerControl::setPlaybackRate(qreal rate) + + Sets the \a rate of playback. +*/ + +/*! + \fn QMediaPlayerControl::media() const + + Returns the current media source. +*/ + +/*! + \fn QMediaPlayerControl::mediaStream() const + + Returns the current media stream. This is only a valid if a stream was passed to setMedia(). + + \sa setMedia() +*/ + +/*! + \fn QMediaPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) + + Sets the current \a media source. If a \a stream is supplied; data will be read from that + instead of attempting to resolve the media source. The media source may still be used to + supply media information such as mime type. + + Setting the media to a null QMediaContent will cause the control to discard all + information relating to the current media source and to cease all I/O operations related + to that media. +*/ + +/*! + \fn QMediaPlayerControl::mediaChanged(const QMediaContent& content) + + Signals that the current media \a content has changed. +*/ + +/*! + \fn QMediaPlayerControl::play() + + Starts playback of the current media. + + If successful the player control will immediately enter the \l {QMediaPlayer::PlayingState} + {playing} state. + + \sa state() +*/ + +/*! + \fn QMediaPlayerControl::pause() + + Pauses playback of the current media. + + If sucessful the player control will immediately enter the \l {QMediaPlayer::PausedState} + {paused} state. + + \sa state(), play(), stop() +*/ + +/*! + \fn QMediaPlayerControl::stop() + + Stops playback of the current media. + + If succesful the player control will immediately enter the \l {QMediaPlayer::StoppedState} + {stopped} state. +*/ + +/*! + \fn QMediaPlayerControl::error(int error, const QString &errorString) + + Signals that an \a error has occurred. The \a errorString provides a more detailed explanation. +*/ + +/*! + \fn QMediaPlayerControl::playbackRateChanged(qreal rate) + + Signal emitted when playback rate changes to \a rate. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaplayercontrol.cpp" + diff --git a/src/multimedia/playback/qmediaplayercontrol.h b/src/multimedia/playback/qmediaplayercontrol.h new file mode 100644 index 0000000..ac3fc45 --- /dev/null +++ b/src/multimedia/playback/qmediaplayercontrol.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMEDIAPLAYERCONTROL_H +#define QMEDIAPLAYERCONTROL_H + +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + + +class QMediaPlaylist; + +class Q_MULTIMEDIA_EXPORT QMediaPlayerControl : public QMediaControl +{ + Q_OBJECT + +public: + ~QMediaPlayerControl(); + + virtual QMediaPlayer::State state() const = 0; + + virtual QMediaPlayer::MediaStatus mediaStatus() const = 0; + + virtual qint64 duration() const = 0; + + virtual qint64 position() const = 0; + virtual void setPosition(qint64 position) = 0; + + virtual int volume() const = 0; + virtual void setVolume(int volume) = 0; + + virtual bool isMuted() const = 0; + virtual void setMuted(bool muted) = 0; + + virtual int bufferStatus() const = 0; + + virtual bool isVideoAvailable() const = 0; + + virtual bool isSeekable() const = 0; + + virtual QMediaTimeRange availablePlaybackRanges() const = 0; + + virtual qreal playbackRate() const = 0; + virtual void setPlaybackRate(qreal rate) = 0; + + virtual QMediaContent media() const = 0; + virtual const QIODevice *mediaStream() const = 0; + virtual void setMedia(const QMediaContent &media, QIODevice *stream) = 0; + + virtual void play() = 0; + virtual void pause() = 0; + virtual void stop() = 0; + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void availablePlaybackRangesChanged(const QMediaTimeRange&); + void playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +protected: + QMediaPlayerControl(QObject* parent = 0); +}; + +#define QMediaPlayerControl_iid "com.nokia.Qt.QMediaPlayerControl/1.0" +Q_MEDIA_DECLARE_CONTROL(QMediaPlayerControl, QMediaPlayerControl_iid) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMEDIAPLAYERCONTROL_H + diff --git a/src/multimedia/qml/qml.pri b/src/multimedia/qml/qml.pri new file mode 100644 index 0000000..adfcc23 --- /dev/null +++ b/src/multimedia/qml/qml.pri @@ -0,0 +1,11 @@ + +contains(QT_CONFIG, declarative) { + QT += declarative + + HEADERS += \ + $$PWD/qmlsound_p.h + + SOURCES += \ + $$PWD/qmlsound.cpp +} + diff --git a/src/multimedia/qml/qmlsound.cpp b/src/multimedia/qml/qmlsound.cpp new file mode 100644 index 0000000..6b01418 --- /dev/null +++ b/src/multimedia/qml/qmlsound.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qmlsound_p.h" + +#include + + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt,4,6,Sound,QmlSound) + +QmlSound::QmlSound(QObject *parent) : + QObject(parent), + m_loopCount(1), + m_volume(100), + m_muted(false), + m_runningCount(0), + m_player(0) +{ +} + +QmlSound::~QmlSound() +{ + delete m_player; +} + +QUrl QmlSound::source() const +{ + return m_player != 0 ? m_player->media().canonicalUrl() : QUrl(); +} + +void QmlSound::setSource(const QUrl &url) +{ + if (m_player != 0 && m_player->media().canonicalUrl() == url) + return; + + if (m_player == 0) { + m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency); + m_player->setVolume(m_volume); + m_player->setMuted(m_muted); + + connect(m_player, SIGNAL(volumeChanged()), SIGNAL(volumeChanged())); + connect(m_player, SIGNAL(mutedChanged()), SIGNAL(mutedChanged())); + connect(m_player, SIGNAL(durationChanged()), SIGNAL(durationChanged())); + connect(m_player, SIGNAL(stateChanged()), SLOT(repeat())); + } + + m_player->setMedia(url); + if (url.isEmpty()) + return; + + emit sourceChanged(); +} + +int QmlSound::loopCount() const +{ + return m_loopCount; +} + +void QmlSound::setLoopCount(int loopCount) +{ + if (m_loopCount == loopCount) + return; + + m_loopCount = loopCount; + emit loopCountChanged(); +} + +int QmlSound::volume() const +{ + return m_player != 0 ? m_player->volume() : m_volume; +} + +void QmlSound::setVolume(int volume) +{ + if (m_volume == volume) + return; + + m_volume = volume; + if (m_player != 0) + m_player->setVolume(volume); + else + emit volumeChanged(); +} + +bool QmlSound::isMuted() const +{ + return m_player != 0 ? m_player->isMuted() : m_muted; +} + +void QmlSound::setMuted(bool muted) +{ + if (m_muted == muted) + return; + + m_muted = muted; + if (m_player != 0) + m_player->setMuted(muted); + else + emit mutedChanged(); +} + +int QmlSound::duration() const +{ + return m_player != 0 ? m_player->duration() : 0; +} + +void QmlSound::play() +{ + m_runningCount = 0; + if (m_player != 0) + m_player->play(); +} + +void QmlSound::stop() +{ + if (m_player != 0) + m_player->stop(); +} + +void QmlSound::repeat() +{ + if (m_player->state() == QMediaPlayer::StoppedState) { + if (++m_runningCount < m_loopCount) + m_player->play(); + } +} + +QT_END_NAMESPACE diff --git a/src/multimedia/qml/qmlsound_p.h b/src/multimedia/qml/qmlsound_p.h new file mode 100644 index 0000000..3c17413 --- /dev/null +++ b/src/multimedia/qml/qmlsound_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMLSOUND_H +#define QMLSOUND_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Multimedia) + +class QMediaPlayer; + +class QmlSound : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + +public: + explicit QmlSound(QObject *parent = 0); + ~QmlSound(); + + QUrl source() const; + void setSource(const QUrl &url); + + int loopCount() const; + void setLoopCount(int loopCount); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int duration() const; + +signals: + void sourceChanged(); + void loopCountChanged(); + void volumeChanged(); + void mutedChanged(); + void durationChanged(); + +public slots: + void play(); + void stop(); + +private slots: + void repeat(); + +private: + Q_DISABLE_COPY(QmlSound) + + int m_loopCount; + int m_volume; + bool m_muted; + int m_runningCount; + QMediaPlayer *m_player; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +QML_DECLARE_TYPE(QmlSound) + +#endif // QMLSOUND_H diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro new file mode 100644 index 0000000..765477d --- /dev/null +++ b/src/plugins/mediaservices/mediaservices.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += qt7 + + diff --git a/src/plugins/mediaservices/qt7/qcvdisplaylink.h b/src/plugins/mediaservices/qt7/qcvdisplaylink.h new file mode 100644 index 0000000..5cd8f73 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qcvdisplaylink.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QCVDISPLAYLINK_H +#define QCVDISPLAYLINK_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink : public QObject +{ +Q_OBJECT +public: + QCvDisplayLink(QObject *parent = 0); + virtual ~QCvDisplayLink(); + + bool isValid(); + bool isActive() const; + +public slots: + void start(); + void stop(); + +signals: + void tick(const CVTimeStamp &ts); + +public: + void displayLinkEvent(const CVTimeStamp *); + +protected: + virtual bool event(QEvent *); + +private: + CVDisplayLinkRef m_displayLink; + QMutex m_displayLinkMutex; + bool m_pendingDisplayLinkEvent; + bool m_isActive; + CVTimeStamp m_frameTimeStamp; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + diff --git a/src/plugins/mediaservices/qt7/qcvdisplaylink.mm b/src/plugins/mediaservices/qt7/qcvdisplaylink.mm new file mode 100644 index 0000000..98ae71d --- /dev/null +++ b/src/plugins/mediaservices/qt7/qcvdisplaylink.mm @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qcvdisplaylink.h" + +#include +#include + + +QT_USE_NAMESPACE + +static CVReturn CVDisplayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + Q_UNUSED(displayLink); + Q_UNUSED(inNow); + Q_UNUSED(flagsIn); + Q_UNUSED(flagsOut); + + QCvDisplayLink *link = (QCvDisplayLink *)displayLinkContext; + + link->displayLinkEvent(inOutputTime); + return kCVReturnSuccess; +} + + +QCvDisplayLink::QCvDisplayLink(QObject *parent) + :QObject(parent), + m_pendingDisplayLinkEvent(false), + m_isActive(false) +{ + // create display link for the main display + CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink); + if (m_displayLink) { + // set the current display of a display link. + CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay); + + // set the renderer output callback function + CVDisplayLinkSetOutputCallback(m_displayLink, &CVDisplayLinkCallback, this); + } +} + +QCvDisplayLink::~QCvDisplayLink() +{ + if (m_displayLink) { + CVDisplayLinkStop(m_displayLink); + CVDisplayLinkRelease(m_displayLink); + m_displayLink = NULL; + } +} + +bool QCvDisplayLink::isValid() +{ + return m_displayLink != 0; +} + +bool QCvDisplayLink::isActive() const +{ + return m_isActive; +} + +void QCvDisplayLink::start() +{ + if (m_displayLink && !m_isActive) { + CVDisplayLinkStart(m_displayLink); + m_isActive = true; + } +} + +void QCvDisplayLink::stop() +{ + if (m_displayLink && m_isActive) { + CVDisplayLinkStop(m_displayLink); + m_isActive = false; + } +} + +void QCvDisplayLink::displayLinkEvent(const CVTimeStamp *ts) +{ + // This function is called from a + // thread != gui thread. So we post the event. + // But we need to make sure that we don't post faster + // than the event loop can eat: + m_displayLinkMutex.lock(); + bool pending = m_pendingDisplayLinkEvent; + m_pendingDisplayLinkEvent = true; + m_frameTimeStamp = *ts; + m_displayLinkMutex.unlock(); + + if (!pending) + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); +} + +bool QCvDisplayLink::event(QEvent *event) +{ + switch (event->type()){ + case QEvent::User: { + m_displayLinkMutex.lock(); + m_pendingDisplayLinkEvent = false; + CVTimeStamp ts = m_frameTimeStamp; + m_displayLinkMutex.unlock(); + + emit tick(ts); + + return false; + } + break; + default: + break; + } + return QObject::event(event); +} + +QT_END_NAMESPACE + +#include "moc_qcvdisplaylink.cpp" + diff --git a/src/plugins/mediaservices/qt7/qt7.pro b/src/plugins/mediaservices/qt7/qt7.pro new file mode 100644 index 0000000..938bc97 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7.pro @@ -0,0 +1,52 @@ +TARGET = qt7 +include(../../qpluginbase.pri) + +QT += opengl multimedia + +LIBS += -framework AppKit -framework AudioUnit \ + -framework AudioToolbox -framework CoreAudio \ + -framework QuartzCore -framework QTKit + +# The Quicktime framework is only awailable for 32-bit builds, so we +# need to check for this before linking against it. +# QMAKE_MAC_XARCH is not awailable on Tiger, but at the same time, +# we never build for 64-bit architechtures on Tiger either: +contains(QMAKE_MAC_XARCH, no) { + LIBS += -framework QuickTime +} else { + LIBS += -Xarch_i386 -framework QuickTime -Xarch_ppc -framework QuickTime +} + +HEADERS += \ + qt7backend.h \ + qt7playercontrol.h \ + qt7videooutputcontrol.h \ + qt7movieviewoutput.h \ + qt7movievideowidget.h \ + qt7movieviewrenderer.h \ + qt7playersession.h \ + qt7playerservice.h \ + qt7serviceplugin.h \ + qt7movierenderer.h \ + qt7playermetadata.h \ + qcvdisplaylink.h + +OBJECTIVE_SOURCES += \ + qt7backend.mm \ + qt7playersession.mm \ + qt7serviceplugin.mm \ + qt7movieviewoutput.mm \ + qt7movievideowidget.mm \ + qt7movieviewrenderer.mm \ + qt7playermetadata.mm \ + qt7movierenderer.mm \ + qt7playercontrol.mm \ + qt7videooutputcontrol.mm \ + qt7playerservice.mm \ + qcvdisplaylink.mm + + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices +target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices +INSTALLS += target + diff --git a/src/plugins/mediaservices/qt7/qt7backend.h b/src/plugins/mediaservices/qt7/qt7backend.h new file mode 100644 index 0000000..5668965 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7backend.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7BACKEND_H +#define QT7BACKEND_H + +#include + +#ifndef Q_WS_MAC64 +#define QUICKTIME_C_API_AVAILABLE +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class AutoReleasePool +{ +private: + void *pool; +public: + AutoReleasePool(); + ~AutoReleasePool(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7backend.mm b/src/plugins/mediaservices/qt7/qt7backend.mm new file mode 100644 index 0000000..478589b --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7backend.mm @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qt7backend.h" + +#import +#include + + +QT_BEGIN_NAMESPACE + +AutoReleasePool::AutoReleasePool() +{ + pool = (void*)[[NSAutoreleasePool alloc] init]; +} + +AutoReleasePool::~AutoReleasePool() +{ + [(NSAutoreleasePool*)pool release]; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.h b/src/plugins/mediaservices/qt7/qt7movierenderer.h new file mode 100644 index 0000000..4543152 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7MOVIERENDERER_H +#define QT7MOVIERENDERER_H + +#include "qt7backend.h" + +#include +#include + +#include +#include + +#include +#include "qt7videooutputcontrol.h" + +#include +#include + + +QT_BEGIN_HEADER + +class QGLContext; + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieRenderer : public QT7VideoRendererControl +{ +Q_OBJECT +public: + QT7MovieRenderer(QObject *parent = 0); + virtual ~QT7MovieRenderer(); + + void setEnabled(bool); + void setMovie(void *movie); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + QSize nativeSize() const; + +private slots: + void updateVideoFrame(const CVTimeStamp &ts); + +private: + void setupVideoOutput(); + bool createPixelBufferVisualContext(); + bool createGLVisualContext(); + + void *m_movie; + + QMutex m_mutex; + + QCvDisplayLink *m_displayLink; +#ifdef QUICKTIME_C_API_AVAILABLE + QTVisualContextRef m_visualContext; + bool m_usingGLContext; + const QGLContext *m_currentGLContext; + QSize m_pixelBufferContextGeometry; +#endif + QAbstractVideoSurface *m_surface; + QSize m_nativeSize; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movierenderer.mm b/src/plugins/mediaservices/qt7/qt7movierenderer.mm new file mode 100644 index 0000000..8cb0f46 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movierenderer.mm @@ -0,0 +1,441 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movierenderer.h" +#include "qt7playersession.h" +#include "qcvdisplaylink.h" +#include +#include + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class CVGLTextureVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVGLTextureVideoBuffer(CVOpenGLTextureRef buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVOpenGLTextureRetain(m_buffer); + } + + virtual ~CVGLTextureVideoBuffer() + { + CVOpenGLTextureRelease(m_buffer); + } + + QVariant handle() const + { + GLuint id = CVOpenGLTextureGetName(m_buffer); + return QVariant(int(id)); + } + + HandleType handleType() const + { + return GLTextureHandle; + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (numBytes) + *numBytes = 0; + + if (bytesPerLine) + *bytesPerLine = 0; + + m_mode = mode; + return 0; + } + + void unmap() { m_mode = NotMapped; } + +private: + CVOpenGLTextureRef m_buffer; + MapMode m_mode; +}; + + +class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVPixelBufferVideoBuffer(CVPixelBufferRef buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVPixelBufferRetain(m_buffer); + } + + virtual ~CVPixelBufferVideoBuffer() + { + CVPixelBufferRelease(m_buffer); + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + CVPixelBufferLockBaseAddress(m_buffer, 0); + + if (numBytes) + *numBytes = CVPixelBufferGetDataSize(m_buffer); + + if (bytesPerLine) + *bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer); + + m_mode = mode; + + return (uchar*)CVPixelBufferGetBaseAddress(m_buffer); + } else { + return 0; + } + } + + void unmap() + { + if (m_mode != NotMapped) { + m_mode = NotMapped; + CVPixelBufferUnlockBaseAddress(m_buffer, 0); + } + } + +private: + CVPixelBufferRef m_buffer; + MapMode m_mode; +}; + + + +QT7MovieRenderer::QT7MovieRenderer(QObject *parent) + :QT7VideoRendererControl(parent), + m_movie(0), +#ifdef QUICKTIME_C_API_AVAILABLE + m_visualContext(0), + m_usingGLContext(false), + m_currentGLContext(0), +#endif + m_surface(0) +{ + qDebug() << "QT7MovieRenderer"; + + m_displayLink = new QCvDisplayLink(this); + connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp))); +} + + +bool QT7MovieRenderer::createGLVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, cglContext, + cglPixelFormat, NULL, &m_visualContext); + if (err != noErr) + qWarning() << "Could not create visual context (OpenGL)"; + + return (err == noErr); +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + +#ifdef QUICKTIME_C_API_AVAILABLE +static bool DictionarySetValue(CFMutableDictionaryRef dict, CFStringRef key, SInt32 value) +{ + CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value); + + if (number) { + CFDictionarySetValue( dict, key, number ); + CFRelease( number ); + return true; + } + return false; +} +#endif // QUICKTIME_C_API_AVAILABLE + +bool QT7MovieRenderer::createPixelBufferVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + if (m_visualContext) { + QTVisualContextRelease(m_visualContext); + m_visualContext = 0; + } + + m_pixelBufferContextGeometry = m_nativeSize; + + CFMutableDictionaryRef pixelBufferOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + //DictionarySetValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32ARGBPixelFormat ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferWidthKey, m_nativeSize.width() ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferHeightKey, m_nativeSize.height() ); + DictionarySetValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, 16); + //CFDictionarySetValue(pixelBufferOptions, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue); + + CFMutableDictionaryRef visualContextOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(visualContextOptions, kQTVisualContextPixelBufferAttributesKey, pixelBufferOptions); + CFDictionarySetValue(visualContextOptions, kQTVisualContextWorkingColorSpaceKey, CGColorSpaceCreateDeviceRGB()); + + OSStatus err = QTPixelBufferContextCreate(kCFAllocatorDefault, + visualContextOptions, + &m_visualContext); + CFRelease(pixelBufferOptions); + CFRelease(visualContextOptions); + + if (err != noErr) { + qWarning() << "Could not create visual context (PixelBuffer)"; + return false; + } + + return true; +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + + +QT7MovieRenderer::~QT7MovieRenderer() +{ + m_displayLink->stop(); +} + +void QT7MovieRenderer::setupVideoOutput() +{ + AutoReleasePool pool; + + qDebug() << "QT7MovieRenderer::setupVideoOutput" << m_movie; + + if (m_movie == 0 || m_surface == 0) { + m_displayLink->stop(); + return; + } + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + +#ifdef QUICKTIME_C_API_AVAILABLE + bool usedGLContext = m_usingGLContext; + + if (!m_nativeSize.isEmpty()) { + + bool glSupported = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty(); + + //Try rendering using opengl textures first: + if (glSupported) { + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32, QAbstractVideoBuffer::GLTextureHandle); + + if (m_surface->isActive()) + m_surface->stop(); + + qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) { + qDebug() << "failed to start video surface" << m_surface->error(); + glSupported = false; + } else { + m_usingGLContext = true; + } + + } + + if (!glSupported) { + m_usingGLContext = false; + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + + if (m_surface->isActive() && m_surface->surfaceFormat() != format) { + qDebug() << "Surface format was changed, stop the surface."; + m_surface->stop(); + } + + if (!m_surface->isActive()) { + qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) + qDebug() << "failed to start video surface" << m_surface->error(); + } + } + } + + + if (m_visualContext) { + //check if the visual context still can be reused + if (usedGLContext != m_usingGLContext || + (m_usingGLContext && (m_currentGLContext != QGLContext::currentContext())) || + (!m_usingGLContext && (m_pixelBufferContextGeometry != m_nativeSize))) { + QTVisualContextRelease(m_visualContext); + m_visualContext = 0; + } + } + + if (!m_visualContext) { + if (m_usingGLContext) { + qDebug() << "Building OpenGL visual context"; + m_currentGLContext = QGLContext::currentContext(); + if (!createGLVisualContext()) { + qWarning() << "QT7MovieRenderer: failed to create visual context"; + return; + } + } else { + qDebug() << "Building Pixel Buffer visual context"; + if (!createPixelBufferVisualContext()) { + qWarning() << "QT7MovieRenderer: failed to create visual context"; + return; + } + } + } + + // targets a Movie to render into a visual context + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], m_visualContext); + + +#endif + + m_displayLink->start(); +} + +void QT7MovieRenderer::setEnabled(bool) +{ +} + +void QT7MovieRenderer::setMovie(void *movie) +{ + qDebug() << "QT7MovieRenderer::setMovie" << movie; + + if (m_movie == movie) + return; + + QMutexLocker locker(&m_mutex); + +#ifdef QUICKTIME_C_API_AVAILABLE + //ensure the old movie doesn't hold the visual context, otherwise it can't be reused + if (m_movie && m_visualContext) + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], 0); +#endif + + m_movie = movie; + setupVideoOutput(); +} + +QAbstractVideoSurface *QT7MovieRenderer::surface() const +{ + return m_surface; +} + +void QT7MovieRenderer::setSurface(QAbstractVideoSurface *surface) +{ + qDebug() << "Set video surface" << surface; + + if (surface == m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + m_surface = surface; + setupVideoOutput(); +} + + +QSize QT7MovieRenderer::nativeSize() const +{ + return m_nativeSize; +} + +void QT7MovieRenderer::updateVideoFrame(const CVTimeStamp &ts) +{ +#ifdef QUICKTIME_C_API_AVAILABLE + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive() && + m_visualContext && QTVisualContextIsNewImageAvailable(m_visualContext, &ts)) { + + CVImageBufferRef imageBuffer = NULL; + + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, &imageBuffer); + + if (status == noErr && imageBuffer) { + //qDebug() << "render video frame"; + QAbstractVideoBuffer *buffer = 0; + + if (m_usingGLContext) { + buffer = new CVGLTextureVideoBuffer((CVOpenGLTextureRef)imageBuffer); + CVOpenGLTextureRelease((CVOpenGLTextureRef)imageBuffer); + //qDebug() << "render GL video frame" << buffer->handle(); + } else { + buffer = new CVPixelBufferVideoBuffer((CVPixelBufferRef)imageBuffer); + CVPixelBufferRelease((CVPixelBufferRef)imageBuffer); + } + + QVideoFrame frame(buffer, m_nativeSize, QVideoFrame::Format_RGB32); + m_surface->present(frame); + QTVisualContextTask(m_visualContext); + } + } +#else + Q_UNUSED(ts); +#endif +} + +#include "moc_qt7movierenderer.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.h b/src/plugins/mediaservices/qt7/qt7movievideowidget.h new file mode 100644 index 0000000..266dad4 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7MOVIEVIDEOWIDGET_H +#define QT7MOVIEVIDEOWIDGET_H + +#include +#include + +#include +#include + +#include +#include "qt7videooutputcontrol.h" + +#include +#include + + +QT_BEGIN_HEADER + +class GLVideoWidget; + +QT_BEGIN_NAMESPACE + +class QCvDisplayLink; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieVideoWidget : public QT7VideoWidgetControl +{ +Q_OBJECT +public: + QT7MovieVideoWidget(QObject *parent = 0); + virtual ~QT7MovieVideoWidget(); + + void setEnabled(bool); + void setMovie(void *movie); + + QWidget *videoWidget(); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private slots: + void updateVideoFrame(const CVTimeStamp &ts); + +private: + void setupVideoOutput(); + bool createVisualContext(); + + void updateColors(); + + void *m_movie; + GLVideoWidget *m_videoWidget; + + QCvDisplayLink *m_displayLink; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTVisualContextRef m_visualContext; +#endif + + bool m_fullscreen; + QSize m_nativeSize; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movievideowidget.mm b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm new file mode 100644 index 0000000..e1e0162 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movievideowidget.mm @@ -0,0 +1,409 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movievideowidget.h" +#include "qt7playersession.h" +#include "qcvdisplaylink.h" +#include +#include + +#include + +#import + +#include "math.h" + +QT_BEGIN_NAMESPACE + +class GLVideoWidget : public QGLWidget +{ +public: + + GLVideoWidget(QWidget *parent, const QGLFormat &format) + : QGLWidget(format, parent), + m_texRef(0), + m_nativeSize(640,480), + m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + { + setAutoFillBackground(false); + } + + void initializeGL() + { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + } + + void resizeGL(int w, int h) + { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, GLsizei(w), GLsizei(h)); + gluOrtho2D(0, GLsizei(w), 0, GLsizei(h)); + updateGL(); + } + + void paintGL() + { + glClear(GL_COLOR_BUFFER_BIT); + if (!m_texRef) + return; + + glPushMatrix(); + glDisable(GL_CULL_FACE); + GLenum target = CVOpenGLTextureGetTarget(m_texRef); + glEnable(target); + + glBindTexture(target, CVOpenGLTextureGetName(m_texRef)); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2]; + CVOpenGLTextureGetCleanTexCoords(m_texRef, lowerLeft, lowerRight, upperRight, upperLeft); + + glBegin(GL_QUADS); + QRect rect = displayRect(); + glTexCoord2f(lowerLeft[0], lowerLeft[1]); + glVertex2i(rect.topLeft().x(), rect.topLeft().y()); + glTexCoord2f(lowerRight[0], lowerRight[1]); + glVertex2i(rect.topRight().x() + 1, rect.topRight().y()); + glTexCoord2f(upperRight[0], upperRight[1]); + glVertex2i(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1); + glTexCoord2f(upperLeft[0], upperLeft[1]); + glVertex2i(rect.bottomLeft().x(), rect.bottomLeft().y() + 1); + glEnd(); + glPopMatrix(); + } + + void setCVTexture(CVOpenGLTextureRef texRef) + { + if (m_texRef) + CVOpenGLTextureRelease(m_texRef); + + m_texRef = texRef; + + if (m_texRef) + CVOpenGLTextureRetain(m_texRef); + + if (isVisible()) { + makeCurrent(); + paintGL(); + swapBuffers(); + } + } + + QSize sizeHint() const + { + return m_nativeSize; + } + + void setNativeSize(const QSize &size) + { + m_nativeSize = size; + } + + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) + { + if (m_aspectRatioMode != mode) { + m_aspectRatioMode = mode; + update(); + } + } + +private: + QRect displayRect() const + { + QRect displayRect = rect(); + + if (m_aspectRatioMode == QVideoWidget::KeepAspectRatio) { + QSize size = m_nativeSize; + size.scale(displayRect.size(), Qt::KeepAspectRatio); + + displayRect = QRect(QPoint(0, 0), size); + displayRect.moveCenter(rect().center()); + } + return displayRect; + } + + CVOpenGLTextureRef m_texRef; + QSize m_nativeSize; + QVideoWidget::AspectRatioMode m_aspectRatioMode; +}; + +QT7MovieVideoWidget::QT7MovieVideoWidget(QObject *parent) + :QT7VideoWidgetControl(parent), + m_movie(0), + m_videoWidget(0), + m_fullscreen(false), + m_aspectRatioMode(QVideoWidget::KeepAspectRatio), + m_brightness(0), + m_contrast(0), + m_hue(0), + m_saturation(0) +{ + qDebug() << "QT7MovieVideoWidget"; + + QGLFormat format = QGLFormat::defaultFormat(); + format.setSwapInterval(1); // Vertical sync (avoid tearing) + m_videoWidget = new GLVideoWidget(0, format); + + m_displayLink = new QCvDisplayLink(this); + + connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp))); + + if (!createVisualContext()) { + qWarning() << "QT7MovieVideoWidget: failed to create visual context"; + } +} + + +bool QT7MovieVideoWidget::createVisualContext() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoWidget->makeCurrent(); + + AutoReleasePool pool; + CGLContextObj cglContext = CGLGetCurrentContext(); + NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat]; + CGLPixelFormatObj cglPixelFormat = static_cast([nsglPixelFormat CGLPixelFormatObj]); + + CFTypeRef keys[] = { kQTVisualContextWorkingColorSpaceKey }; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CFDictionaryRef textureContextAttributes = CFDictionaryCreate(kCFAllocatorDefault, + (const void **)keys, + (const void **)&colorSpace, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, + cglContext, + cglPixelFormat, + textureContextAttributes, + &m_visualContext); + if (err != noErr) + qWarning() << "Could not create visual context (OpenGL)"; + + + return (err == noErr); +#endif // QUICKTIME_C_API_AVAILABLE + + return false; +} + +QT7MovieVideoWidget::~QT7MovieVideoWidget() +{ + m_displayLink->stop(); + [(QTMovie*)m_movie release]; + delete m_videoWidget; +} + +QWidget *QT7MovieVideoWidget::videoWidget() +{ + return m_videoWidget; +} + +void QT7MovieVideoWidget::setupVideoOutput() +{ + AutoReleasePool pool; + + qDebug() << "QT7MovieVideoWidget::setupVideoOutput" << m_movie; + + if (m_movie == 0) { + m_displayLink->stop(); + return; + } + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + m_videoWidget->setNativeSize(m_nativeSize); + +#ifdef QUICKTIME_C_API_AVAILABLE + // targets a Movie to render into a visual context + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], m_visualContext); +#endif + + m_displayLink->start(); +} + +void QT7MovieVideoWidget::setEnabled(bool) +{ +} + +void QT7MovieVideoWidget::setMovie(void *movie) +{ + if (m_movie == movie) + return; + + if (m_movie) { +#ifdef QUICKTIME_C_API_AVAILABLE + SetMovieVisualContext([(QTMovie*)m_movie quickTimeMovie], nil); +#endif + [(QTMovie*)m_movie release]; + } + + m_movie = movie; + [(QTMovie*)m_movie retain]; + + setupVideoOutput(); +} + +bool QT7MovieVideoWidget::isFullScreen() const +{ + return m_fullscreen; +} + +void QT7MovieVideoWidget::setFullScreen(bool fullScreen) +{ + m_fullscreen = fullScreen; +} + +QSize QT7MovieVideoWidget::nativeSize() const +{ + return m_nativeSize; +} + +QVideoWidget::AspectRatioMode QT7MovieVideoWidget::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QT7MovieVideoWidget::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + m_videoWidget->setAspectRatioMode(mode); +} + +int QT7MovieVideoWidget::brightness() const +{ + return m_brightness; +} + +void QT7MovieVideoWidget::setBrightness(int brightness) +{ + m_brightness = brightness; + updateColors(); +} + +int QT7MovieVideoWidget::contrast() const +{ + return m_contrast; +} + +void QT7MovieVideoWidget::setContrast(int contrast) +{ + m_contrast = contrast; + updateColors(); +} + +int QT7MovieVideoWidget::hue() const +{ + return m_hue; +} + +void QT7MovieVideoWidget::setHue(int hue) +{ + m_hue = hue; + updateColors(); +} + +int QT7MovieVideoWidget::saturation() const +{ + return m_saturation; +} + +void QT7MovieVideoWidget::setSaturation(int saturation) +{ + m_saturation = saturation; + updateColors(); +} + +void QT7MovieVideoWidget::updateColors() +{ +#ifdef QUICKTIME_C_API_AVAILABLE + if (m_movie) { + QTMovie *movie = (QTMovie*)m_movie; + + Float32 value; + value = m_brightness/100.0; + SetMovieVisualBrightness([movie quickTimeMovie], value, 0); + value = pow(2, m_contrast/50.0); + SetMovieVisualContrast([movie quickTimeMovie], value, 0); + value = m_hue/100.0; + SetMovieVisualHue([movie quickTimeMovie], value, 0); + value = 1.0+m_saturation/100.0; + SetMovieVisualSaturation([movie quickTimeMovie], value, 0); + } +#endif +} + +void QT7MovieVideoWidget::updateVideoFrame(const CVTimeStamp &ts) +{ +#ifdef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + // check for new frame + if (m_visualContext && QTVisualContextIsNewImageAvailable(m_visualContext, &ts)) { + CVOpenGLTextureRef currentFrame = NULL; + + // get a "frame" (image buffer) from the Visual Context, indexed by the provided time + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, NULL, &ts, ¤tFrame); + + // the above call may produce a null frame so check for this first + // if we have a frame, then draw it + if (status == noErr && currentFrame) { + //qDebug() << "render video frame"; + m_videoWidget->setCVTexture(currentFrame); + CVOpenGLTextureRelease(currentFrame); + } + QTVisualContextTask(m_visualContext); + } +#else + Q_UNUSED(ts); +#endif +} + +#include "moc_qt7movievideowidget.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movieviewoutput.h b/src/plugins/mediaservices/qt7/qt7movieviewoutput.h new file mode 100644 index 0000000..7f3ff91 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewoutput.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7MOVIEVIEWOUTPUT_H +#define QT7MOVIEVIEWOUTPUT_H + +#include + +#include +#include + +#include +#include "qt7videooutputcontrol.h" + + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieViewOutput : public QT7VideoWindowControl +{ +public: + QT7MovieViewOutput(QObject *parent = 0); + ~QT7MovieViewOutput(); + + void setEnabled(bool); + void setMovie(void *movie); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private: + void setupVideoOutput(); + + void *m_movie; + void *m_movieView; + + WId m_winId; + QRect m_displayRect; + bool m_fullscreen; + QSize m_nativeSize; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm b/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm new file mode 100644 index 0000000..8182797 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewoutput.mm @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movieviewoutput.h" +#include "qt7playersession.h" +#include + + +QT_BEGIN_NAMESPACE + +#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} + +@interface TransparentQTMovieView : QTMovieView +{ +@private + QRect *m_drawRect; + qreal m_brightness, m_contrast, m_saturation, m_hue; +} + +- (TransparentQTMovieView *) init; +- (void) setDrawRect:(QRect &)rect; +- (void) setContrast:(qreal) contrast; +@end + +@implementation TransparentQTMovieView + +- (TransparentQTMovieView *) init +{ + self = [super initWithFrame:NSZeroRect]; + if (self) { + [self setControllerVisible:NO]; + [self setContrast:1.0]; + [self setDelegate:self]; + } + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setContrast:(qreal) contrast +{ + m_hue = 0.0; + m_brightness = 0.0; + m_contrast = contrast; + m_saturation = 1.0; +} + + +- (void) setDrawRect:(QRect &)rect +{ + *m_drawRect = rect; + + NSRect nsrect; + nsrect.origin.x = m_drawRect->x(); + nsrect.origin.y = m_drawRect->y(); + nsrect.size.width = m_drawRect->width(); + nsrect.size.height = m_drawRect->height(); + [self setFrame:nsrect]; +} + +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img +{ + // This method is called from QTMovieView just + // before the image will be drawn. + Q_UNUSED(view); + + if ( !qFuzzyCompare(m_brightness, 0.0) || + !qFuzzyCompare(m_contrast, 1.0) || + !qFuzzyCompare(m_saturation, 1.0)){ + CIFilter *colorFilter = [CIFilter filterWithName:@"CIColorControls"]; + [colorFilter setValue:[NSNumber numberWithFloat:m_brightness] forKey:@"inputBrightness"]; + [colorFilter setValue:[NSNumber numberWithFloat:(m_contrast < 1) ? m_contrast : 1 + ((m_contrast-1)*3)] forKey:@"inputContrast"]; + [colorFilter setValue:[NSNumber numberWithFloat:m_saturation] forKey:@"inputSaturation"]; + [colorFilter setValue:img forKey:@"inputImage"]; + img = [colorFilter valueForKey:@"outputImage"]; + } + + /*if (m_hue){ + CIFilter *colorFilter = [CIFilter filterWithName:@"CIHueAdjust"]; + [colorFilter setValue:[NSNumber numberWithFloat:(m_hue * 3.14)] forKey:@"inputAngle"]; + [colorFilter setValue:img forKey:@"inputImage"]; + img = [colorFilter valueForKey:@"outputImage"]; + }*/ + + return img; +} + + +VIDEO_TRANSPARENT(mouseDown); +VIDEO_TRANSPARENT(mouseDragged); +VIDEO_TRANSPARENT(mouseUp); +VIDEO_TRANSPARENT(mouseMoved); +VIDEO_TRANSPARENT(mouseEntered); +VIDEO_TRANSPARENT(mouseExited); +VIDEO_TRANSPARENT(rightMouseDown); +VIDEO_TRANSPARENT(rightMouseDragged); +VIDEO_TRANSPARENT(rightMouseUp); +VIDEO_TRANSPARENT(otherMouseDown); +VIDEO_TRANSPARENT(otherMouseDragged); +VIDEO_TRANSPARENT(otherMouseUp); +VIDEO_TRANSPARENT(keyDown); +VIDEO_TRANSPARENT(keyUp); +VIDEO_TRANSPARENT(scrollWheel) + +@end + + +QT7MovieViewOutput::QT7MovieViewOutput(QObject *parent) + :QT7VideoWindowControl(parent), + m_movie(0), + m_movieView(0), + m_winId(0), + m_fullscreen(false), + m_aspectRatioMode(QVideoWidget::KeepAspectRatio), + m_brightness(0), + m_contrast(0), + m_hue(0), + m_saturation(0) +{ +} + +QT7MovieViewOutput::~QT7MovieViewOutput() +{ +} + +void QT7MovieViewOutput::setupVideoOutput() +{ + AutoReleasePool pool; + + //qDebug() << "QT7MovieViewOutput::setupVideoOutput" << m_movie << m_winId; + if (m_movie == 0 || m_winId <= 0) + return; + + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue]; + m_nativeSize = QSize(size.width, size.height); + + if (!m_movieView) + m_movieView = [[TransparentQTMovieView alloc] init]; + + [(QTMovieView*)m_movieView setControllerVisible:NO]; + [(QTMovieView*)m_movieView setMovie:(QTMovie*)m_movie]; + + [(NSView *)m_winId addSubview:(QTMovieView*)m_movieView]; + + setDisplayRect(m_displayRect); +} + +void QT7MovieViewOutput::setEnabled(bool) +{ +} + +void QT7MovieViewOutput::setMovie(void *movie) +{ + m_movie = movie; + setupVideoOutput(); +} + +WId QT7MovieViewOutput::winId() const +{ + return m_winId; +} + +void QT7MovieViewOutput::setWinId(WId id) +{ + m_winId = id; + setupVideoOutput(); +} + +QRect QT7MovieViewOutput::displayRect() const +{ + return m_displayRect; +} + +void QT7MovieViewOutput::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + if (m_movieView) { + AutoReleasePool pool; + [(QTMovieView*)m_movieView setPreservesAspectRatio:(m_aspectRatioMode == QVideoWidget::KeepAspectRatio ? YES : NO)]; + [(QTMovieView*)m_movieView setFrame:NSMakeRect(m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height())]; + } + +} + +bool QT7MovieViewOutput::isFullScreen() const +{ + return m_fullscreen; +} + +void QT7MovieViewOutput::setFullScreen(bool fullScreen) +{ + m_fullscreen = fullScreen; + setDisplayRect(m_displayRect); +} + +void QT7MovieViewOutput::repaint() +{ +} + +QSize QT7MovieViewOutput::nativeSize() const +{ + return m_nativeSize; +} + +QVideoWidget::AspectRatioMode QT7MovieViewOutput::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QT7MovieViewOutput::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + setDisplayRect(m_displayRect); +} + +int QT7MovieViewOutput::brightness() const +{ + return m_brightness; +} + +void QT7MovieViewOutput::setBrightness(int brightness) +{ + m_brightness = brightness; +} + +int QT7MovieViewOutput::contrast() const +{ + return m_contrast; +} + +void QT7MovieViewOutput::setContrast(int contrast) +{ + m_contrast = contrast; + [(TransparentQTMovieView*)m_movieView setContrast:(contrast/100.0+1.0)]; +} + +int QT7MovieViewOutput::hue() const +{ + return m_hue; +} + +void QT7MovieViewOutput::setHue(int hue) +{ + m_hue = hue; +} + +int QT7MovieViewOutput::saturation() const +{ + return m_saturation; +} + +void QT7MovieViewOutput::setSaturation(int saturation) +{ + m_saturation = saturation; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h new file mode 100644 index 0000000..6f381f8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7MOVIEVIEWRENDERER_H +#define QT7MOVIEVIEWRENDERER_H + +#include +#include + +#include +#include + +#include +#include "qt7videooutputcontrol.h" +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QVideoFrame; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7MovieViewRenderer : public QT7VideoRendererControl +{ +public: + QT7MovieViewRenderer(QObject *parent = 0); + ~QT7MovieViewRenderer(); + + void setEnabled(bool); + void setMovie(void *movie); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void renderFrame(const QVideoFrame &); + +protected: + bool event(QEvent *event); + +private: + void setupVideoOutput(); + + void *m_movie; + void *m_movieView; + QSize m_nativeSize; + QAbstractVideoSurface *m_surface; + QVideoFrame m_currentFrame; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm new file mode 100644 index 0000000..e08d0f3 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7movieviewrenderer.mm @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#import + +#include "qt7backend.h" + +#include "qt7playercontrol.h" +#include "qt7movieviewrenderer.h" +#include "qt7playersession.h" +#include +#include +#include + +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +class NSBitmapVideoBuffer : public QAbstractVideoBuffer +{ +public: + NSBitmapVideoBuffer(NSBitmapImageRep *buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + [m_buffer retain]; + } + + virtual ~NSBitmapVideoBuffer() + { + [m_buffer release]; + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + if (numBytes) + *numBytes = [m_buffer bytesPerPlane]; + + if (bytesPerLine) + *bytesPerLine = [m_buffer bytesPerRow]; + + m_mode = mode; + + return [m_buffer bitmapData]; + } else { + return 0; + } + } + + void unmap() { m_mode = NotMapped; } + +private: + NSBitmapImageRep *m_buffer; + MapMode m_mode; +}; + + +#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} + +@interface HiddenQTMovieView : QTMovieView +{ +@private + QWidget *m_window; + QT7MovieViewRenderer *m_renderer; +} + +- (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer; +- (void) setRenderer:(QT7MovieViewRenderer *)renderer; +- (void) setDrawRect:(const QRect &)rect; +@end + +@implementation HiddenQTMovieView + +- (HiddenQTMovieView *) initWithRenderer:(QT7MovieViewRenderer *)renderer +{ + self = [super initWithFrame:NSZeroRect]; + if (self) { + [self setControllerVisible:NO]; + [self setDelegate:self]; + + self->m_renderer = renderer; + + self->m_window = new QWidget; + self->m_window->setWindowOpacity(0.0); + self->m_window->show(); + self->m_window->hide(); + + [(NSView *)(self->m_window->winId()) addSubview:self]; + [self setDrawRect:QRect(0,0,1,1)]; + } + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setRenderer:(QT7MovieViewRenderer *)renderer +{ + m_renderer = renderer; +} + +- (void) setDrawRect:(const QRect &)rect +{ + NSRect nsrect; + nsrect.origin.x = rect.x(); + nsrect.origin.y = rect.y(); + nsrect.size.width = rect.width(); + nsrect.size.height = rect.height(); + [self setFrame:nsrect]; +} + +- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img +{ + // This method is called from QTMovieView just + // before the image will be drawn. + Q_UNUSED(view); + if (m_renderer) { + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; + CGRect bounds = [img extent]; + int w = bounds.size.width; + int h = bounds.size.height; + + // Swap red and blue (same as QImage::rgbSwapped, but without copy) + uchar *data = [bitmap bitmapData]; + //qDebug() << data << w << h; + int bytesPerLine = [bitmap bytesPerRow]; + for (int i=0; i> 16) & 0xff) | (*p & 0xff00ff00); + p++; + } + } + + QVideoFrame frame( new NSBitmapVideoBuffer(bitmap), QSize(w,h), QVideoFrame::Format_RGB32 ); + + //static int i=0; + //i++; + //QImage img([bitmap bitmapData], w, h, QImage::Format_RGB32); + //img.save(QString("img%1.jpg").arg(i)); + + [bitmap release]; + + if (m_renderer) + m_renderer->renderFrame(frame); + } + + return img; +} + +// Override this method so that the movie doesn't stop if +// the window becomes invisible +- (void)viewWillMoveToWindow:(NSWindow *)newWindow +{ + Q_UNUSED(newWindow); +} + + +VIDEO_TRANSPARENT(mouseDown); +VIDEO_TRANSPARENT(mouseDragged); +VIDEO_TRANSPARENT(mouseUp); +VIDEO_TRANSPARENT(mouseMoved); +VIDEO_TRANSPARENT(mouseEntered); +VIDEO_TRANSPARENT(mouseExited); +VIDEO_TRANSPARENT(rightMouseDown); +VIDEO_TRANSPARENT(rightMouseDragged); +VIDEO_TRANSPARENT(rightMouseUp); +VIDEO_TRANSPARENT(otherMouseDown); +VIDEO_TRANSPARENT(otherMouseDragged); +VIDEO_TRANSPARENT(otherMouseUp); +VIDEO_TRANSPARENT(keyDown); +VIDEO_TRANSPARENT(keyUp); +VIDEO_TRANSPARENT(scrollWheel) + +@end + + +QT7MovieViewRenderer::QT7MovieViewRenderer(QObject *parent) + :QT7VideoRendererControl(parent), + m_movie(0), + m_movieView(0), + m_surface(0) +{ +} + +QT7MovieViewRenderer::~QT7MovieViewRenderer() +{ + [(HiddenQTMovieView*)m_movieView setRenderer:0]; + + QMutexLocker locker(&m_mutex); + m_currentFrame = QVideoFrame(); + [(HiddenQTMovieView*)m_movieView release]; +} + +void QT7MovieViewRenderer::setupVideoOutput() +{ + AutoReleasePool pool; + + qDebug() << "QT7MovieViewRenderer::setupVideoOutput" << m_movie << m_surface; + + HiddenQTMovieView *movieView = (HiddenQTMovieView*)m_movieView; + + if (movieView && !m_movie) { + [movieView setMovie:nil]; + } + + if (m_movie) { + NSSize size = [[(QTMovie*)m_movie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; + + m_nativeSize = QSize(size.width, size.height); + + if (!movieView) { + movieView = [[HiddenQTMovieView alloc] initWithRenderer:this]; + m_movieView = movieView; + [movieView setControllerVisible:NO]; + } + + [movieView setMovie:(QTMovie*)m_movie]; + //[movieView setDrawRect:QRect(QPoint(0,0), m_nativeSize)]; + } + + if (m_surface && !m_nativeSize.isEmpty()) { + QVideoSurfaceFormat format(m_nativeSize, QVideoFrame::Format_RGB32); + + if (m_surface->isActive() && m_surface->surfaceFormat() != format) { + qDebug() << "Surface format was changed, stop the surface."; + m_surface->stop(); + } + + if (!m_surface->isActive()) { + qDebug() << "Starting the surface with format" << format; + if (!m_surface->start(format)) + qDebug() << "failed to start video surface" << m_surface->error(); + } + } +} + +void QT7MovieViewRenderer::setEnabled(bool) +{ +} + +void QT7MovieViewRenderer::setMovie(void *movie) +{ + if (movie == m_movie) + return; + + QMutexLocker locker(&m_mutex); + m_movie = movie; + setupVideoOutput(); +} + +QAbstractVideoSurface *QT7MovieViewRenderer::surface() const +{ + return m_surface; +} + +void QT7MovieViewRenderer::setSurface(QAbstractVideoSurface *surface) +{ + if (surface == m_surface) + return; + + QMutexLocker locker(&m_mutex); + + if (m_surface && m_surface->isActive()) + m_surface->stop(); + + m_surface = surface; + setupVideoOutput(); +} + +void QT7MovieViewRenderer::renderFrame(const QVideoFrame &frame) +{ + { + QMutexLocker locker(&m_mutex); + m_currentFrame = frame; + } + + qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority); +} + +bool QT7MovieViewRenderer::event(QEvent *event) +{ + if (event->type() == QEvent::User) { + QMutexLocker locker(&m_mutex); + if (m_surface->isActive()) + m_surface->present(m_currentFrame); + } + + return QT7VideoRendererControl::event(event); +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7playercontrol.h b/src/plugins/mediaservices/qt7/qt7playercontrol.h new file mode 100644 index 0000000..da86949 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playercontrol.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERCONTROL_H +#define QT7PLAYERCONTROL_H + +#include +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; +class QMediaPlaylist; +class QMediaPlaylistNavigator; + +class QT7PlayerControl : public QMediaPlayerControl +{ +Q_OBJECT +public: + QT7PlayerControl(QObject *parent = 0); + ~QT7PlayerControl(); + + void setSession(QT7PlayerSession *session); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void seekRangeChanged(const QPair&); + void playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +private: + QT7PlayerSession *m_session; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playercontrol.mm b/src/plugins/mediaservices/qt7/qt7playercontrol.mm new file mode 100644 index 0000000..b74f434 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playercontrol.mm @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qt7playercontrol.h" +#include "qt7playersession.h" + +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +QT7PlayerControl::QT7PlayerControl(QObject *parent) + : QMediaPlayerControl(parent) +{ +} + +QT7PlayerControl::~QT7PlayerControl() +{ +} + +void QT7PlayerControl::setSession(QT7PlayerSession *session) +{ + m_session = session; + + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); +} + +qint64 QT7PlayerControl::position() const +{ + return m_session->position(); +} + +qint64 QT7PlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QT7PlayerControl::state() const +{ + return m_session->state(); +} + +QMediaPlayer::MediaStatus QT7PlayerControl::mediaStatus() const +{ + return m_session->mediaStatus(); +} + +int QT7PlayerControl::bufferStatus() const +{ + return m_session->bufferStatus(); +} + +int QT7PlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QT7PlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QT7PlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QT7PlayerControl::availablePlaybackRanges() const +{ + return isSeekable() ? QMediaTimeRange(0, duration()) : QMediaTimeRange(); +} + +qreal QT7PlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QT7PlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QT7PlayerControl::setPosition(qint64 pos) +{ + m_session->setPosition(pos); +} + +void QT7PlayerControl::play() +{ + m_session->play(); +} + +void QT7PlayerControl::pause() +{ + m_session->pause(); +} + +void QT7PlayerControl::stop() +{ + m_session->stop(); +} + +void QT7PlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QT7PlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QT7PlayerControl::media() const +{ + return m_session->media(); +} + +const QIODevice *QT7PlayerControl::mediaStream() const +{ + return m_session->mediaStream(); +} + +void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + m_session->setMedia(content, stream); + + emit mediaChanged(content); +} + + +bool QT7PlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + +#include "moc_qt7playercontrol.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7playermetadata.h b/src/plugins/mediaservices/qt7/qt7playermetadata.h new file mode 100644 index 0000000..9aa9887 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playermetadata.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERMETADATACONTROL_H +#define QT7PLAYERMETADATACONTROL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; + +class QT7PlayerMetaDataControl : public QMetaDataControl +{ + Q_OBJECT +public: + QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent); + virtual ~QT7PlayerMetaDataControl(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QT7PlayerSession *m_session; + QMap m_tags; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playermetadata.mm b/src/plugins/mediaservices/qt7/qt7playermetadata.mm new file mode 100644 index 0000000..96b7a68 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playermetadata.mm @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qt7backend.h" +#include "qt7playermetadata.h" +#include "qt7playersession.h" +#include + +#import + +#ifdef QUICKTIME_C_API_AVAILABLE + #include + #undef check // avoid name clash; +#endif + +QT_BEGIN_NAMESPACE + +QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) + :QMetaDataControl(parent), m_session(session) +{ +} + +QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() +{ +} + +bool QT7PlayerMetaDataControl::isMetaDataAvailable() const +{ + return !m_tags.isEmpty(); +} + +bool QT7PlayerMetaDataControl::isWritable() const +{ + return false; +} + +QVariant QT7PlayerMetaDataControl::metaData(QtMedia::MetaData key) const +{ + return m_tags.value(key); +} + +void QT7PlayerMetaDataControl::setMetaData(QtMedia::MetaData key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QList QT7PlayerMetaDataControl::availableMetaData() const +{ + return m_tags.keys(); +} + +QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const +{ + Q_UNUSED(key); + return QVariant(); +} + +void QT7PlayerMetaDataControl::setExtendedMetaData(const QString &key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +#ifdef QUICKTIME_C_API_AVAILABLE + +static QString stripCopyRightSymbol(const QString &key) +{ + return key.right(key.length()-1); +} + +static QString convertQuickTimeKeyToUserKey(const QString &key) +{ + if (key == QLatin1String("com.apple.quicktime.displayname")) + return QLatin1String("nam"); + else if (key == QLatin1String("com.apple.quicktime.album")) + return QLatin1String("alb"); + else if (key == QLatin1String("com.apple.quicktime.artist")) + return QLatin1String("ART"); + else + return QLatin1String("???"); +} + +static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, + QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) +{ + QTPropertyValueType type; + ByteCount propSize; + UInt32 propFlags; + OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); + + + *value = malloc(propSize); + + err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); + + if (type == 'code' || type == 'itsk' || type == 'itlk') { + // convert from native endian to big endian + OSTypePtr pType = (OSTypePtr)*value; + *pType = EndianU32_NtoB(*pType); + } + + return err; +} + +static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) +{ + QTPropertyValuePtr value = 0; + ByteCount ignore = 0; + OSStatus err = readMetaValue( + metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); + + UInt32 type = *((UInt32 *) value); + if (value) + free(value); + return type; +} + +static QString cFStringToQString(CFStringRef str) +{ + if(!str) + return QString(); + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast(chars), length); + + QVarLengthArray buffer(length); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); + return QString(reinterpret_cast(buffer.constData()), length); +} + + +static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) +{ + QTPropertyValuePtr value = 0; + ByteCount size = 0; + OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); + + QString string; + UInt32 dataType = getMetaType(metaDataRef, item); + switch (dataType){ + case kQTMetaDataTypeUTF8: + case kQTMetaDataTypeMacEncodedText: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); + break; + case kQTMetaDataTypeUTF16BE: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); + break; + default: + break; + } + + if (value) + free(value); + return string; +} + + +static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap &result) +{ + QTMetaDataItem item = kQTMetaDataItemUninitialized; + OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + while (err == noErr){ + QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); + if (format == kQTMetaDataStorageFormatQuickTime) + key = convertQuickTimeKeyToUserKey(key); + else + key = stripCopyRightSymbol(key); + + if (!result.contains(key)){ + QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); + result.insert(key, val); + } + err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + } +} +#endif + + +void QT7PlayerMetaDataControl::updateTags() +{ + bool wasEmpty = m_tags.isEmpty(); + m_tags.clear(); + + QTMovie *movie = (QTMovie*)m_session->movie(); + + if (movie) { + QMultiMap metaMap; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTMetaDataRef metaDataRef; + OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); + + readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); +#else + NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; + metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); +#endif // QUICKTIME_C_API_AVAILABLE + + m_tags.insert(QtMedia::AlbumArtist, metaMap.value(QLatin1String("ART"))); + m_tags.insert(QtMedia::AlbumTitle, metaMap.value(QLatin1String("alb"))); + m_tags.insert(QtMedia::Title, metaMap.value(QLatin1String("nam"))); + m_tags.insert(QtMedia::Date, metaMap.value(QLatin1String("day"))); + m_tags.insert(QtMedia::Genre, metaMap.value(QLatin1String("gnre"))); + m_tags.insert(QtMedia::TrackNumber, metaMap.value(QLatin1String("trk"))); + m_tags.insert(QtMedia::Description, metaMap.value(QLatin1String("des"))); + } + + if (!wasEmpty || !m_tags.isEmpty()) + emit metaDataChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qt7playermetadata.cpp" diff --git a/src/plugins/mediaservices/qt7/qt7playerservice.h b/src/plugins/mediaservices/qt7/qt7playerservice.h new file mode 100644 index 0000000..d4b30b8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playerservice.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERSERVICE_H +#define QT7PLAYERSERVICE_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerControl; +class QT7PlayerMetaDataControl; +class QT7VideoOutputControl; +class QT7VideoWindowControl; +class QT7VideoWidgetControl; +class QT7VideoRendererControl; +class QT7VideoOutput; +class QT7PlayerSession; + +class QT7PlayerService : public QMediaService +{ +Q_OBJECT +public: + QT7PlayerService(QObject *parent = 0); + ~QT7PlayerService(); + + QMediaControl *control(const char *name) const; + +private slots: + void updateVideoOutput(); + +private: + QT7PlayerSession *m_session; + QT7PlayerControl *m_control; + QT7VideoOutputControl *m_videoOutputControl; + QT7VideoWindowControl *m_videoWidnowControl; + QT7VideoWidgetControl *m_videoWidgetControl; + QT7VideoRendererControl *m_videoRendererControl; + QT7PlayerMetaDataControl *m_playerMetaDataControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playerservice.mm b/src/plugins/mediaservices/qt7/qt7playerservice.mm new file mode 100644 index 0000000..df15fa8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playerservice.mm @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 +#include +#include + +#include "qt7backend.h" +#include "qt7playerservice.h" +#include "qt7playercontrol.h" +#include "qt7playersession.h" +#include "qt7videooutputcontrol.h" +#include "qt7movieviewoutput.h" +#include "qt7movieviewrenderer.h" +#include "qt7movierenderer.h" +#include "qt7movievideowidget.h" +#include "qt7playermetadata.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QT7PlayerService::QT7PlayerService(QObject *parent): + QMediaService(parent) +{ + m_session = new QT7PlayerSession; + + m_control = new QT7PlayerControl(this); + m_control->setSession(m_session); + + m_playerMetaDataControl = new QT7PlayerMetaDataControl(m_session, this); + connect(m_control, SIGNAL(mediaChanged(QMediaContent)), m_playerMetaDataControl, SLOT(updateTags())); + + m_videoOutputControl = new QT7VideoOutputControl(this); + + m_videoWidnowControl = 0; + m_videoWidgetControl = 0; + m_videoRendererControl = 0; + +#if defined(QT_MAC_USE_COCOA) + m_videoWidnowControl = new QT7MovieViewOutput(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::WindowOutput); + qDebug() << "Using cocoa"; +#endif + +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoRendererControl = new QT7MovieRenderer(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); + + m_videoWidgetControl = new QT7MovieVideoWidget(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::WidgetOutput); + qDebug() << "QuickTime C API is available"; +#else + m_videoRendererControl = new QT7MovieViewRenderer(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); + qDebug() << "QuickTime C API is not available"; +#endif + + + connect(m_videoOutputControl, SIGNAL(videoOutputChanged(QVideoOutputControl::Output)), + this, SLOT(updateVideoOutput())); +} + +QT7PlayerService::~QT7PlayerService() +{ +} + +QMediaControl *QT7PlayerService::control(const char *name) const +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return m_videoOutputControl; + + if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return m_videoWidnowControl; + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return m_videoRendererControl; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + return m_videoWidgetControl; + + if (qstrcmp(name, QMetaDataControl_iid) == 0) + return m_playerMetaDataControl; + + return 0; +} + +void QT7PlayerService::updateVideoOutput() +{ + qDebug() << "QT7PlayerService::updateVideoOutput" << m_videoOutputControl->output(); + + switch (m_videoOutputControl->output()) { + case QVideoOutputControl::WindowOutput: + m_session->setVideoOutput(m_videoWidnowControl); + break; + case QVideoOutputControl::RendererOutput: + m_session->setVideoOutput(m_videoRendererControl); + break; + case QVideoOutputControl::WidgetOutput: + m_session->setVideoOutput(m_videoWidgetControl); + break; + default: + m_session->setVideoOutput(0); + } +} + +QT_END_NAMESPACE + +#include "moc_qt7playerservice.cpp" diff --git a/src/plugins/mediaservices/qt7/qt7playersession.h b/src/plugins/mediaservices/qt7/qt7playersession.h new file mode 100644 index 0000000..55505ee --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playersession.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERSESSION_H +#define QT7PLAYERSESSION_H + +#include +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7VideoOutput; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7PlayerSession : public QObject +{ +Q_OBJECT +public: + QT7PlayerSession(QObject *parent = 0); + ~QT7PlayerSession(); + + void *movie() const; + + void setControl(QT7PlayerControl *control); + void setVideoOutput(QT7VideoOutput *output); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + + void processEOS(); + +signals: + void positionChanged(qint64 position); + void durationChanged(qint64 duration); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void error(int error, const QString &errorString); + +private: + void *m_QTMovie; + void *m_movieObserver; + + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QIODevice *m_mediaStream; + QMediaContent m_resources; + + QT7VideoOutput *m_videoOutput; + + mutable qint64 m_currentTime; + + bool m_muted; + int m_volume; + qreal m_rate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7playersession.mm b/src/plugins/mediaservices/qt7/qt7playersession.mm new file mode 100644 index 0000000..3131a90 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7playersession.mm @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#import +#import + +#include "qt7backend.h" + +#include "qt7playersession.h" +#include "qt7playercontrol.h" +#include "qt7videooutputcontrol.h" + +#include + +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +@interface QTMovieObserver : NSObject +{ +@private + QT7PlayerSession *m_session; + QTMovie *m_movie; +} + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; +- (void) setMovie:(QTMovie *)movie; +- (void) processEOS:(NSNotification *)notification; +@end + +@implementation QTMovieObserver + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session +{ + if (!(self = [super init])) + return nil; + + self->m_session = session; + return self; +} + +- (void) setMovie:(QTMovie *)movie +{ + if (m_movie == movie) + return; + + if (m_movie) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [m_movie release]; + } + + m_movie = movie; + + if (movie) { + [[NSNotificationCenter defaultCenter] addObserver: self selector: + @selector(processEOS:) name: QTMovieDidEndNotification object: m_movie]; + + [movie retain]; + } +} + +- (void) processEOS:(NSNotification *)notification +{ + Q_UNUSED(notification); + m_session->processEOS(); +} + +@end + +static CFStringRef qString2CFStringRef(const QString &string) +{ + return CFStringCreateWithCharacters(0, reinterpret_cast(string.unicode()), + string.length()); +} + +QT7PlayerSession::QT7PlayerSession(QObject *parent) + : QObject(parent) + , m_QTMovie(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_mediaStream(0) + , m_videoOutput(0) + , m_muted(false) + , m_volume(100) + , m_rate(1.0) +{ + m_movieObserver = [[QTMovieObserver alloc] initWithPlayerSession:this]; +} + +QT7PlayerSession::~QT7PlayerSession() +{ + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + [(QTMovieObserver*)m_movieObserver release]; +} + +void *QT7PlayerSession::movie() const +{ + return m_QTMovie; +} + +void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) +{ + if (m_videoOutput == output) + return; + + qDebug() << "set output" << output; + + if (m_videoOutput) { + m_videoOutput->setEnabled(false); + m_videoOutput->setMovie(0); + } + + m_videoOutput = output; + + if (m_videoOutput) { + m_videoOutput->setEnabled(m_QTMovie != 0); + m_videoOutput->setMovie(m_QTMovie); + } +} + + +qint64 QT7PlayerSession::position() const +{ + if (!m_QTMovie || m_state == QMediaPlayer::PausedState) + return m_currentTime; + + AutoReleasePool pool; + + QTTime qtTime = [(QTMovie*)m_QTMovie currentTime]; + quint64 t = static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); + m_currentTime = t; + + return m_currentTime; +} + +qint64 QT7PlayerSession::duration() const +{ + if (!m_QTMovie) + return 0; + + AutoReleasePool pool; + + QTTime qtTime = [(QTMovie*)m_QTMovie duration]; + + return static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +QMediaPlayer::State QT7PlayerSession::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QT7PlayerSession::mediaStatus() const +{ + return m_mediaStatus; +} + +int QT7PlayerSession::bufferStatus() const +{ + return 100; +} + +int QT7PlayerSession::volume() const +{ + return m_volume; +} + +bool QT7PlayerSession::isMuted() const +{ + return m_muted; +} + +bool QT7PlayerSession::isSeekable() const +{ + return true; +} + +qreal QT7PlayerSession::playbackRate() const +{ + return m_rate; +} + +void QT7PlayerSession::setPlaybackRate(qreal rate) +{ + if (qFuzzyCompare(m_rate, rate)) + return; + + m_rate = rate; + + if (m_QTMovie && m_state == QMediaPlayer::PlayingState) { + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; + } +} + +void QT7PlayerSession::setPosition(qint64 pos) +{ + if ( !isSeekable() || pos == position()) + return; + + AutoReleasePool pool; + + pos = qMin(pos, duration()); + + QTTime newQTTime = [(QTMovie*)m_QTMovie currentTime]; + newQTTime.timeValue = (pos / 1000.0f) * newQTTime.timeScale; + [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; +} + +void QT7PlayerSession::play() +{ + m_state = QMediaPlayer::PlayingState; + + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; + + emit stateChanged(m_state); +} + +void QT7PlayerSession::pause() +{ + m_state = QMediaPlayer::PausedState; + + [(QTMovie*)m_QTMovie setRate:0]; + + emit stateChanged(m_state); +} + +void QT7PlayerSession::stop() +{ + m_state = QMediaPlayer::StoppedState; + + [(QTMovie*)m_QTMovie setRate:0]; + setPosition(0); + + if (m_state == QMediaPlayer::StoppedState) + emit stateChanged(m_state); +} + +void QT7PlayerSession::setVolume(int volume) +{ + if (m_QTMovie) { + m_volume = volume; + [(QTMovie*)m_QTMovie setVolume:(volume/100.0f)]; + } +} + +void QT7PlayerSession::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + + if (m_QTMovie) + [(QTMovie*)m_QTMovie setMuted:m_muted]; + + emit mutedChanged(muted); + } +} + +QMediaContent QT7PlayerSession::media() const +{ + return m_resources; +} + +const QIODevice *QT7PlayerSession::mediaStream() const +{ + return m_mediaStream; +} + +void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) +{ + AutoReleasePool pool; + + if (m_QTMovie) { + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + + if (m_videoOutput) { + m_videoOutput->setEnabled(false); + m_videoOutput->setMovie(0); + } + + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + } + + m_resources = content; + m_mediaStream = stream; + + QUrl url; + + if (!content.isNull()) + url = content.canonicalUrl(); + else + return; + + NSError *err = 0; + QTDataReference *dataRef = 0; + + if ( url.scheme() == "file" ) { + NSString *nsFileName = (NSString *)qString2CFStringRef( url.toLocalFile() ); + dataRef = [QTDataReference dataReferenceWithReferenceToFile:nsFileName]; + } else { + NSString *urlString = (NSString *)qString2CFStringRef( url.toString() ); + NSURL *url = [NSURL URLWithString: urlString]; + dataRef = [QTDataReference dataReferenceWithReferenceToURL:url]; + } + + NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: + dataRef, QTMovieDataReferenceAttribute, + [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, + [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, + [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, + [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, + nil]; + + m_QTMovie = [[QTMovie movieWithAttributes:attr error:&err] retain]; + + if (err) { + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + QString description = QString::fromUtf8([[err localizedDescription] UTF8String]); + + qDebug() << "QT7PlayerSession::setMedia error" << description; + emit error(QMediaPlayer::FormatError, description ); + } else { + [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; + + if (m_videoOutput) { + m_videoOutput->setEnabled(true); + m_videoOutput->setMovie(m_QTMovie); + } + + emit durationChanged(duration()); + emit videoAvailableChanged(isVideoAvailable()); + + [(QTMovie*)m_QTMovie setMuted:m_muted]; + setVolume(m_volume); + } +} + +bool QT7PlayerSession::isVideoAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES; +} + +void QT7PlayerSession::processEOS() +{ + m_mediaStatus = QMediaPlayer::EndOfMedia; + emit stateChanged(m_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(m_mediaStatus); +} + +#include "moc_qt7playersession.cpp" + +QT_END_NAMESPACE + diff --git a/src/plugins/mediaservices/qt7/qt7serviceplugin.h b/src/plugins/mediaservices/qt7/qt7serviceplugin.h new file mode 100644 index 0000000..c5afda1 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7SERVICEPLUGIN_H +#define QT7SERVICEPLUGIN_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7ServicePlugin : public QMediaServiceProviderPlugin +{ +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERSERVICEPLUGIN_H diff --git a/src/plugins/mediaservices/qt7/qt7serviceplugin.mm b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm new file mode 100644 index 0000000..49ae8e0 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 +#include + +#include "qt7serviceplugin.h" +#include "qt7playerservice.h" + +#include + +QT_BEGIN_NAMESPACE + +QStringList QT7ServicePlugin::keys() const +{ + return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); +} + +QMediaService* QT7ServicePlugin::create(QString const& key) +{ + qDebug() << "QT7ServicePlugin::create" << key; + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new QT7PlayerService; + + qDebug() << "unsupported key:" << key; + return 0; +} + +void QT7ServicePlugin::release(QMediaService *service) +{ + delete service; +} + +Q_EXPORT_PLUGIN2(qt7_serviceplugin, QT7ServicePlugin); + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h new file mode 100644 index 0000000..2faf6bb --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7VIDEOOUTPUTCONTROL_H +#define QT7VIDEOOUTPUTCONTROL_H + +#include + +#include +#include +#include +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerSession; +class QT7PlayerService; + + +class QT7VideoOutput { +public: + virtual ~QT7VideoOutput() {} + virtual void setEnabled(bool enabled) = 0; + virtual void setMovie(void *movie) = 0; +}; + +class QT7VideoWindowControl : public QVideoWindowControl, public QT7VideoOutput +{ +public: + virtual ~QT7VideoWindowControl() {} + +protected: + QT7VideoWindowControl(QObject *parent) + :QVideoWindowControl(parent) + {} +}; + +class QT7VideoRendererControl : public QVideoRendererControl, public QT7VideoOutput +{ +public: + virtual ~QT7VideoRendererControl() {} + +protected: + QT7VideoRendererControl(QObject *parent) + :QVideoRendererControl(parent) + {} +}; + +class QT7VideoWidgetControl : public QVideoWidgetControl, public QT7VideoOutput +{ +public: + virtual ~QT7VideoWidgetControl() {} + +protected: + QT7VideoWidgetControl(QObject *parent) + :QVideoWidgetControl(parent) + {} +}; + +class QT7VideoOutputControl : public QVideoOutputControl +{ +Q_OBJECT +public: + QT7VideoOutputControl(QObject *parent = 0); + ~QT7VideoOutputControl(); + + void setSession(QT7PlayerSession *session); + + QList availableOutputs() const; + void enableOutput(Output); + + Output output() const; + void setOutput(Output output); + +signals: + void videoOutputChanged(QVideoOutputControl::Output); + +private: + QT7PlayerSession *m_session; + Output m_output; + QList m_outputs; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm new file mode 100644 index 0000000..a468431 --- /dev/null +++ b/src/plugins/mediaservices/qt7/qt7videooutputcontrol.mm @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qt7playercontrol.h" +#include "qt7videooutputcontrol.h" +#include "qt7playersession.h" +#include + +QT_BEGIN_NAMESPACE + +QT7VideoOutputControl::QT7VideoOutputControl(QObject *parent) + :QVideoOutputControl(parent), + m_session(0), + m_output(QVideoOutputControl::NoOutput) +{ +} + +QT7VideoOutputControl::~QT7VideoOutputControl() +{ +} + +void QT7VideoOutputControl::setSession(QT7PlayerSession *session) +{ + m_session = session; +} + +QList QT7VideoOutputControl::availableOutputs() const +{ + return m_outputs; +} + +void QT7VideoOutputControl::enableOutput(QVideoOutputControl::Output output) +{ + if (!m_outputs.contains(output)) + m_outputs.append(output); +} + +QVideoOutputControl::Output QT7VideoOutputControl::output() const +{ + return m_output; +} + +void QT7VideoOutputControl::setOutput(Output output) +{ + if (m_output != output) { + m_output = output; + emit videoOutputChanged(m_output); + } + +} + +QT_END_NAMESPACE + +#include "moc_qt7videooutputcontrol.cpp" + diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 004b816..5eca0f4 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -11,4 +11,5 @@ embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers !win32:!embedded:!mac:!symbian:SUBDIRS *= inputmethods symbian:SUBDIRS += s60 contains(QT_CONFIG, phonon): SUBDIRS *= phonon -contains(QT_CONFIG, multimedia): SUBDIRS *= audio +contains(QT_CONFIG, multimedia): SUBDIRS *= audio mediaservices + diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 4215e97..50ab902 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -294,6 +294,17 @@ SUBDIRS += \ qaudioformat \ qaudiooutput \ qaudioinput \ + qmediacontent \ + qmediaobject \ + qmediaplayer \ + qmediaplaylist \ + qmediaplaylistnavigator \ + qmediapluginloader \ + qmediaresource \ + qmediaservice \ + qmediaserviceprovider \ + qmediatimerange \ + qvideowidget \ qspinbox \ qsplitter \ qsql \ diff --git a/tests/auto/qmediacontent/qmediacontent.pro b/tests/auto/qmediacontent/qmediacontent.pro new file mode 100644 index 0000000..f7884f6 --- /dev/null +++ b/tests/auto/qmediacontent/qmediacontent.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES += tst_qmediacontent.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediacontent/tst_qmediacontent.cpp b/tests/auto/qmediacontent/tst_qmediacontent.cpp new file mode 100644 index 0000000..4857672 --- /dev/null +++ b/tests/auto/qmediacontent/tst_qmediacontent.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include + + +class tst_QMediaContent : public QObject +{ + Q_OBJECT + +private slots: + void testNull(); + void testUrlCtor(); + void testResourceCtor(); + void testResourceListCtor(); + void testCopy(); + void testAssignment(); + void testEquality(); + void testResources(); +}; + +void tst_QMediaContent::testNull() +{ + QMediaContent media; + + QCOMPARE(media.isNull(), true); + QCOMPARE(media.canonicalUrl(), QUrl()); + QCOMPARE(media.canonicalResource(), QMediaResource()); + QCOMPARE(media.resources(), QMediaResourceList()); +} + +void tst_QMediaContent::testUrlCtor() +{ + QMediaContent media(QUrl("http://example.com/movie.mov")); + + QCOMPARE(media.canonicalUrl(), QUrl("http://example.com/movie.mov")); + QCOMPARE(media.canonicalResource().url(), QUrl("http://example.com/movie.mov")); +} + +void tst_QMediaContent::testResourceCtor() +{ + QMediaContent media(QMediaResource(QUrl("http://example.com/movie.mov"))); + + QCOMPARE(media.canonicalResource(), QMediaResource(QUrl("http://example.com/movie.mov"))); +} + +void tst_QMediaContent::testResourceListCtor() +{ + QMediaResourceList resourceList; + resourceList << QMediaResource(QUrl("http://example.com/movie.mov")); + + QMediaContent media(resourceList); + + QCOMPARE(media.canonicalUrl(), QUrl("http://example.com/movie.mov")); + QCOMPARE(media.canonicalResource().url(), QUrl("http://example.com/movie.mov")); +} + +void tst_QMediaContent::testCopy() +{ + QMediaContent media1(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media2(media1); + + QVERIFY(media1 == media2); +} + +void tst_QMediaContent::testAssignment() +{ + QMediaContent media1(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media2; + QMediaContent media3; + + media2 = media1; + QVERIFY(media2 == media1); + + media2 = media3; + QVERIFY(media2 == media3); +} + +void tst_QMediaContent::testEquality() +{ + QMediaContent media1; + QMediaContent media2; + QMediaContent media3(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media4(QMediaResource(QUrl("http://example.com/movie.mov"))); + QMediaContent media5(QMediaResource(QUrl("file:///some/where/over/the/rainbow.mp3"))); + + // null == null + QCOMPARE(media1 == media2, true); + QCOMPARE(media1 != media2, false); + + // null != something + QCOMPARE(media1 == media3, false); + QCOMPARE(media1 != media3, true); + + // equiv + QCOMPARE(media3 == media4, true); + QCOMPARE(media3 != media4, false); + + // not equiv + QCOMPARE(media4 == media5, false); + QCOMPARE(media4 != media5, true); +} + +void tst_QMediaContent::testResources() +{ + QMediaResourceList resourceList; + + resourceList << QMediaResource(QUrl("http://example.com/movie-main.mov")); + resourceList << QMediaResource(QUrl("http://example.com/movie-big.mov")); + QMediaContent media(resourceList); + + QMediaResourceList res = media.resources(); + QCOMPARE(res.size(), 2); + QCOMPARE(res[0], QMediaResource(QUrl("http://example.com/movie-main.mov"))); + QCOMPARE(res[1], QMediaResource(QUrl("http://example.com/movie-big.mov"))); +} + +QTEST_MAIN(tst_QMediaContent) + +#include "tst_qmediacontent.moc" diff --git a/tests/auto/qmediaobject/qmediaobject.pro b/tests/auto/qmediaobject/qmediaobject.pro new file mode 100644 index 0000000..e59bfdc --- /dev/null +++ b/tests/auto/qmediaobject/qmediaobject.pro @@ -0,0 +1,4 @@ +load(qttest_p4) + +SOURCES += tst_qmediaobject.cpp +QT = core multimedia diff --git a/tests/auto/qmediaobject/tst_qmediaobject.cpp b/tests/auto/qmediaobject/tst_qmediaobject.cpp new file mode 100644 index 0000000..0370fff --- /dev/null +++ b/tests/auto/qmediaobject/tst_qmediaobject.cpp @@ -0,0 +1,549 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include + +#include +#include +#include + + +class tst_QMediaObject : public QObject +{ + Q_OBJECT + +private slots: + void propertyWatch(); + void notifySignals_data(); + void notifySignals(); + void notifyInterval_data(); + void notifyInterval(); + + void nullMetaDataControl(); + void isMetaDataAvailable(); + void isWritable(); + void metaDataChanged(); + void metaData_data(); + void metaData(); + void setMetaData_data(); + void setMetaData(); + void extendedMetaData_data() { metaData_data(); } + void extendedMetaData(); + void setExtendedMetaData_data() { extendedMetaData_data(); } + void setExtendedMetaData(); + + +private: + void setupNotifyTests(); +}; + +class QtTestMetaDataProvider : public QMetaDataControl +{ + Q_OBJECT +public: + QtTestMetaDataProvider(QObject *parent = 0) + : QMetaDataControl(parent) + , m_available(false) + , m_writable(false) + { + } + + bool isMetaDataAvailable() const { return m_available; } + void setMetaDataAvailable(bool available) { + if (m_available != available) + emit metaDataAvailableChanged(m_available = available); + } + QList availableMetaData() const { return m_data.keys(); } + + bool isWritable() const { return m_writable; } + void setWritable(bool writable) { emit writableChanged(m_writable = writable); } + + QVariant metaData(QtMedia::MetaData key) const { return m_data.value(key); } + void setMetaData(QtMedia::MetaData key, const QVariant &value) { + m_data.insert(key, value); } + + QVariant extendedMetaData(const QString &key) const { return m_extendedData.value(key); } + void setExtendedMetaData(const QString &key, const QVariant &value) { + m_extendedData.insert(key, value); } + + QStringList availableExtendedMetaData() const { return m_extendedData.keys(); } + + using QMetaDataControl::metaDataChanged; + + void populateMetaData() + { + m_available = true; + } + + bool m_available; + bool m_writable; + QMap m_data; + QMap m_extendedData; +}; + +class QtTestMetaDataService : public QMediaService +{ + Q_OBJECT +public: + QtTestMetaDataService(QObject *parent = 0):QMediaService(parent), hasMetaData(true) + { + } + + QMediaControl *control(const char *iid) const + { + if (hasMetaData && qstrcmp(iid, QMetaDataControl_iid) == 0) + return const_cast(&metaData); + else + return 0; + } + + QtTestMetaDataProvider metaData; + bool hasMetaData; +}; + + +class QtTestMediaObject : public QMediaObject +{ + Q_OBJECT + Q_PROPERTY(int a READ a WRITE setA NOTIFY aChanged) + Q_PROPERTY(int b READ b WRITE setB NOTIFY bChanged) + Q_PROPERTY(int c READ c WRITE setC NOTIFY cChanged) + Q_PROPERTY(int d READ d WRITE setD) +public: + QtTestMediaObject(QMediaService *service = 0): QMediaObject(0, service), m_a(0), m_b(0), m_c(0), m_d(0) {} + + using QMediaObject::addPropertyWatch; + using QMediaObject::removePropertyWatch; + + int a() const { return m_a; } + void setA(int a) { m_a = a; } + + int b() const { return m_b; } + void setB(int b) { m_b = b; } + + int c() const { return m_c; } + void setC(int c) { m_c = c; } + + int d() const { return m_d; } + void setD(int d) { m_d = d; } + +Q_SIGNALS: + void aChanged(int a); + void bChanged(int b); + void cChanged(int c); + +private: + int m_a; + int m_b; + int m_c; + int m_d; +}; + +void tst_QMediaObject::propertyWatch() +{ + QtTestMediaObject object; + object.setNotifyInterval(0); + + QEventLoop loop; + connect(&object, SIGNAL(aChanged(int)), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&object, SIGNAL(bChanged(int)), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&object, SIGNAL(cChanged(int)), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QSignalSpy aSpy(&object, SIGNAL(aChanged(int))); + QSignalSpy bSpy(&object, SIGNAL(bChanged(int))); + QSignalSpy cSpy(&object, SIGNAL(cChanged(int))); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), 0); + QCOMPARE(bSpy.count(), 0); + QCOMPARE(cSpy.count(), 0); + + int aCount = 0; + int bCount = 0; + int cCount = 0; + + object.addPropertyWatch("a"); + + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(aSpy.count() > aCount); + QCOMPARE(bSpy.count(), 0); + QCOMPARE(cSpy.count(), 0); + QCOMPARE(aSpy.last().value(0).toInt(), 0); + + aCount = aSpy.count(); + + object.setA(54); + object.setB(342); + object.setC(233); + + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(aSpy.count() > aCount); + QCOMPARE(bSpy.count(), 0); + QCOMPARE(cSpy.count(), 0); + QCOMPARE(aSpy.last().value(0).toInt(), 54); + + aCount = aSpy.count(); + + object.addPropertyWatch("b"); + object.addPropertyWatch("d"); + object.removePropertyWatch("e"); + object.setA(43); + object.setB(235); + object.setC(90); + + QTestEventLoop::instance().enterLoop(1); + + QVERIFY(aSpy.count() > aCount); + QVERIFY(bSpy.count() > bCount); + QCOMPARE(cSpy.count(), 0); + QCOMPARE(aSpy.last().value(0).toInt(), 43); + QCOMPARE(bSpy.last().value(0).toInt(), 235); + + aCount = aSpy.count(); + bCount = bSpy.count(); + + object.removePropertyWatch("a"); + object.addPropertyWatch("c"); + object.addPropertyWatch("e"); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QVERIFY(bSpy.count() > bCount); + QVERIFY(cSpy.count() > cCount); + QCOMPARE(bSpy.last().value(0).toInt(), 235); + QCOMPARE(cSpy.last().value(0).toInt(), 90); + + bCount = bSpy.count(); + cCount = cSpy.count(); + + object.setA(435); + object.setC(9845); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QVERIFY(bSpy.count() > bCount); + QVERIFY(cSpy.count() > cCount); + QCOMPARE(bSpy.last().value(0).toInt(), 235); + QCOMPARE(cSpy.last().value(0).toInt(), 9845); + + bCount = bSpy.count(); + cCount = cSpy.count(); + + object.setA(8432); + object.setB(324); + object.setC(443); + object.removePropertyWatch("c"); + object.removePropertyWatch("d"); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QVERIFY(bSpy.count() > bCount); + QCOMPARE(cSpy.count(), cCount); + QCOMPARE(bSpy.last().value(0).toInt(), 324); + QCOMPARE(cSpy.last().value(0).toInt(), 9845); + + bCount = bSpy.count(); + + object.removePropertyWatch("b"); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(aSpy.count(), aCount); + QCOMPARE(bSpy.count(), bCount); + QCOMPARE(cSpy.count(), cCount); +} + +void tst_QMediaObject::setupNotifyTests() +{ + QTest::addColumn("interval"); + QTest::addColumn("count"); + + QTest::newRow("single 750ms") + << 750 + << 1; + QTest::newRow("single 600ms") + << 600 + << 1; + QTest::newRow("x3 300ms") + << 300 + << 3; + QTest::newRow("x5 180ms") + << 180 + << 5; +} + +void tst_QMediaObject::notifySignals_data() +{ + setupNotifyTests(); +} + +void tst_QMediaObject::notifySignals() +{ + QFETCH(int, interval); + QFETCH(int, count); + + QtTestMediaObject object; + object.setNotifyInterval(interval); + object.addPropertyWatch("a"); + + QSignalSpy spy(&object, SIGNAL(aChanged(int))); + + QTestEventLoop::instance().enterLoop(1); + + QCOMPARE(spy.count(), count); +} + +void tst_QMediaObject::notifyInterval_data() +{ + setupNotifyTests(); +} + +void tst_QMediaObject::notifyInterval() +{ + QFETCH(int, interval); + + QtTestMediaObject object; + QSignalSpy spy(&object, SIGNAL(notifyIntervalChanged(int))); + + object.setNotifyInterval(interval); + QCOMPARE(object.notifyInterval(), interval); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.last().value(0).toInt(), interval); + + object.setNotifyInterval(interval); + QCOMPARE(object.notifyInterval(), interval); + QCOMPARE(spy.count(), 1); +} + +void tst_QMediaObject::nullMetaDataControl() +{ + const QString titleKey(QLatin1String("Title")); + const QString title(QLatin1String("Host of Seraphim")); + + QtTestMetaDataService service; + service.hasMetaData = false; + + QtTestMediaObject object(&service); + + QSignalSpy spy(&object, SIGNAL(metaDataChanged())); + + QCOMPARE(object.isMetaDataAvailable(), false); + QCOMPARE(object.isMetaDataWritable(), false); + + object.setMetaData(QtMedia::Title, title); + object.setExtendedMetaData(titleKey, title); + + QCOMPARE(object.metaData(QtMedia::Title).toString(), QString()); + QCOMPARE(object.extendedMetaData(titleKey).toString(), QString()); + QCOMPARE(object.availableMetaData(), QList()); + QCOMPARE(object.availableExtendedMetaData(), QStringList()); + QCOMPARE(spy.count(), 0); +} + +void tst_QMediaObject::isMetaDataAvailable() +{ + QtTestMetaDataService service; + service.metaData.setMetaDataAvailable(false); + + QtTestMediaObject object(&service); + QCOMPARE(object.isMetaDataAvailable(), false); + + QSignalSpy spy(&object, SIGNAL(metaDataAvailableChanged(bool))); + service.metaData.setMetaDataAvailable(true); + + QCOMPARE(object.isMetaDataAvailable(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toBool(), true); + + service.metaData.setMetaDataAvailable(false); + + QCOMPARE(object.isMetaDataAvailable(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.at(1).at(0).toBool(), false); +} + +void tst_QMediaObject::isWritable() +{ + QtTestMetaDataService service; + service.metaData.setWritable(false); + + QtTestMediaObject object(&service); + + QSignalSpy spy(&object, SIGNAL(metaDataWritableChanged(bool))); + + QCOMPARE(object.isMetaDataWritable(), false); + + service.metaData.setWritable(true); + + QCOMPARE(object.isMetaDataWritable(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toBool(), true); + + service.metaData.setWritable(false); + + QCOMPARE(object.isMetaDataWritable(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.at(1).at(0).toBool(), false); +} + +void tst_QMediaObject::metaDataChanged() +{ + QtTestMetaDataService service; + QtTestMediaObject object(&service); + + QSignalSpy spy(&object, SIGNAL(metaDataChanged())); + + service.metaData.metaDataChanged(); + QCOMPARE(spy.count(), 1); + + service.metaData.metaDataChanged(); + QCOMPARE(spy.count(), 2); +} + +void tst_QMediaObject::metaData_data() +{ + QTest::addColumn("artist"); + QTest::addColumn("title"); + QTest::addColumn("genre"); + + QTest::newRow("") + << QString::fromLatin1("Dead Can Dance") + << QString::fromLatin1("Host of Seraphim") + << QString::fromLatin1("Awesome"); +} + +void tst_QMediaObject::metaData() +{ + QFETCH(QString, artist); + QFETCH(QString, title); + QFETCH(QString, genre); + + QtTestMetaDataService service; + service.metaData.populateMetaData(); + + QtTestMediaObject object(&service); + QVERIFY(object.availableMetaData().isEmpty()); + + service.metaData.m_data.insert(QtMedia::AlbumArtist, artist); + service.metaData.m_data.insert(QtMedia::Title, title); + service.metaData.m_data.insert(QtMedia::Genre, genre); + + QCOMPARE(object.metaData(QtMedia::AlbumArtist).toString(), artist); + QCOMPARE(object.metaData(QtMedia::Title).toString(), title); + + QList metaDataKeys = object.availableMetaData(); + QCOMPARE(metaDataKeys.size(), 3); + QVERIFY(metaDataKeys.contains(QtMedia::AlbumArtist)); + QVERIFY(metaDataKeys.contains(QtMedia::Title)); + QVERIFY(metaDataKeys.contains(QtMedia::Genre)); +} + +void tst_QMediaObject::setMetaData_data() +{ + QTest::addColumn("title"); + + QTest::newRow("") + << QString::fromLatin1("In the Kingdom of the Blind the One eyed are Kings"); +} + +void tst_QMediaObject::setMetaData() +{ + QFETCH(QString, title); + + QtTestMetaDataService service; + service.metaData.populateMetaData(); + + QtTestMediaObject object(&service); + + object.setMetaData(QtMedia::Title, title); + QCOMPARE(object.metaData(QtMedia::Title).toString(), title); + QCOMPARE(service.metaData.m_data.value(QtMedia::Title).toString(), title); +} + +void tst_QMediaObject::extendedMetaData() +{ + QFETCH(QString, artist); + QFETCH(QString, title); + QFETCH(QString, genre); + + QtTestMetaDataService service; + QtTestMediaObject object(&service); + QVERIFY(object.availableExtendedMetaData().isEmpty()); + + service.metaData.m_extendedData.insert(QLatin1String("Artist"), artist); + service.metaData.m_extendedData.insert(QLatin1String("Title"), title); + service.metaData.m_extendedData.insert(QLatin1String("Genre"), genre); + + QCOMPARE(object.extendedMetaData(QLatin1String("Artist")).toString(), artist); + QCOMPARE(object.extendedMetaData(QLatin1String("Title")).toString(), title); + + QStringList extendedKeys = object.availableExtendedMetaData(); + QCOMPARE(extendedKeys.size(), 3); + QVERIFY(extendedKeys.contains(QLatin1String("Artist"))); + QVERIFY(extendedKeys.contains(QLatin1String("Title"))); + QVERIFY(extendedKeys.contains(QLatin1String("Genre"))); +} + +void tst_QMediaObject::setExtendedMetaData() +{ + QtTestMetaDataService service; + service.metaData.populateMetaData(); + + QtTestMediaObject object(&service); + + QString title(QLatin1String("In the Kingdom of the Blind the One eyed are Kings")); + + object.setExtendedMetaData(QLatin1String("Title"), title); + QCOMPARE(object.extendedMetaData(QLatin1String("Title")).toString(), title); + QCOMPARE(service.metaData.m_extendedData.value(QLatin1String("Title")).toString(), title); +} + +QTEST_MAIN(tst_QMediaObject) + +#include "tst_qmediaobject.moc" diff --git a/tests/auto/qmediaplayer/qmediaplayer.pro b/tests/auto/qmediaplayer/qmediaplayer.pro new file mode 100644 index 0000000..21008f9 --- /dev/null +++ b/tests/auto/qmediaplayer/qmediaplayer.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES += tst_qmediaplayer.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaplayer/tst_qmediaplayer.cpp b/tests/auto/qmediaplayer/tst_qmediaplayer.cpp new file mode 100644 index 0000000..a3cba3f --- /dev/null +++ b/tests/auto/qmediaplayer/tst_qmediaplayer.cpp @@ -0,0 +1,1011 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include + +#include +#include +#include +#include + + + +class AutoConnection +{ +public: + AutoConnection(QObject *sender, const char *signal, QObject *receiver, const char *method) + : sender(sender), signal(signal), receiver(receiver), method(method) + { + QObject::connect(sender, signal, receiver, method); + } + + ~AutoConnection() + { + QObject::disconnect(sender, signal, receiver, method); + } + +private: + QObject *sender; + const char *signal; + QObject *receiver; + const char *method; +}; + + +class MockPlayerControl : public QMediaPlayerControl +{ + friend class MockPlayerService; + +public: + MockPlayerControl():QMediaPlayerControl(0) {} + + QMediaPlayer::State state() const { return _state; } + QMediaPlayer::MediaStatus mediaStatus() const { return _mediaStatus; } + + qint64 duration() const { return _duration; } + + qint64 position() const { return _position; } + + void setPosition(qint64 position) { if (position != _position) emit positionChanged(_position = position); } + + int volume() const { return _volume; } + void setVolume(int volume) { emit volumeChanged(_volume = volume); } + + bool isMuted() const { return _muted; } + void setMuted(bool muted) { if (muted != _muted) emit mutedChanged(_muted = muted); } + + int bufferStatus() const { return _bufferStatus; } + + bool isVideoAvailable() const { return _videoAvailable; } + + bool isSeekable() const { return _isSeekable; } + QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(_seekRange.first, _seekRange.second); } + void setSeekRange(qint64 minimum, qint64 maximum) { _seekRange = qMakePair(minimum, maximum); } + + qreal playbackRate() const { return _playbackRate; } + void setPlaybackRate(qreal rate) { if (rate != _playbackRate) emit playbackRateChanged(_playbackRate = rate); } + + QMediaContent media() const { return _media; } + void setMedia(const QMediaContent &content, QIODevice *stream) + { + _stream = stream; + _media = content; + if (_state != QMediaPlayer::StoppedState) { + _mediaStatus = _media.isNull() ? QMediaPlayer::NoMedia : QMediaPlayer::LoadingMedia; + emit stateChanged(_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(_mediaStatus); + } + emit mediaChanged(_media = content); + } + QIODevice *mediaStream() const { return _stream; } + + void play() { if (_isValid && !_media.isNull() && _state != QMediaPlayer::PlayingState) emit stateChanged(_state = QMediaPlayer::PlayingState); } + void pause() { if (_isValid && !_media.isNull() && _state != QMediaPlayer::PausedState) emit stateChanged(_state = QMediaPlayer::PausedState); } + void stop() { if (_state != QMediaPlayer::StoppedState) emit stateChanged(_state = QMediaPlayer::StoppedState); } + + QMediaPlayer::State _state; + QMediaPlayer::MediaStatus _mediaStatus; + QMediaPlayer::Error _error; + qint64 _duration; + qint64 _position; + int _volume; + bool _muted; + int _bufferStatus; + bool _videoAvailable; + bool _isSeekable; + QPair _seekRange; + qreal _playbackRate; + QMediaContent _media; + QIODevice *_stream; + bool _isValid; + QString _errorString; +}; + + +class MockPlayerService : public QMediaService +{ + Q_OBJECT + +public: + MockPlayerService():QMediaService(0) + { + mockControl = new MockPlayerControl; + } + + ~MockPlayerService() + { + delete mockControl; + } + + QMediaControl* control(const char *iid) const + { + if (qstrcmp(iid, QMediaPlayerControl_iid) == 0) + return mockControl; + + return 0; + } + + void setState(QMediaPlayer::State state) { emit mockControl->stateChanged(mockControl->_state = state); } + void setState(QMediaPlayer::State state, QMediaPlayer::MediaStatus status) { + mockControl->_state = state; + mockControl->_mediaStatus = status; + emit mockControl->mediaStatusChanged(status); + emit mockControl->stateChanged(state); + } + void setMediaStatus(QMediaPlayer::MediaStatus status) { emit mockControl->mediaStatusChanged(mockControl->_mediaStatus = status); } + void setIsValid(bool isValid) { mockControl->_isValid = isValid; } + void setMedia(QMediaContent media) { mockControl->_media = media; } + void setDuration(qint64 duration) { mockControl->_duration = duration; } + void setPosition(qint64 position) { mockControl->_position = position; } + void setSeekable(bool seekable) { mockControl->_isSeekable = seekable; } + void setVolume(int volume) { mockControl->_volume = volume; } + void setMuted(bool muted) { mockControl->_muted = muted; } + void setVideoAvailable(bool videoAvailable) { mockControl->_videoAvailable = videoAvailable; } + void setBufferStatus(int bufferStatus) { mockControl->_bufferStatus = bufferStatus; } + void setPlaybackRate(qreal playbackRate) { mockControl->_playbackRate = playbackRate; } + void setError(QMediaPlayer::Error error) { mockControl->_error = error; emit mockControl->error(mockControl->_error, mockControl->_errorString); } + void setErrorString(QString errorString) { mockControl->_errorString = errorString; emit mockControl->error(mockControl->_error, mockControl->_errorString); } + + void reset() + { + mockControl->_state = QMediaPlayer::StoppedState; + mockControl->_mediaStatus = QMediaPlayer::UnknownMediaStatus; + mockControl->_error = QMediaPlayer::NoError; + mockControl->_duration = 0; + mockControl->_position = 0; + mockControl->_volume = 0; + mockControl->_muted = false; + mockControl->_bufferStatus = 0; + mockControl->_videoAvailable = false; + mockControl->_isSeekable = false; + mockControl->_playbackRate = 0.0; + mockControl->_media = QMediaContent(); + mockControl->_stream = 0; + mockControl->_isValid = false; + mockControl->_errorString = QString(); + } + + MockPlayerControl *mockControl; +}; + +class MockProvider : public QMediaServiceProvider +{ +public: + MockProvider(MockPlayerService *service):mockService(service) {} + QMediaService *requestService(const QByteArray &, const QMediaServiceProviderHint &) + { + return mockService; + } + + void releaseService(QMediaService *service) { delete service; } + + MockPlayerService *mockService; +}; + +class tst_QMediaPlayer: public QObject +{ + Q_OBJECT + +public slots: + void initTestCase_data(); + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void testNullService(); + void testValid(); + void testMedia(); + void testDuration(); + void testPosition(); + void testVolume(); + void testMuted(); + void testVideoAvailable(); + void testBufferStatus(); + void testSeekable(); + void testPlaybackRate(); + void testError(); + void testErrorString(); + void testService(); + void testPlay(); + void testPause(); + void testStop(); + void testMediaStatus(); + void testPlaylist(); + +private: + MockProvider *mockProvider; + MockPlayerService *mockService; + QMediaPlayer *player; +}; + +void tst_QMediaPlayer::initTestCase_data() +{ + QTest::addColumn("valid"); + QTest::addColumn("state"); + QTest::addColumn("status"); + QTest::addColumn("mediaContent"); + QTest::addColumn("duration"); + QTest::addColumn("position"); + QTest::addColumn("seekable"); + QTest::addColumn("volume"); + QTest::addColumn("muted"); + QTest::addColumn("videoAvailable"); + QTest::addColumn("bufferStatus"); + QTest::addColumn("playbackRate"); + QTest::addColumn("error"); + QTest::addColumn("errorString"); + + QTest::newRow("invalid") << false << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent() << qint64(0) << qint64(0) << false << 0 << false << false << 0 << + qreal(0) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+null") << true << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent() << qint64(0) << qint64(0) << false << 0 << false << false << 50 << + qreal(0) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+content+stopped") << true << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent(QUrl("file:///some.mp3")) << qint64(0) << qint64(0) << false << 50 << false << false << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+content+playing") << true << QMediaPlayer::PlayingState << QMediaPlayer::LoadedMedia << + QMediaContent(QUrl("file:///some.mp3")) << qint64(10000) << qint64(10) << true << 50 << true << false << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+content+paused") << true << QMediaPlayer::PausedState << QMediaPlayer::LoadedMedia << + QMediaContent(QUrl("file:///some.mp3")) << qint64(10000) << qint64(10) << true << 50 << true << false << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valud+streaming") << true << QMediaPlayer::PlayingState << QMediaPlayer::LoadedMedia << + QMediaContent(QUrl("http://example.com/stream")) << qint64(10000) << qint64(10000) << false << 50 << false << true << 0 << + qreal(1) << QMediaPlayer::NoError << QString(); + QTest::newRow("valid+error") << true << QMediaPlayer::StoppedState << QMediaPlayer::UnknownMediaStatus << + QMediaContent(QUrl("http://example.com/stream")) << qint64(0) << qint64(0) << false << 50 << false << false << 0 << + qreal(0) << QMediaPlayer::ResourceError << QString("Resource unavailable"); +} + +void tst_QMediaPlayer::initTestCase() +{ + qRegisterMetaType("QMediaPlayer::State"); + qRegisterMetaType("QMediaPlayer::Error"); + qRegisterMetaType("QMediaPlayer::MediaStatus"); + qRegisterMetaType("QMediaContent"); + + mockService = new MockPlayerService; + mockProvider = new MockProvider(mockService); + player = new QMediaPlayer(0, 0, mockProvider); +} + +void tst_QMediaPlayer::cleanupTestCase() +{ + delete player; +} + +void tst_QMediaPlayer::init() +{ + mockService->reset(); +} + +void tst_QMediaPlayer::cleanup() +{ +} + +void tst_QMediaPlayer::testNullService() +{ + MockProvider provider(0); + QMediaPlayer player(0, 0, &provider); + + const QIODevice *nullDevice = 0; + + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(player.mediaStream(), nullDevice); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(player.duration(), qint64(-1)); + QCOMPARE(player.position(), qint64(0)); + QCOMPARE(player.volume(), 0); + QCOMPARE(player.isMuted(), false); + QCOMPARE(player.isVideoAvailable(), false); + QCOMPARE(player.bufferStatus(), 0); + QCOMPARE(player.isSeekable(), false); + QCOMPARE(player.playbackRate(), qreal(0)); + QCOMPARE(player.error(), QMediaPlayer::ServiceMissingError); + + { + QFETCH_GLOBAL(QMediaContent, mediaContent); + + QSignalSpy spy(&player, SIGNAL(mediaChanged(QMediaContent))); + QFile file; + + player.setMedia(mediaContent, &file); + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(player.mediaStream(), nullDevice); + QCOMPARE(spy.count(), 0); + } { + QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State))); + QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + + player.play(); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + + player.pause(); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + + player.stop(); + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::UnknownMediaStatus); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + } { + QFETCH_GLOBAL(int, volume); + QFETCH_GLOBAL(bool, muted); + + QSignalSpy volumeSpy(&player, SIGNAL(volumeChanged(int))); + QSignalSpy mutingSpy(&player, SIGNAL(mutedChanged(bool))); + + player.setVolume(volume); + QCOMPARE(player.volume(), 0); + QCOMPARE(volumeSpy.count(), 0); + + player.setMuted(muted); + QCOMPARE(player.isMuted(), false); + QCOMPARE(mutingSpy.count(), 0); + } { + QFETCH_GLOBAL(qint64, position); + + QSignalSpy spy(&player, SIGNAL(positionChanged(qint64))); + + player.setPosition(position); + QCOMPARE(player.position(), qint64(0)); + QCOMPARE(spy.count(), 0); + } { + QFETCH_GLOBAL(qreal, playbackRate); + + QSignalSpy spy(&player, SIGNAL(playbackRateChanged(qreal))); + + player.setPlaybackRate(playbackRate); + QCOMPARE(player.playbackRate(), qreal(0)); + QCOMPARE(spy.count(), 0); + } { + QMediaPlaylist playlist; + playlist.setMediaObject(&player); + + QSignalSpy mediaSpy(&player, SIGNAL(mediaChanged(QMediaContent))); + QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + + playlist.addMedia(QUrl("http://example.com/stream")); + playlist.addMedia(QUrl("file:///some.mp3")); + + playlist.setCurrentIndex(0); + QCOMPARE(playlist.currentIndex(), 0); + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(mediaSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + + playlist.next(); + QCOMPARE(playlist.currentIndex(), 1); + QCOMPARE(player.media(), QMediaContent()); + QCOMPARE(mediaSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + } +} + +void tst_QMediaPlayer::testValid() +{ + /* + QFETCH_GLOBAL(bool, valid); + + mockService->setIsValid(valid); + QCOMPARE(player->isValid(), valid); + */ +} + +void tst_QMediaPlayer::testMedia() +{ + QFETCH_GLOBAL(QMediaContent, mediaContent); + + mockService->setMedia(mediaContent); + QCOMPARE(player->media(), mediaContent); + + QBuffer stream; + player->setMedia(mediaContent, &stream); + QCOMPARE(player->media(), mediaContent); + QCOMPARE((QBuffer*)player->mediaStream(), &stream); +} + +void tst_QMediaPlayer::testDuration() +{ + QFETCH_GLOBAL(qint64, duration); + + mockService->setDuration(duration); + QVERIFY(player->duration() == duration); +} + +void tst_QMediaPlayer::testPosition() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(bool, seekable); + QFETCH_GLOBAL(qint64, position); + QFETCH_GLOBAL(qint64, duration); + + mockService->setIsValid(valid); + mockService->setSeekable(seekable); + mockService->setPosition(position); + mockService->setDuration(duration); + QVERIFY(player->isSeekable() == seekable); + QVERIFY(player->position() == position); + QVERIFY(player->duration() == duration); + + if (seekable) { + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(position); + QCOMPARE(player->position(), position); + QCOMPARE(spy.count(), 0); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(0); + QCOMPARE(player->position(), qint64(0)); + QCOMPARE(spy.count(), position == 0 ? 0 : 1); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(duration); + QCOMPARE(player->position(), duration); + QCOMPARE(spy.count(), position == duration ? 0 : 1); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(-1); + QCOMPARE(player->position(), qint64(0)); + QCOMPARE(spy.count(), position == 0 ? 0 : 1); } + + mockService->setPosition(position); + { QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(duration + 1); + QCOMPARE(player->position(), duration); + QCOMPARE(spy.count(), position == duration ? 0 : 1); } + } + else { + QSignalSpy spy(player, SIGNAL(positionChanged(qint64))); + player->setPosition(position); + + QCOMPARE(player->position(), position); + QCOMPARE(spy.count(), 0); + } +} + +void tst_QMediaPlayer::testVolume() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(int, volume); + + mockService->setVolume(volume); + QVERIFY(player->volume() == volume); + + if (valid) { + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(10); + QCOMPARE(player->volume(), 10); + QCOMPARE(spy.count(), 1); } + + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(-1000); + QCOMPARE(player->volume(), 0); + QCOMPARE(spy.count(), 1); } + + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(100); + QCOMPARE(player->volume(), 100); + QCOMPARE(spy.count(), 1); } + + { QSignalSpy spy(player, SIGNAL(volumeChanged(int))); + player->setVolume(1000); + QCOMPARE(player->volume(), 100); + QCOMPARE(spy.count(), 0); } + } +} + +void tst_QMediaPlayer::testMuted() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(bool, muted); + QFETCH_GLOBAL(int, volume); + + if (valid) { + mockService->setMuted(muted); + mockService->setVolume(volume); + QVERIFY(player->isMuted() == muted); + + QSignalSpy spy(player, SIGNAL(mutedChanged(bool))); + player->setMuted(!muted); + QCOMPARE(player->isMuted(), !muted); + QCOMPARE(player->volume(), volume); + QCOMPARE(spy.count(), 1); + } +} + +void tst_QMediaPlayer::testVideoAvailable() +{ + QFETCH_GLOBAL(bool, videoAvailable); + + mockService->setVideoAvailable(videoAvailable); + QVERIFY(player->isVideoAvailable() == videoAvailable); +} + +void tst_QMediaPlayer::testBufferStatus() +{ + QFETCH_GLOBAL(int, bufferStatus); + + mockService->setBufferStatus(bufferStatus); + QVERIFY(player->bufferStatus() == bufferStatus); +} + +void tst_QMediaPlayer::testSeekable() +{ + QFETCH_GLOBAL(bool, seekable); + + mockService->setSeekable(seekable); + QVERIFY(player->isSeekable() == seekable); +} + +void tst_QMediaPlayer::testPlaybackRate() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(qreal, playbackRate); + + if (valid) { + mockService->setPlaybackRate(playbackRate); + QVERIFY(player->playbackRate() == playbackRate); + + QSignalSpy spy(player, SIGNAL(playbackRateChanged(qreal))); + player->setPlaybackRate(playbackRate + 0.5f); + QCOMPARE(player->playbackRate(), playbackRate + 0.5f); + QCOMPARE(spy.count(), 1); + } +} + +void tst_QMediaPlayer::testError() +{ + QFETCH_GLOBAL(QMediaPlayer::Error, error); + + mockService->setError(error); + QVERIFY(player->error() == error); +} + +void tst_QMediaPlayer::testErrorString() +{ + QFETCH_GLOBAL(QString, errorString); + + mockService->setErrorString(errorString); + QVERIFY(player->errorString() == errorString); +} + +void tst_QMediaPlayer::testService() +{ + /* + QFETCH_GLOBAL(bool, valid); + + mockService->setIsValid(valid); + + if (valid) + QVERIFY(player->service() != 0); + else + QVERIFY(player->service() == 0); + */ +} + +void tst_QMediaPlayer::testPlay() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(QMediaContent, mediaContent); + QFETCH_GLOBAL(QMediaPlayer::State, state); + + mockService->setIsValid(valid); + mockService->setState(state); + mockService->setMedia(mediaContent); + QVERIFY(player->state() == state); + QVERIFY(player->media() == mediaContent); + + QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + + player->play(); + + if (!valid || mediaContent.isNull()) { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 0); + } + else { + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(spy.count(), state == QMediaPlayer::PlayingState ? 0 : 1); + } +} + +void tst_QMediaPlayer::testPause() +{ + QFETCH_GLOBAL(bool, valid); + QFETCH_GLOBAL(QMediaContent, mediaContent); + QFETCH_GLOBAL(QMediaPlayer::State, state); + + mockService->setIsValid(valid); + mockService->setState(state); + mockService->setMedia(mediaContent); + QVERIFY(player->state() == state); + QVERIFY(player->media() == mediaContent); + + QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + + player->pause(); + + if (!valid || mediaContent.isNull()) { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 0); + } + else { + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(spy.count(), state == QMediaPlayer::PausedState ? 0 : 1); + } +} + +void tst_QMediaPlayer::testStop() +{ + QFETCH_GLOBAL(QMediaContent, mediaContent); + QFETCH_GLOBAL(QMediaPlayer::State, state); + + mockService->setState(state); + mockService->setMedia(mediaContent); + QVERIFY(player->state() == state); + QVERIFY(player->media() == mediaContent); + + QSignalSpy spy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + + player->stop(); + + if (mediaContent.isNull() || state == QMediaPlayer::StoppedState) { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 0); + } + else { + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(spy.count(), 1); + } +} + +void tst_QMediaPlayer::testMediaStatus() +{ + QFETCH_GLOBAL(int, bufferStatus); + int bufferSignals = 0; + + player->setNotifyInterval(10); + + mockService->setMediaStatus(QMediaPlayer::NoMedia); + mockService->setBufferStatus(bufferStatus); + + AutoConnection connection( + player, SIGNAL(bufferStatusChanged(int)), + &QTestEventLoop::instance(), SLOT(exitLoop())); + + QSignalSpy statusSpy(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + QSignalSpy bufferSpy(player, SIGNAL(bufferStatusChanged(int))); + + QCOMPARE(player->mediaStatus(), QMediaPlayer::NoMedia); + + mockService->setMediaStatus(QMediaPlayer::LoadingMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadingMedia); + QCOMPARE(statusSpy.count(), 1); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast(statusSpy.last().value(0)), + QMediaPlayer::LoadingMedia); + + mockService->setMediaStatus(QMediaPlayer::LoadedMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::LoadedMedia); + QCOMPARE(statusSpy.count(), 2); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast(statusSpy.last().value(0)), + QMediaPlayer::LoadedMedia); + + // Verify the bufferStatusChanged() signal isn't being emitted. + QTestEventLoop::instance().enterLoop(1); + QCOMPARE(bufferSpy.count(), 0); + + mockService->setMediaStatus(QMediaPlayer::StalledMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::StalledMedia); + QCOMPARE(statusSpy.count(), 3); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast(statusSpy.last().value(0)), + QMediaPlayer::StalledMedia); + + // Verify the bufferStatusChanged() signal is being emitted. + QTestEventLoop::instance().enterLoop(1); + QVERIFY(bufferSpy.count() > bufferSignals); + QCOMPARE(bufferSpy.last().value(0).toInt(), bufferStatus); + bufferSignals = bufferSpy.count(); + + mockService->setMediaStatus(QMediaPlayer::BufferingMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::BufferingMedia); + QCOMPARE(statusSpy.count(), 4); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast(statusSpy.last().value(0)), + QMediaPlayer::BufferingMedia); + + // Verify the bufferStatusChanged() signal is being emitted. + QTestEventLoop::instance().enterLoop(1); + QVERIFY(bufferSpy.count() > bufferSignals); + QCOMPARE(bufferSpy.last().value(0).toInt(), bufferStatus); + bufferSignals = bufferSpy.count(); + + mockService->setMediaStatus(QMediaPlayer::BufferedMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::BufferedMedia); + QCOMPARE(statusSpy.count(), 5); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast(statusSpy.last().value(0)), + QMediaPlayer::BufferedMedia); + + // Verify the bufferStatusChanged() signal isn't being emitted. + QTestEventLoop::instance().enterLoop(1); + QCOMPARE(bufferSpy.count(), bufferSignals); + + mockService->setMediaStatus(QMediaPlayer::EndOfMedia); + QCOMPARE(player->mediaStatus(), QMediaPlayer::EndOfMedia); + QCOMPARE(statusSpy.count(), 6); + +#ifdef QTM_NAMESPACE + //looks like the correct value is emited, but QSignalSpy doesn't work correctly with QtMobility namespace + QEXPECT_FAIL("", "QSignalSpy doesn't grab the correct value from signal because of QtMobility namespace", Continue); +#endif + QCOMPARE(qvariant_cast(statusSpy.last().value(0)), + QMediaPlayer::EndOfMedia); +} + +void tst_QMediaPlayer::testPlaylist() +{ + QMediaContent content0(QUrl(QLatin1String("test://audio/song1.mp3"))); + QMediaContent content1(QUrl(QLatin1String("test://audio/song2.mp3"))); + QMediaContent content2(QUrl(QLatin1String("test://video/movie1.mp4"))); + QMediaContent content3(QUrl(QLatin1String("test://video/movie2.mp4"))); + QMediaContent content4(QUrl(QLatin1String("test://image/photo.jpg"))); + + mockService->setIsValid(true); + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::NoMedia); + + QMediaPlaylist *playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + + QSignalSpy stateSpy(player, SIGNAL(stateChanged(QMediaPlayer::State))); + QSignalSpy mediaSpy(player, SIGNAL(mediaChanged(QMediaContent))); + + // Test the player does nothing with an empty playlist attached. + player->play(); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(mediaSpy.count(), 0); + + playlist->addMedia(content0); + playlist->addMedia(content1); + playlist->addMedia(content2); + playlist->addMedia(content3); + + // Test changing the playlist position, changes the current media, but not the playing state. + playlist->setCurrentIndex(1); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(mediaSpy.count(), 1); + + // Test playing starts with the current media. + player->play(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 1); + QCOMPARE(mediaSpy.count(), 1); + + // Test pausing doesn't change the current media. + player->pause(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(stateSpy.count(), 2); + QCOMPARE(mediaSpy.count(), 1); + + // Test stopping doesn't change the current media. + player->stop(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 3); + QCOMPARE(mediaSpy.count(), 1); + + // Test when the player service reaches the end of the current media, the player moves onto + // the next item without stopping. + player->play(); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 4); + QCOMPARE(mediaSpy.count(), 1); + + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); + QCOMPARE(player->media(), content2); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 4); + QCOMPARE(mediaSpy.count(), 2); + + // Test skipping the current media doesn't change the state. + playlist->next(); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 4); + QCOMPARE(mediaSpy.count(), 3); + + // Test changing the current media while paused doesn't change the state. + player->pause(); + mockService->setMediaStatus(QMediaPlayer::BufferedMedia); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(stateSpy.count(), 5); + QCOMPARE(mediaSpy.count(), 3); + + playlist->previous(); + QCOMPARE(player->media(), content2); + QCOMPARE(player->state(), QMediaPlayer::PausedState); + QCOMPARE(stateSpy.count(), 5); + QCOMPARE(mediaSpy.count(), 4); + + // Test changing the current media while stopped doesn't change the state. + player->stop(); + mockService->setMediaStatus(QMediaPlayer::LoadedMedia); + QCOMPARE(player->media(), content2); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 6); + QCOMPARE(mediaSpy.count(), 4); + + playlist->next(); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 6); + QCOMPARE(mediaSpy.count(), 5); + + // Test the player is stopped and the current media cleared when it reaches the end of the last + // item in the playlist. + player->play(); + QCOMPARE(player->media(), content3); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 7); + QCOMPARE(mediaSpy.count(), 5); + + // Double up the signals to ensure some noise doesn't destabalize things. + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); + mockService->setState(QMediaPlayer::StoppedState, QMediaPlayer::EndOfMedia); + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 8); + QCOMPARE(mediaSpy.count(), 6); + + // Test starts playing from the start of the playlist if there is no current media selected. + player->play(); + QCOMPARE(player->media(), content0); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 9); + QCOMPARE(mediaSpy.count(), 7); + + // Test deleting the playlist stops the player and clears the media it set. + delete playlist; + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 10); + QCOMPARE(mediaSpy.count(), 8); + + // Test the player works as normal with the playlist removed. + player->play(); + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + QCOMPARE(stateSpy.count(), 10); + QCOMPARE(mediaSpy.count(), 8); + + player->setMedia(content1); + player->play(); + + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::PlayingState); + QCOMPARE(stateSpy.count(), 11); + QCOMPARE(mediaSpy.count(), 9); + + // Test the player can bind to playlist again + playlist = new QMediaPlaylist; + playlist->setMediaObject(player); + QCOMPARE(playlist->mediaObject(), qobject_cast(player)); + + QCOMPARE(player->media(), QMediaContent()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + + playlist->addMedia(content0); + playlist->addMedia(content1); + playlist->addMedia(content2); + playlist->addMedia(content3); + + playlist->setCurrentIndex(1); + QCOMPARE(player->media(), content1); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + + // Test attaching the new playlist, + // player should detach the current one + QMediaPlaylist *playlist2 = new QMediaPlaylist; + playlist2->addMedia(content1); + playlist2->addMedia(content2); + playlist2->addMedia(content3); + playlist2->setCurrentIndex(2); + + player->play(); + playlist2->setMediaObject(player); + QCOMPARE(playlist2->mediaObject(), qobject_cast(player)); + QVERIFY(playlist->mediaObject() == 0); + QCOMPARE(player->media(), playlist2->currentMedia()); + QCOMPARE(player->state(), QMediaPlayer::StoppedState); + + playlist2->setCurrentIndex(1); + QCOMPARE(player->media(), playlist2->currentMedia()); +} + +QTEST_MAIN(tst_QMediaPlayer) + +#include "tst_qmediaplayer.moc" diff --git a/tests/auto/qmediaplaylist/qmediaplaylist.pro b/tests/auto/qmediaplaylist/qmediaplaylist.pro new file mode 100644 index 0000000..b114bda --- /dev/null +++ b/tests/auto/qmediaplaylist/qmediaplaylist.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaplaylist.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaplaylist/tmp.unsupported_format b/tests/auto/qmediaplaylist/tmp.unsupported_format new file mode 100644 index 0000000..e69de29 diff --git a/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp new file mode 100644 index 0000000..88a2f31 --- /dev/null +++ b/tests/auto/qmediaplaylist/tst_qmediaplaylist.cpp @@ -0,0 +1,622 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include +#include +#include +#include +#include + + +class MockReadOnlyPlaylistProvider : public QMediaPlaylistProvider +{ + Q_OBJECT +public: + MockReadOnlyPlaylistProvider(QObject *parent) + :QMediaPlaylistProvider(parent) + { + m_items.append(QMediaContent(QUrl(QLatin1String("file:///1")))); + m_items.append(QMediaContent(QUrl(QLatin1String("file:///2")))); + m_items.append(QMediaContent(QUrl(QLatin1String("file:///3")))); + } + + int mediaCount() const { return m_items.size(); } + QMediaContent media(int index) const + { + return index >=0 && index < mediaCount() ? m_items.at(index) : QMediaContent(); + } + +private: + QList m_items; +}; + +class MockPlaylistControl : public QMediaPlaylistControl +{ + Q_OBJECT +public: + MockPlaylistControl(QObject *parent) : QMediaPlaylistControl(parent) + { + m_navigator = new QMediaPlaylistNavigator(new MockReadOnlyPlaylistProvider(this), this); + } + + ~MockPlaylistControl() + { + } + + QMediaPlaylistProvider* playlistProvider() const { return m_navigator->playlist(); } + bool setPlaylistProvider(QMediaPlaylistProvider *playlist) { m_navigator->setPlaylist(playlist); return true; } + + int currentIndex() const { return m_navigator->currentIndex(); } + void setCurrentIndex(int position) { m_navigator->jump(position); } + int nextIndex(int steps) const { return m_navigator->nextIndex(steps); } + int previousIndex(int steps) const { return m_navigator->previousIndex(steps); } + + void next() { m_navigator->next(); } + void previous() { m_navigator->previous(); } + + QMediaPlaylist::PlaybackMode playbackMode() const { return m_navigator->playbackMode(); } + void setPlaybackMode(QMediaPlaylist::PlaybackMode mode) { m_navigator->setPlaybackMode(mode); } + +private: + QMediaPlaylistNavigator *m_navigator; +}; + +class MockPlaylistService : public QMediaService +{ + Q_OBJECT + +public: + MockPlaylistService():QMediaService(0) + { + mockControl = new MockPlaylistControl(this); + } + + ~MockPlaylistService() + { + } + + QMediaControl* control(const char *iid) const + { + if (qstrcmp(iid, QMediaPlaylistControl_iid) == 0) + return mockControl; + return 0; + } + + MockPlaylistControl *mockControl; +}; + +class MockReadOnlyPlaylistObject : public QMediaObject +{ + Q_OBJECT +public: + MockReadOnlyPlaylistObject(QObject *parent = 0) + :QMediaObject(parent, new MockPlaylistService) + { + } +}; + + +class tst_QMediaPlaylist : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + void initTestCase(); + +private slots: + void construction(); + void append(); + void insert(); + void clear(); + void removeMedia(); + void currentItem(); + void saveAndLoad(); + void playbackMode(); + void playbackMode_data(); + void shuffle(); + void readOnlyPlaylist(); + void setMediaObject(); + +private: + QMediaContent content1; + QMediaContent content2; + QMediaContent content3; +}; + +void tst_QMediaPlaylist::init() +{ +} + +void tst_QMediaPlaylist::initTestCase() +{ + content1 = QMediaContent(QUrl(QLatin1String("file:///1"))); + content2 = QMediaContent(QUrl(QLatin1String("file:///2"))); + content3 = QMediaContent(QUrl(QLatin1String("file:///3"))); +} + +void tst_QMediaPlaylist::cleanup() +{ +} + +void tst_QMediaPlaylist::construction() +{ + QMediaPlaylist playlist; + QCOMPARE(playlist.mediaCount(), 0); + QVERIFY(playlist.isEmpty()); +} + +void tst_QMediaPlaylist::append() +{ + QMediaPlaylist playlist; + QVERIFY(!playlist.isReadOnly()); + + playlist.addMedia(content1); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0), content1); + + QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int,int))); + QSignalSpy insertedSignalSpy(&playlist, SIGNAL(mediaInserted(int,int))); + playlist.addMedia(content2); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(1), content2); + + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + QMediaContent content4(QUrl(QLatin1String("file:///4"))); + QMediaContent content5(QUrl(QLatin1String("file:///5"))); + playlist.addMedia(QList() << content3 << content4 << content5); + QCOMPARE(playlist.mediaCount(), 5); + QCOMPARE(playlist.media(2), content3); + QCOMPARE(playlist.media(3), content4); + QCOMPARE(playlist.media(4), content5); + + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy[0][0].toInt(), 2); + QCOMPARE(aboutToBeInsertedSignalSpy[0][1].toInt(), 4); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy[0][0].toInt(), 2); + QCOMPARE(insertedSignalSpy[0][1].toInt(), 4); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + playlist.addMedia(QList()); + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 0); + QCOMPARE(insertedSignalSpy.count(), 0); +} + +void tst_QMediaPlaylist::insert() +{ + QMediaPlaylist playlist; + QVERIFY(!playlist.isReadOnly()); + + playlist.addMedia(content1); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0), content1); + + playlist.addMedia(content2); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(1), content2); + + QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(mediaAboutToBeInserted(int,int))); + QSignalSpy insertedSignalSpy(&playlist, SIGNAL(mediaInserted(int,int))); + + playlist.insertMedia(1, content3); + QCOMPARE(playlist.mediaCount(), 3); + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content3); + QCOMPARE(playlist.media(2), content2); + + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + QMediaContent content4(QUrl(QLatin1String("file:///4"))); + QMediaContent content5(QUrl(QLatin1String("file:///5"))); + playlist.insertMedia(1, QList() << content4 << content5); + + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content4); + QCOMPARE(playlist.media(2), content5); + QCOMPARE(playlist.media(3), content3); + QCOMPARE(playlist.media(4), content2); + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy[0][0].toInt(), 1); + QCOMPARE(aboutToBeInsertedSignalSpy[0][1].toInt(), 2); + + QCOMPARE(insertedSignalSpy.count(), 1); + QCOMPARE(insertedSignalSpy[0][0].toInt(), 1); + QCOMPARE(insertedSignalSpy[0][1].toInt(), 2); + + aboutToBeInsertedSignalSpy.clear(); + insertedSignalSpy.clear(); + + playlist.insertMedia(1, QList()); + QCOMPARE(aboutToBeInsertedSignalSpy.count(), 0); + QCOMPARE(insertedSignalSpy.count(), 0); +} + + +void tst_QMediaPlaylist::currentItem() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + + QCOMPARE(playlist.currentIndex(), -1); + QCOMPARE(playlist.currentMedia(), QMediaContent()); + + QCOMPARE(playlist.nextIndex(), 0); + QCOMPARE(playlist.nextIndex(2), 1); + QCOMPARE(playlist.previousIndex(), 1); + QCOMPARE(playlist.previousIndex(2), 0); + + playlist.setCurrentIndex(0); + QCOMPARE(playlist.currentIndex(), 0); + QCOMPARE(playlist.currentMedia(), content1); + + QCOMPARE(playlist.nextIndex(), 1); + QCOMPARE(playlist.nextIndex(2), -1); + QCOMPARE(playlist.previousIndex(), -1); + QCOMPARE(playlist.previousIndex(2), -1); + + playlist.setCurrentIndex(1); + QCOMPARE(playlist.currentIndex(), 1); + QCOMPARE(playlist.currentMedia(), content2); + + QCOMPARE(playlist.nextIndex(), -1); + QCOMPARE(playlist.nextIndex(2), -1); + QCOMPARE(playlist.previousIndex(), 0); + QCOMPARE(playlist.previousIndex(2), -1); + + QTest::ignoreMessage(QtWarningMsg, "QMediaPlaylistNavigator: Jump outside playlist range "); + playlist.setCurrentIndex(2); + + QCOMPARE(playlist.currentIndex(), -1); + QCOMPARE(playlist.currentMedia(), QMediaContent()); +} + +void tst_QMediaPlaylist::clear() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + + playlist.clear(); + QVERIFY(playlist.isEmpty()); + QCOMPARE(playlist.mediaCount(), 0); +} + +void tst_QMediaPlaylist::removeMedia() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + QSignalSpy aboutToBeRemovedSignalSpy(&playlist, SIGNAL(mediaAboutToBeRemoved(int,int))); + QSignalSpy removedSignalSpy(&playlist, SIGNAL(mediaRemoved(int,int))); + playlist.removeMedia(1); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(1), content3); + + QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(removedSignalSpy.count(), 1); + QCOMPARE(removedSignalSpy.first()[0].toInt(), 1); + QCOMPARE(removedSignalSpy.first()[1].toInt(), 1); + + aboutToBeRemovedSignalSpy.clear(); + removedSignalSpy.clear(); + + playlist.removeMedia(0,1); + QVERIFY(playlist.isEmpty()); + + QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 0); + QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1); + + QCOMPARE(removedSignalSpy.count(), 1); + QCOMPARE(removedSignalSpy.first()[0].toInt(), 0); + QCOMPARE(removedSignalSpy.first()[1].toInt(), 1); + + + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + playlist.removeMedia(0,1); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0), content3); +} + +void tst_QMediaPlaylist::saveAndLoad() +{ + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + QVERIFY(playlist.errorString().isEmpty()); + + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + + QTest::ignoreMessage(QtWarningMsg, "Load static plugins for \"/playlistformats/\" "); + bool res = playlist.save(&buffer, "unsupported_format"); + QVERIFY(!res); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed())); + playlist.load(&buffer, "unsupported_format"); + QCOMPARE(errorSignal.size(), 1); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + res = playlist.save(QUrl(QLatin1String("tmp.unsupported_format")), "unsupported_format"); + QVERIFY(!res); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + errorSignal.clear(); + playlist.load(QUrl(QLatin1String("tmp.unsupported_format")), "unsupported_format"); + QCOMPARE(errorSignal.size(), 1); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + QVERIFY(!playlist.errorString().isEmpty()); + + res = playlist.save(&buffer, "m3u"); + + QVERIFY(res); + QVERIFY(buffer.pos() > 0); + buffer.seek(0); + + QMediaPlaylist playlist2; + playlist2.load(&buffer, "m3u"); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + + QCOMPARE(playlist.mediaCount(), playlist2.mediaCount()); + QCOMPARE(playlist.media(0), playlist2.media(0)); + QCOMPARE(playlist.media(1), playlist2.media(1)); + QCOMPARE(playlist.media(3), playlist2.media(3)); + + res = playlist.save(QUrl(QLatin1String("tmp.m3u")), "m3u"); + QVERIFY(res); + + playlist2.clear(); + QVERIFY(playlist2.isEmpty()); + playlist2.load(QUrl(QLatin1String("tmp.m3u")), "m3u"); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + + QCOMPARE(playlist.mediaCount(), playlist2.mediaCount()); + QCOMPARE(playlist.media(0), playlist2.media(0)); + QCOMPARE(playlist.media(1), playlist2.media(1)); + QCOMPARE(playlist.media(3), playlist2.media(3)); +} + +void tst_QMediaPlaylist::playbackMode_data() +{ + QTest::addColumn("playbackMode"); + QTest::addColumn("expectedPrevious"); + QTest::addColumn("pos"); + QTest::addColumn("expectedNext"); + + QTest::newRow("Linear, 0") << QMediaPlaylist::Linear << -1 << 0 << 1; + QTest::newRow("Linear, 1") << QMediaPlaylist::Linear << 0 << 1 << 2; + QTest::newRow("Linear, 2") << QMediaPlaylist::Linear << 1 << 2 << -1; + + QTest::newRow("Loop, 0") << QMediaPlaylist::Loop << 2 << 0 << 1; + QTest::newRow("Loop, 1") << QMediaPlaylist::Loop << 0 << 1 << 2; + QTest::newRow("Lopp, 2") << QMediaPlaylist::Loop << 1 << 2 << 0; + + QTest::newRow("ItemOnce, 1") << QMediaPlaylist::CurrentItemOnce << -1 << 1 << -1; + QTest::newRow("ItemInLoop, 1") << QMediaPlaylist::CurrentItemInLoop << 1 << 1 << 1; + +} + +void tst_QMediaPlaylist::playbackMode() +{ + QFETCH(QMediaPlaylist::PlaybackMode, playbackMode); + QFETCH(int, expectedPrevious); + QFETCH(int, pos); + QFETCH(int, expectedNext); + + QMediaPlaylist playlist; + playlist.addMedia(content1); + playlist.addMedia(content2); + playlist.addMedia(content3); + + QCOMPARE(playlist.playbackMode(), QMediaPlaylist::Linear); + QCOMPARE(playlist.currentIndex(), -1); + + playlist.setPlaybackMode(playbackMode); + QCOMPARE(playlist.playbackMode(), playbackMode); + + playlist.setCurrentIndex(pos); + QCOMPARE(playlist.currentIndex(), pos); + QCOMPARE(playlist.nextIndex(), expectedNext); + QCOMPARE(playlist.previousIndex(), expectedPrevious); + + playlist.next(); + QCOMPARE(playlist.currentIndex(), expectedNext); + + playlist.setCurrentIndex(pos); + playlist.previous(); + QCOMPARE(playlist.currentIndex(), expectedPrevious); +} + +void tst_QMediaPlaylist::shuffle() +{ + QMediaPlaylist playlist; + QList contentList; + + for (int i=0; i<100; i++) { + QMediaContent content(QUrl(QString::number(i))); + contentList.append(content); + playlist.addMedia(content); + } + + playlist.shuffle(); + + QList shuffledContentList; + for (int i=0; i() << content1 << content2)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.insertMedia(1, content1)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.insertMedia(1, QList() << content1 << content2)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.removeMedia(1)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.removeMedia(0,2)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(!playlist.clear()); + QCOMPARE(playlist.mediaCount(), 3); + + //but it is still allowed to append/insert an empty list + QVERIFY(playlist.addMedia(QList())); + QVERIFY(playlist.insertMedia(1, QList())); + + playlist.shuffle(); + //it's still the same + QCOMPARE(playlist.media(0), content1); + QCOMPARE(playlist.media(1), content2); + QCOMPARE(playlist.media(2), content3); + QCOMPARE(playlist.media(3), QMediaContent()); + + + //load to read only playlist should fail, + //unless underlaying provider supports it + QBuffer buffer; + buffer.open(QBuffer::ReadWrite); + buffer.write(QByteArray("file:///1\nfile:///2")); + buffer.seek(0); + + QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed())); + playlist.load(&buffer, "m3u"); + QCOMPARE(errorSignal.size(), 1); + QCOMPARE(playlist.error(), QMediaPlaylist::AccessDeniedError); + QVERIFY(!playlist.errorString().isEmpty()); + QCOMPARE(playlist.mediaCount(), 3); + + errorSignal.clear(); + playlist.load(QUrl(QLatin1String("tmp.m3u")), "m3u"); + + QCOMPARE(errorSignal.size(), 1); + QCOMPARE(playlist.error(), QMediaPlaylist::AccessDeniedError); + QVERIFY(!playlist.errorString().isEmpty()); + QCOMPARE(playlist.mediaCount(), 3); +} + +void tst_QMediaPlaylist::setMediaObject() +{ + MockReadOnlyPlaylistObject mediaObject; + + QMediaPlaylist playlist; + QVERIFY(playlist.mediaObject() == 0); + QVERIFY(!playlist.isReadOnly()); + + playlist.setMediaObject(&mediaObject); + QCOMPARE(playlist.mediaObject(), qobject_cast(&mediaObject)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(playlist.isReadOnly()); + + playlist.setMediaObject(0); + QVERIFY(playlist.mediaObject() == 0); + QCOMPARE(playlist.mediaCount(), 0); + QVERIFY(!playlist.isReadOnly()); + + playlist.setMediaObject(&mediaObject); + QCOMPARE(playlist.mediaObject(), qobject_cast(&mediaObject)); + QCOMPARE(playlist.mediaCount(), 3); + QVERIFY(playlist.isReadOnly()); +} + +QTEST_MAIN(tst_QMediaPlaylist) +#include "tst_qmediaplaylist.moc" + diff --git a/tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro b/tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro new file mode 100644 index 0000000..ea9bc0f --- /dev/null +++ b/tests/auto/qmediaplaylistnavigator/qmediaplaylistnavigator.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaplaylistnavigator.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp b/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp new file mode 100644 index 0000000..a5eb3fe --- /dev/null +++ b/tests/auto/qmediaplaylistnavigator/tst_qmediaplaylistnavigator.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include +#include + + +class tst_QMediaPlaylistNavigator : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + +private slots: + void construction(); + void setPlaylist(); + void linearPlayback(); + void loopPlayback(); + void currentItemOnce(); + void currentItemInLoop(); + void randomPlayback(); +}; + +void tst_QMediaPlaylistNavigator::init() +{ +} + +void tst_QMediaPlaylistNavigator::cleanup() +{ +} + +void tst_QMediaPlaylistNavigator::construction() +{ + QLocalMediaPlaylistProvider playlist; + QCOMPARE(playlist.mediaCount(), 0); + + QMediaPlaylistNavigator navigator(&playlist); + QVERIFY(navigator.currentItem().isNull()); + QCOMPARE(navigator.currentIndex(), -1); +} + +void tst_QMediaPlaylistNavigator::setPlaylist() +{ + QMediaPlaylistNavigator navigator(0); + QVERIFY(navigator.playlist() != 0); + QCOMPARE(navigator.playlist()->mediaCount(), 0); + QCOMPARE(navigator.playlist()->media(0), QMediaContent()); + QVERIFY(navigator.playlist()->isReadOnly() ); + + QLocalMediaPlaylistProvider playlist; + QCOMPARE(playlist.mediaCount(), 0); + + navigator.setPlaylist(&playlist); + QCOMPARE(navigator.playlist(), (QMediaPlaylistProvider*)&playlist); + QCOMPARE(navigator.playlist()->mediaCount(), 0); + QVERIFY(!navigator.playlist()->isReadOnly() ); +} + +void tst_QMediaPlaylistNavigator::linearPlayback() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::Linear); + QTest::ignoreMessage(QtWarningMsg, "QMediaPlaylistNavigator: Jump outside playlist range "); + navigator.jump(0);//it's ok to have warning here + QVERIFY(navigator.currentItem().isNull()); + QCOMPARE(navigator.currentIndex(), -1); + + QMediaContent content1(QUrl(QLatin1String("file:///1"))); + playlist.addMedia(content1); + navigator.jump(0); + QVERIFY(!navigator.currentItem().isNull()); + + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), QMediaContent()); + QCOMPARE(navigator.nextItem(2), QMediaContent()); + QCOMPARE(navigator.previousItem(), QMediaContent()); + QCOMPARE(navigator.previousItem(2), QMediaContent()); + + QMediaContent content2(QUrl(QLatin1String("file:///2"))); + playlist.addMedia(content2); + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), content2); + QCOMPARE(navigator.nextItem(2), QMediaContent()); + QCOMPARE(navigator.previousItem(), QMediaContent()); + QCOMPARE(navigator.previousItem(2), QMediaContent()); + + navigator.jump(1); + QCOMPARE(navigator.currentIndex(), 1); + QCOMPARE(navigator.currentItem(), content2); + QCOMPARE(navigator.nextItem(), QMediaContent()); + QCOMPARE(navigator.nextItem(2), QMediaContent()); + QCOMPARE(navigator.previousItem(), content1); + QCOMPARE(navigator.previousItem(2), QMediaContent()); + + navigator.jump(0); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.next();//jump to the first item + QCOMPARE(navigator.currentIndex(), 0); + + navigator.previous(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.previous();//jump to the last item + QCOMPARE(navigator.currentIndex(), 1); +} + +void tst_QMediaPlaylistNavigator::loopPlayback() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::Loop); + QTest::ignoreMessage(QtWarningMsg, "QMediaPlaylistNavigator: Jump outside playlist range "); + navigator.jump(0); + QVERIFY(navigator.currentItem().isNull()); + QCOMPARE(navigator.currentIndex(), -1); + + QMediaContent content1(QUrl(QLatin1String("file:///1"))); + playlist.addMedia(content1); + navigator.jump(0); + QVERIFY(!navigator.currentItem().isNull()); + + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), content1); + QCOMPARE(navigator.nextItem(2), content1); + QCOMPARE(navigator.previousItem(), content1); + QCOMPARE(navigator.previousItem(2), content1); + + QMediaContent content2(QUrl(QLatin1String("file:///2"))); + playlist.addMedia(content2); + QCOMPARE(navigator.currentIndex(), 0); + QCOMPARE(navigator.currentItem(), content1); + QCOMPARE(navigator.nextItem(), content2); + QCOMPARE(navigator.nextItem(2), content1); //loop over end of the list + QCOMPARE(navigator.previousItem(), content2); + QCOMPARE(navigator.previousItem(2), content1); + + navigator.jump(1); + QCOMPARE(navigator.currentIndex(), 1); + QCOMPARE(navigator.currentItem(), content2); + QCOMPARE(navigator.nextItem(), content1); + QCOMPARE(navigator.nextItem(2), content2); + QCOMPARE(navigator.previousItem(), content1); + QCOMPARE(navigator.previousItem(2), content2); + + navigator.jump(0); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 0); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 0); +} + +void tst_QMediaPlaylistNavigator::currentItemOnce() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::CurrentItemOnce); + + QCOMPARE(navigator.playbackMode(), QMediaPlaylist::CurrentItemOnce); + QCOMPARE(navigator.currentIndex(), -1); + + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///1")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///2")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///3")))); + + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + + navigator.jump(1); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.jump(1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), -1); +} + +void tst_QMediaPlaylistNavigator::currentItemInLoop() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::CurrentItemInLoop); + + QCOMPARE(navigator.playbackMode(), QMediaPlaylist::CurrentItemInLoop); + QCOMPARE(navigator.currentIndex(), -1); + + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///1")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///2")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///3")))); + + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), -1); + navigator.jump(1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.next(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 1); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), 1); +} + +void tst_QMediaPlaylistNavigator::randomPlayback() +{ + QLocalMediaPlaylistProvider playlist; + QMediaPlaylistNavigator navigator(&playlist); + + navigator.setPlaybackMode(QMediaPlaylist::Random); + + QCOMPARE(navigator.playbackMode(), QMediaPlaylist::Random); + QCOMPARE(navigator.currentIndex(), -1); + + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///1")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///2")))); + playlist.addMedia(QMediaContent(QUrl(QLatin1String("file:///3")))); + + playlist.shuffle(); + + QCOMPARE(navigator.currentIndex(), -1); + navigator.next(); + int pos1 = navigator.currentIndex(); + navigator.next(); + int pos2 = navigator.currentIndex(); + navigator.next(); + int pos3 = navigator.currentIndex(); + + QVERIFY(pos1 != -1); + QVERIFY(pos2 != -1); + QVERIFY(pos3 != -1); + + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos2); + navigator.next(); + QCOMPARE(navigator.currentIndex(), pos3); + navigator.next(); + int pos4 = navigator.currentIndex(); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos3); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos2); + navigator.previous(); + QCOMPARE(navigator.currentIndex(), pos1); + navigator.previous(); + int pos0 = navigator.currentIndex(); + QVERIFY(pos0 != -1); + navigator.next(); + navigator.next(); + navigator.next(); + navigator.next(); + QCOMPARE(navigator.currentIndex(), pos4); + +} + +QTEST_MAIN(tst_QMediaPlaylistNavigator) +#include "tst_qmediaplaylistnavigator.moc" diff --git a/tests/auto/qmediapluginloader/qmediapluginloader.pro b/tests/auto/qmediapluginloader/qmediapluginloader.pro new file mode 100644 index 0000000..66950e9 --- /dev/null +++ b/tests/auto/qmediapluginloader/qmediapluginloader.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediapluginloader.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp b/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp new file mode 100644 index 0000000..1ed23a0 --- /dev/null +++ b/tests/auto/qmediapluginloader/tst_qmediapluginloader.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include + +#include +#include + + + +class tst_QMediaPluginLoader : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void testInstance(); + void testInstances(); + void testInvalidKey(); + +private: + QMediaPluginLoader *loader; +}; + +void tst_QMediaPluginLoader::initTestCase() +{ + loader = new QMediaPluginLoader(QMediaServiceProviderFactoryInterface_iid, + QLatin1String("/mediaservice"), + Qt::CaseInsensitive); +} + +void tst_QMediaPluginLoader::cleanupTestCase() +{ + delete loader; +} + +void tst_QMediaPluginLoader::testInstance() +{ + const QStringList keys = loader->keys(); + + if (keys.isEmpty()) // Test is invalidated, skip. + QSKIP("No plug-ins available", SkipAll); + + foreach (const QString &key, keys) + QVERIFY(loader->instance(key) != 0); +} + +void tst_QMediaPluginLoader::testInstances() +{ + const QStringList keys = loader->keys(); + + if (keys.isEmpty()) // Test is invalidated, skip. + QSKIP("No plug-ins available", SkipAll); + + foreach (const QString &key, keys) + QVERIFY(loader->instances(key).size() > 0); +} + +// Last so as to not interfere with the other tests if there is a failure. +void tst_QMediaPluginLoader::testInvalidKey() +{ + const QString key(QLatin1String("invalid-key")); + + // This test assumes there is no 'invalid-key' in the key list, verify that. + if (loader->keys().contains(key)) + QSKIP("a plug-in includes the invalid key", SkipAll); + + QVERIFY(loader->instance(key) == 0); + + // Test looking up the key hasn't inserted it into the list. See QMap::operator[]. + QVERIFY(!loader->keys().contains(key)); + + QVERIFY(loader->instances(key).isEmpty()); + QVERIFY(!loader->keys().contains(key)); +} + +QTEST_MAIN(tst_QMediaPluginLoader) + +#include "tst_qmediapluginloader.moc" diff --git a/tests/auto/qmediaresource/qmediaresource.pro b/tests/auto/qmediaresource/qmediaresource.pro new file mode 100644 index 0000000..2741608 --- /dev/null +++ b/tests/auto/qmediaresource/qmediaresource.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaresource.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediaresource/tst_qmediaresource.cpp b/tests/auto/qmediaresource/tst_qmediaresource.cpp new file mode 100644 index 0000000..55ddcab --- /dev/null +++ b/tests/auto/qmediaresource/tst_qmediaresource.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include + + +class tst_QMediaResource : public QObject +{ + Q_OBJECT +private slots: + void constructNull(); + void construct_data(); + void construct(); + void setResolution(); + void equality(); + void copy(); + void assign(); +}; + +void tst_QMediaResource::constructNull() +{ + QMediaResource resource; + + QCOMPARE(resource.isNull(), true); + QCOMPARE(resource.url(), QUrl()); + QCOMPARE(resource.mimeType(), QString()); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); +} + +void tst_QMediaResource::construct_data() +{ + QTest::addColumn("url"); + QTest::addColumn("mimeType"); + QTest::addColumn("language"); + QTest::addColumn("audioCodec"); + QTest::addColumn("videoCodec"); + QTest::addColumn("dataSize"); + QTest::addColumn("audioBitRate"); + QTest::addColumn("sampleRate"); + QTest::addColumn("channelCount"); + QTest::addColumn("videoBitRate"); + QTest::addColumn("resolution"); + + QTest::newRow("audio content") + << QUrl(QString::fromLatin1("http:://test.com/test.mp3")) + << QString::fromLatin1("audio/mpeg") + << QString::fromLatin1("eng") + << QString::fromLatin1("mp3") + << QString() + << qint64(5465433) + << 128000 + << 44100 + << 2 + << 0 + << QSize(); + QTest::newRow("image content") + << QUrl(QString::fromLatin1("http:://test.com/test.jpg")) + << QString::fromLatin1("image/jpeg") + << QString() + << QString() + << QString() + << qint64(23600) + << 0 + << 0 + << 0 + << 0 + << QSize(640, 480); + QTest::newRow("video content") + << QUrl(QString::fromLatin1("http:://test.com/test.mp4")) + << QString::fromLatin1("video/mp4") + << QString() + << QString::fromLatin1("aac") + << QString::fromLatin1("h264") + << qint64(36245851) + << 96000 + << 44000 + << 5 + << 750000 + << QSize(720, 576); + QTest::newRow("thumbnail") + << QUrl(QString::fromLatin1("file::///thumbs/test.png")) + << QString::fromLatin1("image/png") + << QString() + << QString() + << QString() + << qint64(2360) + << 0 + << 0 + << 0 + << 0 + << QSize(128, 128); +} + +void tst_QMediaResource::construct() +{ + QFETCH(QUrl, url); + QFETCH(QString, mimeType); + QFETCH(QString, language); + QFETCH(QString, audioCodec); + QFETCH(QString, videoCodec); + QFETCH(qint64, dataSize); + QFETCH(int, audioBitRate); + QFETCH(int, sampleRate); + QFETCH(int, channelCount); + QFETCH(int, videoBitRate); + QFETCH(QSize, resolution); + + { + QMediaResource resource(url); + + QCOMPARE(resource.isNull(), false); + QCOMPARE(resource.url(), url); + QCOMPARE(resource.mimeType(), QString()); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); + } + { + QMediaResource resource(url, mimeType); + + QCOMPARE(resource.isNull(), false); + QCOMPARE(resource.url(), url); + QCOMPARE(resource.mimeType(), mimeType); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); + + resource.setLanguage(language); + resource.setAudioCodec(audioCodec); + resource.setVideoCodec(videoCodec); + resource.setDataSize(dataSize); + resource.setAudioBitRate(audioBitRate); + resource.setSampleRate(sampleRate); + resource.setChannelCount(channelCount); + resource.setVideoBitRate(videoBitRate); + resource.setResolution(resolution); + + QCOMPARE(resource.language(), language); + QCOMPARE(resource.audioCodec(), audioCodec); + QCOMPARE(resource.videoCodec(), videoCodec); + QCOMPARE(resource.dataSize(), dataSize); + QCOMPARE(resource.audioBitRate(), audioBitRate); + QCOMPARE(resource.sampleRate(), sampleRate); + QCOMPARE(resource.channelCount(), channelCount); + QCOMPARE(resource.videoBitRate(), videoBitRate); + QCOMPARE(resource.resolution(), resolution); + } +} + +void tst_QMediaResource::setResolution() +{ + QMediaResource resource( + QUrl(QString::fromLatin1("file::///thumbs/test.png")), + QString::fromLatin1("image/png")); + + QCOMPARE(resource.resolution(), QSize()); + + resource.setResolution(QSize(120, 80)); + QCOMPARE(resource.resolution(), QSize(120, 80)); + + resource.setResolution(QSize(-1, 23)); + QCOMPARE(resource.resolution(), QSize(-1, 23)); + + resource.setResolution(QSize(-43, 34)); + QCOMPARE(resource.resolution(), QSize(-43, 34)); + + resource.setResolution(QSize(64, -1)); + QCOMPARE(resource.resolution(), QSize(64, -1)); + + resource.setResolution(QSize(64, -83)); + QCOMPARE(resource.resolution(), QSize(64, -83)); + + resource.setResolution(QSize(-12, -83)); + QCOMPARE(resource.resolution(), QSize(-12, -83)); + + resource.setResolution(QSize()); + QCOMPARE(resource.resolution(), QSize(-1, -1)); + + resource.setResolution(120, 80); + QCOMPARE(resource.resolution(), QSize(120, 80)); + + resource.setResolution(-1, 23); + QCOMPARE(resource.resolution(), QSize(-1, 23)); + + resource.setResolution(-43, 34); + QCOMPARE(resource.resolution(), QSize(-43, 34)); + + resource.setResolution(64, -1); + QCOMPARE(resource.resolution(), QSize(64, -1)); + + resource.setResolution(64, -83); + QCOMPARE(resource.resolution(), QSize(64, -83)); + + resource.setResolution(-12, -83); + QCOMPARE(resource.resolution(), QSize(-12, -83)); + + resource.setResolution(-1, -1); + QCOMPARE(resource.resolution(), QSize()); +} + +void tst_QMediaResource::equality() +{ + QMediaResource resource1( + QUrl(QString::fromLatin1("http://test.com/test.mp4")), + QString::fromLatin1("video/mp4")); + QMediaResource resource2( + QUrl(QString::fromLatin1("http://test.com/test.mp4")), + QString::fromLatin1("video/mp4")); + QMediaResource resource3( + QUrl(QString::fromLatin1("file:///thumbs/test.jpg"))); + QMediaResource resource4( + QUrl(QString::fromLatin1("file:///thumbs/test.jpg"))); + QMediaResource resource5( + QUrl(QString::fromLatin1("http://test.com/test.mp3")), + QString::fromLatin1("audio/mpeg")); + + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + QCOMPARE(resource3 == resource4, true); + QCOMPARE(resource3 != resource4, false); + + QCOMPARE(resource1 == resource3, false); + QCOMPARE(resource1 != resource3, true); + + QCOMPARE(resource1 == resource5, false); + QCOMPARE(resource1 != resource5, true); + + resource1.setAudioCodec(QString::fromLatin1("mp3")); + resource2.setAudioCodec(QString::fromLatin1("aac")); + + // Not equal differing audio codecs. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource1.setAudioCodec(QString::fromLatin1("aac")); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setVideoCodec(QString()); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setVideoCodec(QString::fromLatin1("h264")); + + // Not equal differing video codecs. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setVideoCodec(QString::fromLatin1("h264")); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource2.setDataSize(0); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setDataSize(546423); + + // Not equal differing video codecs. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setDataSize(546423); + + // Equal. + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setAudioBitRate(96000); + resource1.setSampleRate(48000); + resource2.setSampleRate(44100); + resource1.setChannelCount(0); + resource1.setVideoBitRate(900000); + resource2.setLanguage(QString::fromLatin1("eng")); + + // Not equal, audio bit rate, sample rate, video bit rate, and + // language. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setAudioBitRate(96000); + resource1.setSampleRate(44100); + + // Not equal, differing video bit rate, and language. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource2.setVideoBitRate(900000); + resource1.setLanguage(QString::fromLatin1("eng")); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setResolution(QSize()); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource2.setResolution(-1, -1); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); + + resource1.setResolution(QSize(-640, -480)); + + // Not equal, differing resolution. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + resource1.setResolution(QSize(640, 480)); + resource2.setResolution(QSize(800, 600)); + + // Not equal, differing resolution. + QCOMPARE(resource1 == resource2, false); + QCOMPARE(resource1 != resource2, true); + + resource1.setResolution(800, 600); + + // Equal + QCOMPARE(resource1 == resource2, true); + QCOMPARE(resource1 != resource2, false); +} + +void tst_QMediaResource::copy() +{ + const QUrl url(QString::fromLatin1("http://test.com/test.mp4")); + const QString mimeType(QLatin1String("video/mp4")); + const QString amrCodec(QLatin1String("amr")); + const QString mp3Codec(QLatin1String("mp3")); + const QString aacCodec(QLatin1String("aac")); + const QString h264Codec(QLatin1String("h264")); + + QMediaResource original(url, mimeType); + original.setAudioCodec(amrCodec); + + QMediaResource copy(original); + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + QCOMPARE(copy.audioCodec(), amrCodec); + + QCOMPARE(original == copy, true); + QCOMPARE(original != copy, false); + + original.setAudioCodec(mp3Codec); + + QCOMPARE(copy.audioCodec(), amrCodec); + QCOMPARE(original == copy, false); + QCOMPARE(original != copy, true); + + copy.setAudioCodec(aacCodec); + copy.setVideoCodec(h264Codec); + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + + QCOMPARE(original.audioCodec(), mp3Codec); +} + +void tst_QMediaResource::assign() +{ + const QUrl url(QString::fromLatin1("http://test.com/test.mp4")); + const QString mimeType(QLatin1String("video/mp4")); + const QString amrCodec(QLatin1String("amr")); + const QString mp3Codec(QLatin1String("mp3")); + const QString aacCodec(QLatin1String("aac")); + const QString h264Codec(QLatin1String("h264")); + + QMediaResource copy(QUrl(QString::fromLatin1("file:///thumbs/test.jpg"))); + + QMediaResource original(url, mimeType); + original.setAudioCodec(amrCodec); + + copy = original; + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + QCOMPARE(copy.audioCodec(), amrCodec); + + QCOMPARE(original == copy, true); + QCOMPARE(original != copy, false); + + original.setAudioCodec(mp3Codec); + + QCOMPARE(copy.audioCodec(), amrCodec); + QCOMPARE(original == copy, false); + QCOMPARE(original != copy, true); + + copy.setAudioCodec(aacCodec); + copy.setVideoCodec(h264Codec); + + QCOMPARE(copy.url(), url); + QCOMPARE(copy.mimeType(), mimeType); + + QCOMPARE(original.audioCodec(), mp3Codec); +} + +QTEST_MAIN(tst_QMediaResource) + +#include "tst_qmediaresource.moc" diff --git a/tests/auto/qmediaservice/qmediaservice.pro b/tests/auto/qmediaservice/qmediaservice.pro new file mode 100644 index 0000000..f877665 --- /dev/null +++ b/tests/auto/qmediaservice/qmediaservice.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaservice.cpp + +QT = core gui multimedia + diff --git a/tests/auto/qmediaservice/tst_qmediaservice.cpp b/tests/auto/qmediaservice/tst_qmediaservice.cpp new file mode 100644 index 0000000..3c3684a --- /dev/null +++ b/tests/auto/qmediaservice/tst_qmediaservice.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include +#include +#include + +#include +#include + +class QtTestMediaService; + + +class tst_QMediaService : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + + void control_iid(); + void control(); +}; + + +class QtTestMediaControlA : public QMediaControl +{ + Q_OBJECT +}; + + +#define QtTestMediaControlA_iid "com.nokia.QtTestMediaControlA" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlA, QtTestMediaControlA_iid) + + +class QtTestMediaControlB : public QMediaControl +{ + Q_OBJECT +}; + +#define QtTestMediaControlB_iid "com.nokia.QtTestMediaControlB" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlB, QtTestMediaControlB_iid) + + +class QtTestMediaControlC : public QMediaControl +{ + Q_OBJECT +}; + +#define QtTestMediaControlC_iid "com.nokia.QtTestMediaControlC" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlC, QtTestMediaControlA_iid) // Yes A. + +class QtTestMediaControlD : public QMediaControl +{ + Q_OBJECT +}; + +#define QtTestMediaControlD_iid "com.nokia.QtTestMediaControlD" +Q_MEDIA_DECLARE_CONTROL(QtTestMediaControlD, QtTestMediaControlD_iid) + +class QtTestMediaControlE : public QMediaControl +{ + Q_OBJECT +}; + +struct QtTestDevice +{ + QtTestDevice() {} + QtTestDevice(const QString &name, const QString &description, const QIcon &icon) + : name(name), description(description), icon(icon) + { + } + + QString name; + QString description; + QIcon icon; +}; + +class QtTestVideoDeviceControl : public QVideoDeviceControl +{ +public: + QtTestVideoDeviceControl(QObject *parent = 0) + : QVideoDeviceControl(parent) + , m_selectedDevice(-1) + , m_defaultDevice(-1) + { + } + + int deviceCount() const { return devices.count(); } + + QString deviceName(int index) const { return devices.value(index).name; } + QString deviceDescription(int index) const { return devices.value(index).description; } + QIcon deviceIcon(int index) const { return devices.value(index).icon; } + + int defaultDevice() const { return m_defaultDevice; } + void setDefaultDevice(int index) { m_defaultDevice = index; } + + int selectedDevice() const { return m_selectedDevice; } + void setSelectedDevice(int index) + { + emit selectedDeviceChanged(m_selectedDevice = index); + emit selectedDeviceChanged(devices.value(index).name); + } + + QList devices; + +private: + int m_selectedDevice; + int m_defaultDevice; +}; + +class QtTestMediaService : public QMediaService +{ + Q_OBJECT +public: + QtTestMediaService() + : QMediaService(0) + , hasDeviceControls(false) + { + } + + QMediaControl* control(const char *name) const + { + if (strcmp(name, QtTestMediaControlA_iid) == 0) + return const_cast(&controlA); + else if (strcmp(name, QtTestMediaControlB_iid) == 0) + return const_cast(&controlB); + else if (strcmp(name, QtTestMediaControlC_iid) == 0) + return const_cast(&controlC); + else if (hasDeviceControls && strcmp(name, QVideoDeviceControl_iid) == 0) + return const_cast(&videoDeviceControl); + else + return 0; + } + + using QMediaService::control; + + QtTestMediaControlA controlA; + QtTestMediaControlB controlB; + QtTestMediaControlC controlC; + QtTestVideoDeviceControl videoDeviceControl; + bool hasDeviceControls; +}; + +void tst_QMediaService::initTestCase() +{ +} + +void tst_QMediaService::control_iid() +{ + const char *nullString = 0; + + // Default implementation. + QCOMPARE(qmediacontrol_iid(), nullString); + + // Partial template. + QVERIFY(qstrcmp(qmediacontrol_iid(), QtTestMediaControlA_iid) == 0); +} + +void tst_QMediaService::control() +{ + QtTestMediaService service; + + QCOMPARE(service.control(), &service.controlA); + QCOMPARE(service.control(), &service.controlB); + QVERIFY(!service.control()); // Faulty implementation returns A. + QVERIFY(!service.control()); // No control of that type. +} + +QTEST_MAIN(tst_QMediaService) + +#include "tst_qmediaservice.moc" diff --git a/tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro b/tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro new file mode 100644 index 0000000..9aaa9e5 --- /dev/null +++ b/tests/auto/qmediaserviceprovider/qmediaserviceprovider.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediaserviceprovider.cpp + +QT = core gui multimedia + diff --git a/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp new file mode 100644 index 0000000..a2c1be5 --- /dev/null +++ b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp @@ -0,0 +1,458 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include + +#include +#include +#include +#include +#include +#include + +class MockMediaService : public QMediaService +{ + Q_OBJECT +public: + MockMediaService(const QString& name, QObject *parent = 0) : QMediaService(parent) + { setObjectName(name); } + ~MockMediaService() {} + + QMediaControl* control(const char *) const {return 0;} +}; + +class MockServicePlugin1 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedFormatsInterface, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const + { + return QStringList() << + QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) << + QLatin1String(Q_MEDIASERVICE_CAMERA); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin1"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const + { + if (codecs.contains(QLatin1String("mpeg4"))) + return QtMedia::NotSupported; + + if (mimeType == "audio/ogg") { + return QtMedia::ProbablySupported; + } + + return QtMedia::MaybeSupported; + } + + QStringList supportedMimeTypes() const + { + return QStringList("audio/ogg"); + } + + QList devices(const QByteArray &service) const + { + QList res; + if (service == QByteArray(Q_MEDIASERVICE_CAMERA)) + res << "camera1" << "camera2"; + return res; + } + + QString deviceDescription(const QByteArray &service, const QByteArray &device) + { + if (devices(service).contains(device)) + return QString(device)+" description"; + else + return QString(); + } +}; + +class MockServicePlugin2 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedFormatsInterface, + public QMediaServiceFeaturesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) + Q_INTERFACES(QMediaServiceFeaturesInterface) +public: + QStringList keys() const + { + return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin2"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QtMedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const + { + Q_UNUSED(codecs); + + if (mimeType == "audio/wav") + return QtMedia::PreferedService; + + return QtMedia::NotSupported; + } + + QStringList supportedMimeTypes() const + { + return QStringList("audio/wav"); + } + + QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const + { + if (service == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) + return QMediaServiceProviderHint::LowLatencyPlayback; + else + return 0; + } +}; + + +class MockServicePlugin3 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const + { + return QStringList() << + QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) << + QLatin1String(Q_MEDIASERVICE_CAMERA) << + QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin3"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QList devices(const QByteArray &service) const + { + QList res; + if (service == QByteArray(Q_MEDIASERVICE_CAMERA)) + res << "camera3" << "camera4"; + else if (service == QByteArray(Q_MEDIASERVICE_AUDIOSOURCE)) + res << "audiosource1" << "audiosource2"; + + return res; + } + + QString deviceDescription(const QByteArray &service, const QByteArray &device) + { + if (devices(service).contains(device)) + return QString(device)+" description"; + else + return QString(); + } +}; + + + +class MockMediaServiceProvider : public QMediaServiceProvider +{ + QMediaService* requestService(const QByteArray &type, const QMediaServiceProviderHint &) + { + Q_UNUSED(type); + return 0; + } + + void releaseService(QMediaService *service) + { + Q_UNUSED(service); + } +}; + + +class tst_QMediaServiceProvider : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + +private slots: + void testDefaultProviderAvailable(); + void testObtainService(); + void testHasSupport(); + void testSupportedMimeTypes(); + void testDevices(); + void testProviderHints(); + +private: + QObjectList plugins; +}; + +void tst_QMediaServiceProvider::initTestCase() +{ + plugins << new MockServicePlugin1; + plugins << new MockServicePlugin2; + plugins << new MockServicePlugin3; + + QMediaPluginLoader::setStaticPlugins(QLatin1String("/mediaservice"), plugins); +} + +void tst_QMediaServiceProvider::testDefaultProviderAvailable() +{ + // Must always be a default provider available + QVERIFY(QMediaServiceProvider::defaultServiceProvider() != 0); +} + +void tst_QMediaServiceProvider::testObtainService() +{ + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + if (provider == 0) + QSKIP("No default provider", SkipSingle); + + QMediaService *service = 0; + + QTest::ignoreMessage(QtWarningMsg, "Load static plugins for \"/mediaservice/\" "); + // Player + service = provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); + QVERIFY(service != 0); + provider->releaseService(service); +} + +void tst_QMediaServiceProvider::testHasSupport() +{ + MockMediaServiceProvider mockProvider; + QCOMPARE(mockProvider.hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()), + QtMedia::MaybeSupported); + + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + if (provider == 0) + QSKIP("No default provider", SkipSingle); + + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/ogv", QStringList()), + QtMedia::MaybeSupported); + + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/ogg", QStringList()), + QtMedia::ProbablySupported); + + //while the service returns PreferredService, provider should return ProbablySupported + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "audio/wav", QStringList()), + QtMedia::ProbablySupported); + + //even while all the plugins with "hasSupport" returned NotSupported, + //MockServicePlugin3 has no "hasSupport" interface, so MaybeSupported + QCOMPARE(provider->hasSupport(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER), "video/avi", + QStringList() << "mpeg4"), + QtMedia::MaybeSupported); + + QCOMPARE(provider->hasSupport(QByteArray("non existing service"), "video/ogv", QStringList()), + QtMedia::NotSupported); + + QCOMPARE(QMediaPlayer::hasSupport("video/ogv"), QtMedia::MaybeSupported); + QCOMPARE(QMediaPlayer::hasSupport("audio/ogg"), QtMedia::ProbablySupported); + QCOMPARE(QMediaPlayer::hasSupport("audio/wav"), QtMedia::ProbablySupported); + + //ensure the correct media player plugin is choosen for mime type + QMediaPlayer simplePlayer(0, QMediaPlayer::LowLatency); + QCOMPARE(simplePlayer.service()->objectName(), QLatin1String("MockServicePlugin2")); + + QMediaPlayer mediaPlayer; + QVERIFY(mediaPlayer.service()->objectName() != QLatin1String("MockServicePlugin2")); +} + +void tst_QMediaServiceProvider::testSupportedMimeTypes() +{ + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + if (provider == 0) + QSKIP("No default provider", SkipSingle); + + QVERIFY(provider->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)).contains("audio/ogg")); + QVERIFY(!provider->supportedMimeTypes(QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)).contains("audio/mp3")); +} + +void tst_QMediaServiceProvider::testDevices() +{ + MockMediaServiceProvider mockProvider; + QVERIFY(mockProvider.devices(QByteArray(Q_MEDIASERVICE_CAMERA)).isEmpty()); + QVERIFY(mockProvider.deviceDescription(QByteArray(Q_MEDIASERVICE_CAMERA), + QByteArray()).isEmpty()); + + QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); + + QList cameraDevices = provider->devices(QByteArray(Q_MEDIASERVICE_CAMERA)); + QCOMPARE(cameraDevices.count(), 4); + QVERIFY(cameraDevices.contains(QByteArray("camera1"))); + QVERIFY(cameraDevices.contains(QByteArray("camera2"))); + QVERIFY(cameraDevices.contains(QByteArray("camera3"))); + QVERIFY(cameraDevices.contains(QByteArray("camera4"))); + + /* + //ensure the right plugin is choosen for a device + QCamera camera1(QByteArray("camera1")); + QCOMPARE( camera1.service()->objectName(), QLatin1String("MockServicePlugin1") ); + QCamera camera2(QByteArray("camera2")); + QCOMPARE( camera2.service()->objectName(), QLatin1String("MockServicePlugin1") ); + QCamera camera3(QByteArray("camera3")); + QCOMPARE( camera3.service()->objectName(), QLatin1String("MockServicePlugin3") ); + QCamera camera4(QByteArray("camera4")); + QCOMPARE( camera4.service()->objectName(), QLatin1String("MockServicePlugin3") ); + + QList audioSourceDevices = provider->devices(QByteArray(Q_MEDIASERVICE_AUDIOSOURCE)); + QCOMPARE(audioSourceDevices.count(), 2); + QVERIFY(audioSourceDevices.contains(QByteArray("audiosource1"))); + QVERIFY(audioSourceDevices.contains(QByteArray("audiosource2"))); + + QVERIFY(provider->devices(QByteArray("non existing service")).isEmpty()); + */ +} + + + + +void tst_QMediaServiceProvider::testProviderHints() +{ + { + QMediaServiceProviderHint hint; + QVERIFY(hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::Null); + QVERIFY(hint.device().isEmpty()); + QVERIFY(hint.mimeType().isEmpty()); + QVERIFY(hint.codecs().isEmpty()); + QCOMPARE(hint.features(), 0); + } + + { + QByteArray deviceName(QByteArray("testDevice")); + QMediaServiceProviderHint hint(deviceName); + QVERIFY(!hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::Device); + QCOMPARE(hint.device(), deviceName); + QVERIFY(hint.mimeType().isEmpty()); + QVERIFY(hint.codecs().isEmpty()); + QCOMPARE(hint.features(), 0); + } + + { + QMediaServiceProviderHint hint(QMediaServiceProviderHint::LowLatencyPlayback); + QVERIFY(!hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::SupportedFeatures); + QVERIFY(hint.device().isEmpty()); + QVERIFY(hint.mimeType().isEmpty()); + QVERIFY(hint.codecs().isEmpty()); + QCOMPARE(hint.features(), QMediaServiceProviderHint::LowLatencyPlayback); + } + + { + QString mimeType(QLatin1String("video/ogg")); + QStringList codecs; + codecs << "theora" << "vorbis"; + + QMediaServiceProviderHint hint(mimeType,codecs); + QVERIFY(!hint.isNull()); + QCOMPARE(hint.type(), QMediaServiceProviderHint::ContentType); + QVERIFY(hint.device().isEmpty()); + QCOMPARE(hint.mimeType(), mimeType); + QCOMPARE(hint.codecs(), codecs); + + QMediaServiceProviderHint hint2(hint); + + QVERIFY(!hint2.isNull()); + QCOMPARE(hint2.type(), QMediaServiceProviderHint::ContentType); + QVERIFY(hint2.device().isEmpty()); + QCOMPARE(hint2.mimeType(), mimeType); + QCOMPARE(hint2.codecs(), codecs); + + QMediaServiceProviderHint hint3; + QVERIFY(hint3.isNull()); + hint3 = hint; + QVERIFY(!hint3.isNull()); + QCOMPARE(hint3.type(), QMediaServiceProviderHint::ContentType); + QVERIFY(hint3.device().isEmpty()); + QCOMPARE(hint3.mimeType(), mimeType); + QCOMPARE(hint3.codecs(), codecs); + + QCOMPARE(hint, hint2); + QCOMPARE(hint3, hint2); + + QMediaServiceProviderHint hint4(mimeType,codecs); + QCOMPARE(hint, hint4); + + QMediaServiceProviderHint hint5(mimeType,QStringList()); + QVERIFY(hint != hint5); + } +} + +QTEST_MAIN(tst_QMediaServiceProvider) + +#include "tst_qmediaserviceprovider.moc" diff --git a/tests/auto/qmediatimerange/qmediatimerange.pro b/tests/auto/qmediatimerange/qmediatimerange.pro new file mode 100644 index 0000000..b1b436e --- /dev/null +++ b/tests/auto/qmediatimerange/qmediatimerange.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qmediatimerange.cpp + +QT = core multimedia + diff --git a/tests/auto/qmediatimerange/tst_qmediatimerange.cpp b/tests/auto/qmediatimerange/tst_qmediatimerange.cpp new file mode 100644 index 0000000..a8c58db --- /dev/null +++ b/tests/auto/qmediatimerange/tst_qmediatimerange.cpp @@ -0,0 +1,735 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include + +#include + +class tst_QMediaTimeRange: public QObject +{ + Q_OBJECT + +public slots: + +private slots: + void testCtor(); + void testGetters(); + void testAssignment(); + void testNormalize(); + void testTranslated(); + void testEarliestLatest(); + void testContains(); + void testAddInterval(); + void testAddTimeRange(); + void testRemoveInterval(); + void testRemoveTimeRange(); + void testClear(); + void testComparisons(); + void testArithmetic(); +}; + +void tst_QMediaTimeRange::testCtor() +{ + // Default Ctor + QMediaTimeRange a; + QVERIFY(a.isEmpty()); + + // (qint, qint) Ctor + QMediaTimeRange b(10, 20); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Interval Ctor + QMediaTimeRange c(QMediaTimeInterval(30, 40)); + + QVERIFY(!c.isEmpty()); + QVERIFY(c.isContinuous()); + QVERIFY(c.earliestTime() == 30); + QVERIFY(c.latestTime() == 40); + + // Abnormal Interval Ctor + QMediaTimeRange d(QMediaTimeInterval(20, 10)); + + QVERIFY(d.isEmpty()); + + // Copy Ctor + QMediaTimeRange e(b); + + QVERIFY(!e.isEmpty()); + QVERIFY(e.isContinuous()); + QVERIFY(e.earliestTime() == 10); + QVERIFY(e.latestTime() == 20); +} + +void tst_QMediaTimeRange::testGetters() +{ + QMediaTimeRange x; + + // isEmpty + QVERIFY(x.isEmpty()); + + x.addInterval(10, 20); + + // isEmpty + isContinuous + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + + x.addInterval(30, 40); + + // isEmpty + isContinuous + intervals + start + end + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 20); + QVERIFY(x.intervals()[1].start() == 30); + QVERIFY(x.intervals()[1].end() == 40); +} + +void tst_QMediaTimeRange::testAssignment() +{ + QMediaTimeRange x; + + // Range Assignment + x = QMediaTimeRange(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 20); + + // Interval Assignment + x = QMediaTimeInterval(30, 40); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 40); + + // Shared Data Check + QMediaTimeRange y; + + y = x; + y.addInterval(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 40); +} + +void tst_QMediaTimeRange::testNormalize() +{ + QMediaTimeInterval x(20, 10); + + QVERIFY(!x.isNormal()); + + x = x.normalized(); + + QVERIFY(x.isNormal()); + QVERIFY(x.start() == 10); + QVERIFY(x.end() == 20); +} + +void tst_QMediaTimeRange::testTranslated() +{ + QMediaTimeInterval x(10, 20); + x = x.translated(10); + + QVERIFY(x.start() == 20); + QVERIFY(x.end() == 30); +} + +void tst_QMediaTimeRange::testEarliestLatest() +{ + // Test over a single interval + QMediaTimeRange x(30, 40); + + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 40); + + // Test over multiple intervals + x.addInterval(50, 60); + + QVERIFY(x.earliestTime() == 30); + QVERIFY(x.latestTime() == 60); +} + +void tst_QMediaTimeRange::testContains() +{ + // Test over a single interval + QMediaTimeRange x(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.contains(15)); + QVERIFY(x.contains(10)); + QVERIFY(x.contains(20)); + QVERIFY(!x.contains(25)); + + // Test over multiple intervals + x.addInterval(40, 50); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.contains(15)); + QVERIFY(x.contains(45)); + QVERIFY(!x.contains(30)); + + // Test over a concrete interval + QMediaTimeInterval y(10, 20); + QVERIFY(y.contains(15)); + QVERIFY(y.contains(10)); + QVERIFY(y.contains(20)); + QVERIFY(!y.contains(25)); +} + +void tst_QMediaTimeRange::testAddInterval() +{ + // All intervals Overlap + QMediaTimeRange x; + x.addInterval(10, 40); + x.addInterval(30, 50); + x.addInterval(20, 60); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 60); + + // 1 adjacent interval, 1 encompassed interval + x = QMediaTimeRange(); + x.addInterval(10, 40); + x.addInterval(20, 30); + x.addInterval(41, 50); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 50); + + // 1 overlapping interval, 1 disjoint interval + x = QMediaTimeRange(); + x.addInterval(10, 30); + x.addInterval(20, 40); + x.addInterval(50, 60); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 40); + QVERIFY(x.intervals()[1].start() == 50); + QVERIFY(x.intervals()[1].end() == 60); + + // Identical Add + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(10, 20); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 20); + + // Multi-Merge + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.addInterval(50, 60); + x.addInterval(15, 55); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 60); + + // Interval Parameter - All intervals Overlap + x = QMediaTimeRange(); + x.addInterval(QMediaTimeInterval(10, 40)); + x.addInterval(QMediaTimeInterval(30, 50)); + x.addInterval(QMediaTimeInterval(20, 60)); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 60); + + // Interval Parameter - Abnormal Interval + x = QMediaTimeRange(); + x.addInterval(QMediaTimeInterval(20, 10)); + + QVERIFY(x.isEmpty()); +} + +void tst_QMediaTimeRange::testAddTimeRange() +{ + // Add Time Range uses Add Interval internally, + // so in this test the focus is on combinations of number + // of intervals added, rather than the different types of + // merges which can occur. + QMediaTimeRange a, b; + + // Add Single into Single + a = QMediaTimeRange(10, 30); + b = QMediaTimeRange(20, 40); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 40); + + // Add Multiple into Single + a = QMediaTimeRange(); + a.addInterval(10, 30); + a.addInterval(40, 60); + + b = QMediaTimeRange(20, 50); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 60); + + // Add Single into Multiple + a = QMediaTimeRange(20, 50); + + b = QMediaTimeRange(); + b.addInterval(10, 30); + b.addInterval(40, 60); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 60); + + // Add Multiple into Multiple + a = QMediaTimeRange(); + a.addInterval(10, 30); + a.addInterval(40, 70); + a.addInterval(80, 100); + + b = QMediaTimeRange(); + b.addInterval(20, 50); + b.addInterval(60, 90); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 100); + + // Add Nothing to Single + a = QMediaTimeRange(); + b = QMediaTimeRange(10, 20); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Add Single to Nothing + a = QMediaTimeRange(10, 20); + b = QMediaTimeRange(); + + b.addTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Add Nothing to Nothing + a = QMediaTimeRange(); + b = QMediaTimeRange(); + + b.addTimeRange(a); + + QVERIFY(b.isEmpty()); +} + +void tst_QMediaTimeRange::testRemoveInterval() +{ + // Removing an interval, causing a split + QMediaTimeRange x; + x.addInterval(10, 50); + x.removeInterval(20, 40); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 19); + QVERIFY(x.intervals()[1].start() == 41); + QVERIFY(x.intervals()[1].end() == 50); + + // Removing an interval, causing a deletion + x = QMediaTimeRange(); + x.addInterval(20, 30); + x.removeInterval(10, 40); + + QVERIFY(x.isEmpty()); + + // Removing an interval, causing a tail trim + x = QMediaTimeRange(); + x.addInterval(20, 40); + x.removeInterval(30, 50); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 20); + QVERIFY(x.latestTime() == 29); + + // Removing an interval, causing a head trim + x = QMediaTimeRange(); + x.addInterval(20, 40); + x.removeInterval(10, 30); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 31); + QVERIFY(x.latestTime() == 40); + + // Identical Remove + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.removeInterval(10, 20); + + QVERIFY(x.isEmpty()); + + // Multi-Trim + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.removeInterval(15, 35); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 14); + QVERIFY(x.intervals()[1].start() == 36); + QVERIFY(x.intervals()[1].end() == 40); + + // Multi-Delete + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.addInterval(50, 60); + x.removeInterval(10, 60); + + QVERIFY(x.isEmpty()); + + // Interval Parameter - Removing an interval, causing a split + x = QMediaTimeRange(); + x.addInterval(10, 50); + x.removeInterval(QMediaTimeInterval(20, 40)); + + QVERIFY(!x.isEmpty()); + QVERIFY(!x.isContinuous()); + QVERIFY(x.intervals().count() == 2); + QVERIFY(x.intervals()[0].start() == 10); + QVERIFY(x.intervals()[0].end() == 19); + QVERIFY(x.intervals()[1].start() == 41); + QVERIFY(x.intervals()[1].end() == 50); + + // Interval Parameter - Abnormal Interval + x = QMediaTimeRange(); + x.addInterval(10, 40); + x.removeInterval(QMediaTimeInterval(30, 20)); + + QVERIFY(!x.isEmpty()); + QVERIFY(x.isContinuous()); + QVERIFY(x.earliestTime() == 10); + QVERIFY(x.latestTime() == 40); +} + +void tst_QMediaTimeRange::testRemoveTimeRange() +{ + // Remove Time Range uses Remove Interval internally, + // so in this test the focus is on combinations of number + // of intervals removed, rather than the different types of + // deletions which can occur. + QMediaTimeRange a, b; + + // Remove Single from Single + a = QMediaTimeRange(10, 30); + b = QMediaTimeRange(20, 40); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 31); + QVERIFY(b.latestTime() == 40); + + // Remove Multiple from Single + a = QMediaTimeRange(); + a.addInterval(10, 30); + a.addInterval(40, 60); + + b = QMediaTimeRange(20, 50); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 31); + QVERIFY(b.latestTime() == 39); + + // Remove Single from Multiple + a = QMediaTimeRange(20, 50); + + b = QMediaTimeRange(); + b.addInterval(10, 30); + b.addInterval(40, 60); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(!b.isContinuous()); + QVERIFY(b.intervals().count() == 2); + QVERIFY(b.intervals()[0].start() == 10); + QVERIFY(b.intervals()[0].end() == 19); + QVERIFY(b.intervals()[1].start() == 51); + QVERIFY(b.intervals()[1].end() == 60); + + // Remove Multiple from Multiple + a = QMediaTimeRange(); + a.addInterval(20, 50); + a.addInterval(50, 90); + + + b = QMediaTimeRange(); + b.addInterval(10, 30); + b.addInterval(40, 70); + b.addInterval(80, 100); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(!b.isContinuous()); + QVERIFY(b.intervals().count() == 2); + QVERIFY(b.intervals()[0].start() == 10); + QVERIFY(b.intervals()[0].end() == 19); + QVERIFY(b.intervals()[1].start() == 91); + QVERIFY(b.intervals()[1].end() == 100); + + // Remove Nothing from Single + a = QMediaTimeRange(); + b = QMediaTimeRange(10, 20); + + b.removeTimeRange(a); + + QVERIFY(!b.isEmpty()); + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 10); + QVERIFY(b.latestTime() == 20); + + // Remove Single from Nothing + a = QMediaTimeRange(10, 20); + b = QMediaTimeRange(); + + b.removeTimeRange(a); + + QVERIFY(b.isEmpty()); + + // Remove Nothing from Nothing + a = QMediaTimeRange(); + b = QMediaTimeRange(); + + b.removeTimeRange(a); + + QVERIFY(b.isEmpty()); +} + +void tst_QMediaTimeRange::testClear() +{ + QMediaTimeRange x; + + // Clear Nothing + x.clear(); + + QVERIFY(x.isEmpty()); + + // Clear Single + x = QMediaTimeRange(10, 20); + x.clear(); + + QVERIFY(x.isEmpty()); + + // Clear Multiple + x = QMediaTimeRange(); + x.addInterval(10, 20); + x.addInterval(30, 40); + x.clear(); + + QVERIFY(x.isEmpty()); +} + +void tst_QMediaTimeRange::testComparisons() +{ + // Interval equality + QVERIFY(QMediaTimeInterval(10, 20) == QMediaTimeInterval(10, 20)); + QVERIFY(QMediaTimeInterval(10, 20) != QMediaTimeInterval(10, 30)); + QVERIFY(!(QMediaTimeInterval(10, 20) != QMediaTimeInterval(10, 20))); + QVERIFY(!(QMediaTimeInterval(10, 20) == QMediaTimeInterval(10, 30))); + + // Time range equality - Single Interval + QMediaTimeRange a(10, 20), b(20, 30), c(10, 20); + + QVERIFY(a == c); + QVERIFY(!(a == b)); + QVERIFY(a != b); + QVERIFY(!(a != c)); + + // Time Range Equality - Multiple Intervals + QMediaTimeRange x, y, z; + + x.addInterval(10, 20); + x.addInterval(30, 40); + x.addInterval(50, 60); + + y.addInterval(10, 20); + y.addInterval(35, 45); + y.addInterval(50, 60); + + z.addInterval(10, 20); + z.addInterval(30, 40); + z.addInterval(50, 60); + + QVERIFY(x == z); + QVERIFY(!(x == y)); + QVERIFY(x != y); + QVERIFY(!(x != z)); +} + +void tst_QMediaTimeRange::testArithmetic() +{ + QMediaTimeRange a(10, 20), b(20, 30); + + // Test += + a += b; + + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 30); + + // Test -= + a -= b; + + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 19); + + // Test += and -= on intervals + a -= QMediaTimeInterval(10, 20); + a += QMediaTimeInterval(40, 50); + + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 40); + QVERIFY(a.latestTime() == 50); + + // Test Interval + Interval + a = QMediaTimeInterval(10, 20) + QMediaTimeInterval(20, 30); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 30); + + // Test Range + Interval + a = a + QMediaTimeInterval(30, 40); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 40); + + // Test Interval + Range + a = QMediaTimeInterval(40, 50) + a; + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 50); + + // Test Range + Range + a = a + QMediaTimeRange(50, 60); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 60); + + // Test Range - Interval + a = a - QMediaTimeInterval(50, 60); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 49); + + // Test Range - Range + a = a - QMediaTimeRange(40, 50); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 39); + + // Test Interval - Range + b = QMediaTimeInterval(0, 20) - a; + QVERIFY(b.isContinuous()); + QVERIFY(b.earliestTime() == 0); + QVERIFY(b.latestTime() == 9); + + // Test Interval - Interval + a = QMediaTimeInterval(10, 20) - QMediaTimeInterval(15, 30); + QVERIFY(a.isContinuous()); + QVERIFY(a.earliestTime() == 10); + QVERIFY(a.latestTime() == 14); +} + +QTEST_MAIN(tst_QMediaTimeRange) + +#include "tst_qmediatimerange.moc" diff --git a/tests/auto/qvideowidget/qvideowidget.pro b/tests/auto/qvideowidget/qvideowidget.pro new file mode 100644 index 0000000..ca0fc24 --- /dev/null +++ b/tests/auto/qvideowidget/qvideowidget.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +SOURCES = tst_qvideowidget.cpp + +QT = core gui multimedia + diff --git a/tests/auto/qvideowidget/tst_qvideowidget.cpp b/tests/auto/qvideowidget/tst_qvideowidget.cpp new file mode 100644 index 0000000..37676cf --- /dev/null +++ b/tests/auto/qvideowidget/tst_qvideowidget.cpp @@ -0,0 +1,1595 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +class tst_QVideoWidget : public QObject +{ + Q_OBJECT +private slots: + void nullObject(); + void nullService(); + void nullOutputControl(); + void noOutputs(); + void serviceDestroyed(); + void objectDestroyed(); + void setMediaObject(); + + void showWindowControl(); + void fullScreenWindowControl(); + void aspectRatioWindowControl(); + void sizeHintWindowControl_data() { sizeHint_data(); } + void sizeHintWindowControl(); + void brightnessWindowControl_data() { color_data(); } + void brightnessWindowControl(); + void contrastWindowControl_data() { color_data(); } + void contrastWindowControl(); + void hueWindowControl_data() { color_data(); } + void hueWindowControl(); + void saturationWindowControl_data() { color_data(); } + void saturationWindowControl(); + + void showWidgetControl(); + void fullScreenWidgetControl(); + void aspectRatioWidgetControl(); + void sizeHintWidgetControl_data() { sizeHint_data(); } + void sizeHintWidgetControl(); + void brightnessWidgetControl_data() { color_data(); } + void brightnessWidgetControl(); + void contrastWidgetControl_data() { color_data(); } + void contrastWidgetControl(); + void hueWidgetControl_data() { color_data(); } + void hueWidgetControl(); + void saturationWidgetControl_data() { color_data(); } + void saturationWidgetControl(); + + void showRendererControl(); + void fullScreenRendererControl(); + void aspectRatioRendererControl(); + void sizeHintRendererControl_data(); + void sizeHintRendererControl(); + void brightnessRendererControl_data() { color_data(); } + void brightnessRendererControl(); + void contrastRendererControl_data() { color_data(); } + void contrastRendererControl(); + void hueRendererControl_data() { color_data(); } + void hueRendererControl(); + void saturationRendererControl_data() { color_data(); } + void saturationRendererControl(); + + void paintRendererControl(); + +private: + void sizeHint_data(); + void color_data(); +}; + +Q_DECLARE_METATYPE(QVideoWidget::AspectRatioMode) +Q_DECLARE_METATYPE(const uchar *) + +class QtTestOutputControl : public QVideoOutputControl +{ +public: + QtTestOutputControl() : m_output(NoOutput) {} + + QList availableOutputs() const { return m_outputs; } + void setAvailableOutputs(const QList outputs) { m_outputs = outputs; } + + Output output() const { return m_output; } + virtual void setOutput(Output output) { m_output = output; } + +private: + Output m_output; + QList m_outputs; +}; + +class QtTestWindowControl : public QVideoWindowControl +{ +public: + QtTestWindowControl() + : m_winId(0) + , m_repaintCount(0) + , m_brightness(0) + , m_contrast(0) + , m_saturation(0) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_fullScreen(0) + { + } + + WId winId() const { return m_winId; } + void setWinId(WId id) { m_winId = id; } + + QRect displayRect() const { return m_displayRect; } + void setDisplayRect(const QRect &rect) { m_displayRect = rect; } + + bool isFullScreen() const { return m_fullScreen; } + void setFullScreen(bool fullScreen) { emit fullScreenChanged(m_fullScreen = fullScreen); } + + int repaintCount() const { return m_repaintCount; } + void setRepaintCount(int count) { m_repaintCount = count; } + void repaint() { ++m_repaintCount; } + + QSize nativeSize() const { return m_nativeSize; } + void setNativeSize(const QSize &size) { m_nativeSize = size; emit nativeSizeChanged(); } + + QVideoWidget::AspectRatioMode aspectRatioMode() const { return m_aspectRatioMode; } + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) { m_aspectRatioMode = mode; } + + int brightness() const { return m_brightness; } + void setBrightness(int brightness) { emit brightnessChanged(m_brightness = brightness); } + + int contrast() const { return m_contrast; } + void setContrast(int contrast) { emit contrastChanged(m_contrast = contrast); } + + int hue() const { return m_hue; } + void setHue(int hue) { emit hueChanged(m_hue = hue); } + + int saturation() const { return m_saturation; } + void setSaturation(int saturation) { emit saturationChanged(m_saturation = saturation); } + +private: + WId m_winId; + int m_repaintCount; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QRect m_displayRect; + QSize m_nativeSize; + bool m_fullScreen; +}; + +class QtTestWidgetControl : public QVideoWidgetControl +{ +public: + QtTestWidgetControl() + : m_brightness(1.0) + , m_contrast(1.0) + , m_hue(1.0) + , m_saturation(1.0) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_fullScreen(false) + { + } + + bool isFullScreen() const { return m_fullScreen; } + void setFullScreen(bool fullScreen) { emit fullScreenChanged(m_fullScreen = fullScreen); } + + QVideoWidget::AspectRatioMode aspectRatioMode() const { return m_aspectRatioMode; } + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode) { m_aspectRatioMode = mode; } + + int brightness() const { return m_brightness; } + void setBrightness(int brightness) { emit brightnessChanged(m_brightness = brightness); } + + int contrast() const { return m_contrast; } + void setContrast(int contrast) { emit contrastChanged(m_contrast = contrast); } + + int hue() const { return m_hue; } + void setHue(int hue) { emit hueChanged(m_hue = hue); } + + int saturation() const { return m_saturation; } + void setSaturation(int saturation) { emit saturationChanged(m_saturation = saturation); } + + void setSizeHint(const QSize &size) { m_widget.setSizeHint(size); } + + QWidget *videoWidget() { return &m_widget; } + +private: + class Widget : public QWidget + { + public: + QSize sizeHint() const { return m_sizeHint; } + void setSizeHint(const QSize &size) { m_sizeHint = size; updateGeometry(); } + private: + QSize m_sizeHint; + } m_widget; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QSize m_sizeHint; + bool m_fullScreen; +}; + +class QtTestRendererControl : public QVideoRendererControl +{ +public: + QtTestRendererControl() + : m_surface(0) + { + } + + QAbstractVideoSurface *surface() const { return m_surface; } + void setSurface(QAbstractVideoSurface *surface) { m_surface = surface; } + +private: + QAbstractVideoSurface *m_surface; +}; + +class QtTestVideoService : public QMediaService +{ + Q_OBJECT +public: + QtTestVideoService( + QtTestOutputControl *output, + QtTestWindowControl *window, + QtTestWidgetControl *widget, + QtTestRendererControl *renderer) + : QMediaService(0) + , outputControl(output) + , windowControl(window) + , widgetControl(widget) + , rendererControl(renderer) + { + } + + ~QtTestVideoService() + { + delete outputControl; + delete windowControl; + delete widgetControl; + delete rendererControl; + } + + QMediaControl *control(const char *name) const + { + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return outputControl; + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return windowControl; + else if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + return widgetControl; + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return rendererControl; + else + return 0; + } + + QtTestOutputControl *outputControl; + QtTestWindowControl *windowControl; + QtTestWidgetControl *widgetControl; + QtTestRendererControl *rendererControl; +}; + +class QtTestVideoObject : public QMediaObject +{ + Q_OBJECT +public: + QtTestVideoObject( + QtTestWindowControl *window, + QtTestWidgetControl *widget, + QtTestRendererControl *renderer): + QMediaObject(0, new QtTestVideoService(new QtTestOutputControl, window, widget, renderer)) + { + testService = qobject_cast(service()); + QList outputs; + + if (window) + outputs.append(QVideoOutputControl::WindowOutput); + if (widget) + outputs.append(QVideoOutputControl::WidgetOutput); + if (renderer) + outputs.append(QVideoOutputControl::RendererOutput); + + testService->outputControl->setAvailableOutputs(outputs); + } + + QtTestVideoObject(QtTestVideoService *service): + QMediaObject(0, service), + testService(service) + { + } + + ~QtTestVideoObject() + { + delete testService; + } + + QtTestVideoService *testService; +}; + +void tst_QVideoWidget::nullObject() +{ + QVideoWidget widget; + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + { + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + QCOMPARE(spy.count(), 1); + + widget.setBrightness(-120); + QCOMPARE(widget.brightness(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } { + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(spy.count(), 1); + + widget.setContrast(-120); + QCOMPARE(widget.contrast(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } { + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(spy.count(), 1); + + widget.setHue(-120); + QCOMPARE(widget.hue(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } { + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); + QCOMPARE(spy.count(), 1); + + widget.setSaturation(-120); + QCOMPARE(widget.saturation(), -100); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), -100); + } +} + +void tst_QVideoWidget::nullService() +{ + QtTestVideoObject object(0); + + QVideoWidget widget; + widget.setMediaObject(&object); + + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); +} + +void tst_QVideoWidget::nullOutputControl() +{ + QtTestVideoObject object(new QtTestVideoService(0, 0, 0, 0)); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); +} + +void tst_QVideoWidget::noOutputs() +{ + QtTestVideoObject object(0, 0, 0); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QVERIFY(widget.sizeHint().isEmpty()); + + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); + + widget.setBrightness(100); + QCOMPARE(widget.brightness(), 100); + + widget.setContrast(100); + QCOMPARE(widget.contrast(), 100); + + widget.setHue(100); + QCOMPARE(widget.hue(), 100); + + widget.setSaturation(100); + QCOMPARE(widget.saturation(), 100); +} + +void tst_QVideoWidget::serviceDestroyed() +{ + QtTestVideoObject object(new QtTestWindowControl, new QtTestWidgetControl, 0); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + widget.setBrightness(100); + widget.setContrast(100); + widget.setHue(100); + widget.setSaturation(100); + + delete object.testService; + object.testService = 0; + + QCOMPARE(widget.mediaObject(), static_cast(&object)); + + QCOMPARE(widget.brightness(), 100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(widget.saturation(), 100); + + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); +} + +void tst_QVideoWidget::objectDestroyed() +{ + QtTestVideoObject *object = new QtTestVideoObject( + new QtTestWindowControl, + new QtTestWidgetControl, + 0); + + QVideoWidget widget; + widget.setMediaObject(object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + widget.setBrightness(100); + widget.setContrast(100); + widget.setHue(100); + widget.setSaturation(100); + + // Delete the media object without deleting the service. + QtTestVideoService *service = object->testService; + object->testService = 0; + + delete object; + object = 0; + + QCOMPARE(widget.mediaObject(), static_cast(object)); + + QCOMPARE(service->outputControl->output(), QVideoOutputControl::NoOutput); + + QCOMPARE(widget.brightness(), 100); + QCOMPARE(widget.contrast(), 100); + QCOMPARE(widget.hue(), 100); + QCOMPARE(widget.saturation(), 100); + + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); + + delete service; +} + +void tst_QVideoWidget::setMediaObject() +{ + QMediaObject *nullObject = 0; + QtTestVideoObject windowObject(new QtTestWindowControl, 0, 0); + QtTestVideoObject widgetObject(0, new QtTestWidgetControl, 0); + QtTestVideoObject rendererObject(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(widget.mediaObject(), nullObject); + QCOMPARE(windowObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(widgetObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(rendererObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.setMediaObject(&windowObject); + QCOMPARE(widget.mediaObject(), static_cast(&windowObject)); + QCOMPARE(windowObject.testService->outputControl->output(), QVideoOutputControl::WindowOutput); + QVERIFY(windowObject.testService->windowControl->winId() != 0); + + + widget.setMediaObject(&widgetObject); + QCOMPARE(widget.mediaObject(), static_cast(&widgetObject)); + QCOMPARE(widgetObject.testService->outputControl->output(), QVideoOutputControl::WidgetOutput); + + QCoreApplication::processEvents(QEventLoop::AllEvents); + QCOMPARE(widgetObject.testService->widgetControl->videoWidget()->isVisible(), true); + + QCOMPARE(windowObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.setMediaObject(&rendererObject); + QCOMPARE(widget.mediaObject(), static_cast(&rendererObject)); + QCOMPARE(rendererObject.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(rendererObject.testService->rendererControl->surface() != 0); + + QCOMPARE(widgetObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.setMediaObject(0); + QCOMPARE(widget.mediaObject(), nullObject); + + QCOMPARE(rendererObject.testService->outputControl->output(), QVideoOutputControl::NoOutput); +} + +void tst_QVideoWidget::showWindowControl() +{ + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setNativeSize(QSize(240, 180)); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::WindowOutput); + QVERIFY(object.testService->windowControl->winId() != 0); + + QVERIFY(object.testService->windowControl->repaintCount() > 0); + + widget.resize(640, 480); + QCOMPARE(object.testService->windowControl->displayRect(), QRect(0, 0, 640, 480)); + + widget.move(10, 10); + QCOMPARE(object.testService->windowControl->displayRect(), QRect(0, 0, 640, 480)); + + widget.hide(); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); +} + +void tst_QVideoWidget::showWidgetControl() +{ + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::WidgetOutput); + QCOMPARE(object.testService->widgetControl->videoWidget()->isVisible(), true); + + widget.resize(640, 480); + + widget.move(10, 10); + + widget.hide(); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(object.testService->widgetControl->videoWidget()->isVisible(), false); +} + +void tst_QVideoWidget::showRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(object.testService->rendererControl->surface() != 0); + + widget.resize(640, 480); + + widget.move(10, 10); + + widget.hide(); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); +} + +void tst_QVideoWidget::aspectRatioWindowControl() +{ + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + // Test the aspect ratio defaults to keeping the aspect ratio. + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test the control has been informed of the aspect ratio change, post show. + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->windowControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test an aspect ratio change is enforced immediately while visible. + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + QCOMPARE(object.testService->windowControl->aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + // Test an aspect ratio set while not visible is respected. + widget.hide(); + widget.setAspectRatioMode(QVideoWidget::KeepAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + widget.show(); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->windowControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); +} + +void tst_QVideoWidget::aspectRatioWidgetControl() +{ + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + // Test the aspect ratio defaults to keeping the aspect ratio. + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test the control has been informed of the aspect ratio change, post show. + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->widgetControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test an aspect ratio change is enforced immediately while visible. + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + QCOMPARE(object.testService->widgetControl->aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + // Test an aspect ratio set while not visible is respected. + widget.hide(); + widget.setAspectRatioMode(QVideoWidget::KeepAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + widget.show(); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + QCOMPARE(object.testService->widgetControl->aspectRatioMode(), QVideoWidget::KeepAspectRatio); +} + +void tst_QVideoWidget::aspectRatioRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + // Test the aspect ratio defaults to keeping the aspect ratio. + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test the control has been informed of the aspect ratio change, post show. + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + + // Test an aspect ratio change is enforced immediately while visible. + widget.setAspectRatioMode(QVideoWidget::IgnoreAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::IgnoreAspectRatio); + + // Test an aspect ratio set while not visible is respected. + widget.hide(); + widget.setAspectRatioMode(QVideoWidget::KeepAspectRatio); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); + widget.show(); + QCOMPARE(widget.aspectRatioMode(), QVideoWidget::KeepAspectRatio); +} + +void tst_QVideoWidget::sizeHint_data() +{ + QTest::addColumn("size"); + + QTest::newRow("720x576") + << QSize(720, 576); +} + +void tst_QVideoWidget::sizeHintWindowControl() +{ + QFETCH(QSize, size); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QVERIFY(widget.sizeHint().isEmpty()); + + object.testService->windowControl->setNativeSize(size); + QCOMPARE(widget.sizeHint(), size); +} + +void tst_QVideoWidget::sizeHintWidgetControl() +{ + QFETCH(QSize, size); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QVERIFY(widget.sizeHint().isEmpty()); + + object.testService->widgetControl->setSizeHint(size); + QCOMPARE(widget.sizeHint(), size); +} + +void tst_QVideoWidget::sizeHintRendererControl_data() +{ + QTest::addColumn("frameSize"); + QTest::addColumn("viewport"); + QTest::addColumn("pixelAspectRatio"); + QTest::addColumn("expectedSize"); + + QTest::newRow("640x480") + << QSize(640, 480) + << QRect(0, 0, 640, 480) + << QSize(1, 1) + << QSize(640, 480); + + QTest::newRow("800x600, (80,60, 640x480) viewport") + << QSize(800, 600) + << QRect(80, 60, 640, 480) + << QSize(1, 1) + << QSize(640, 480); + + QTest::newRow("800x600, (80,60, 640x480) viewport, 4:3") + << QSize(800, 600) + << QRect(80, 60, 640, 480) + << QSize(4, 3) + << QSize(853, 480); + +} + +void tst_QVideoWidget::sizeHintRendererControl() +{ + QFETCH(QSize, frameSize); + QFETCH(QRect, viewport); + QFETCH(QSize, pixelAspectRatio); + QFETCH(QSize, expectedSize); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QVideoSurfaceFormat format(frameSize, QVideoFrame::Format_ARGB32); + format.setViewport(viewport); + format.setPixelAspectRatio(pixelAspectRatio); + + QVERIFY(object.testService->rendererControl->surface()->start(format)); + + QCOMPARE(widget.sizeHint(), expectedSize); +} + + +void tst_QVideoWidget::fullScreenWindowControl() +{ + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + Qt::WindowFlags windowFlags = widget.windowFlags(); + + QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool))); + + // Test showing full screen with setFullScreen(true). + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toBool(), true); + + // Test returning to normal with setFullScreen(false). + widget.setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test showing full screen with showFullScreen(). + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 3); + QCOMPARE(spy.value(2).value(0).toBool(), true); + + // Test returning to normal with showNormal(). + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + QCOMPARE(spy.value(3).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false. + widget.setFullScreen(false); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->windowControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + + // Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true. + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + widget.setFullScreen(true); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + widget.showFullScreen(); + QCOMPARE(object.testService->windowControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + + // Test if the window control exits full screen mode, the widget follows suit. + object.testService->windowControl->setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); + QCOMPARE(spy.value(5).value(0).toBool(), false); + + // Test if the window control enters full screen mode, the widget does nothing. + object.testService->windowControl->setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); +} + +void tst_QVideoWidget::fullScreenWidgetControl() +{ + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + Qt::WindowFlags windowFlags = widget.windowFlags(); + + QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool))); + + // Test showing full screen with setFullScreen(true). + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toBool(), true); + + // Test returning to normal with setFullScreen(false). + widget.setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test showing full screen with showFullScreen(). + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 3); + QCOMPARE(spy.value(2).value(0).toBool(), true); + + // Test returning to normal with showNormal(). + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + QCOMPARE(spy.value(3).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false. + widget.setFullScreen(false); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + widget.showNormal(); + QCOMPARE(object.testService->widgetControl->isFullScreen(), false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + + // Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true. + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + widget.setFullScreen(true); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + widget.showFullScreen(); + QCOMPARE(object.testService->widgetControl->isFullScreen(), true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + + // Test if the window control exits full screen mode, the widget follows suit. + object.testService->widgetControl->setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); + QCOMPARE(spy.value(5).value(0).toBool(), false); + + // Test if the window control enters full screen mode, the widget does nothing. + object.testService->widgetControl->setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 6); +} + + +void tst_QVideoWidget::fullScreenRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + QVideoWidget widget; + widget.setMediaObject(&object); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + Qt::WindowFlags windowFlags = widget.windowFlags(); + + QSignalSpy spy(&widget, SIGNAL(fullScreenChanged(bool))); + + // Test showing full screen with setFullScreen(true). + widget.setFullScreen(true); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toBool(), true); + + // Test returning to normal with setFullScreen(false). + widget.setFullScreen(false); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test showing full screen with showFullScreen(). + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 3); + QCOMPARE(spy.value(2).value(0).toBool(), true); + + // Test returning to normal with showNormal(). + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + QCOMPARE(spy.value(3).value(0).toBool(), false); + QCOMPARE(widget.windowFlags(), windowFlags); + + // Test setFullScreen(false) and showNormal() do nothing when isFullScreen() == false. + widget.setFullScreen(false); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + widget.showNormal(); + QCOMPARE(widget.isFullScreen(), false); + QCOMPARE(spy.count(), 4); + + // Test setFullScreen(true) and showFullScreen() do nothing when isFullScreen() == true. + widget.showFullScreen(); + QTest::qWaitForWindowShown(&widget); + widget.setFullScreen(true); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); + widget.showFullScreen(); + QCOMPARE(widget.isFullScreen(), true); + QCOMPARE(spy.count(), 5); +} + + +void tst_QVideoWidget::color_data() +{ + QTest::addColumn("controlValue"); + QTest::addColumn("value"); + QTest::addColumn("expectedValue"); + + QTest::newRow("12") + << 0 + << 12 + << 12; + QTest::newRow("-56") + << 87 + << -56 + << -56; + QTest::newRow("100") + << 32 + << 100 + << 100; + QTest::newRow("1294") + << 0 + << 1294 + << 100; + QTest::newRow("-102") + << 34 + << -102 + << -100; +} + +void tst_QVideoWidget::brightnessWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setBrightness(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + // Test the video widget resets the controls starting brightness to the default. + QCOMPARE(widget.brightness(), 0); + + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + // Test the video widget sets the brightness value, bounded if necessary and emits a changed + // signal. + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->windowControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + // Test the changed signal isn't emitted if the value is unchanged. + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->windowControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + + // Test the changed signal is emitted if the brightness is changed internally. + object.testService->windowControl->setBrightness(controlValue); + QCOMPARE(widget.brightness(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::brightnessWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setBrightness(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(widget.brightness(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->widgetControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(object.testService->widgetControl->brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setBrightness(controlValue); + QCOMPARE(widget.brightness(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::brightnessRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(brightnessChanged(int))); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setBrightness(value); + QCOMPARE(widget.brightness(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +void tst_QVideoWidget::contrastWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setContrast(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(widget.contrast(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.contrast(), 0); + + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->windowControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->windowControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->windowControl->setContrast(controlValue); + QCOMPARE(widget.contrast(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::contrastWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setContrast(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.contrast(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.contrast(), 0); + + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->widgetControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(object.testService->widgetControl->contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setContrast(controlValue); + QCOMPARE(widget.contrast(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::contrastRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(contrastChanged(int))); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setContrast(value); + QCOMPARE(widget.contrast(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +void tst_QVideoWidget::hueWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setHue(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.hue(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.hue(), 0); + + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->windowControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->windowControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->windowControl->setHue(controlValue); + QCOMPARE(widget.hue(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::hueWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setHue(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.hue(), 0); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.hue(), 0); + + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->widgetControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(object.testService->widgetControl->hue(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setHue(controlValue); + QCOMPARE(widget.hue(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::hueRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QSignalSpy spy(&widget, SIGNAL(hueChanged(int))); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setHue(value); + QCOMPARE(widget.hue(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +void tst_QVideoWidget::saturationWindowControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(new QtTestWindowControl, 0, 0); + object.testService->windowControl->setSaturation(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + QCOMPARE(widget.saturation(), 0); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.saturation(), 0); + + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->windowControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->windowControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->windowControl->setSaturation(controlValue); + QCOMPARE(widget.saturation(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); +} + +void tst_QVideoWidget::saturationWidgetControl() +{ + QFETCH(int, controlValue); + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, new QtTestWidgetControl, 0); + object.testService->widgetControl->setSaturation(controlValue); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + + QCOMPARE(widget.saturation(), 0); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QCOMPARE(widget.saturation(), 0); + + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->widgetControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(object.testService->widgetControl->saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + + object.testService->widgetControl->setSaturation(controlValue); + QCOMPARE(widget.saturation(), controlValue); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.value(1).value(0).toInt(), controlValue); + +} + +void tst_QVideoWidget::saturationRendererControl() +{ + QFETCH(int, value); + QFETCH(int, expectedValue); + + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QSignalSpy spy(&widget, SIGNAL(saturationChanged(int))); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.value(0).value(0).toInt(), expectedValue); + + widget.setSaturation(value); + QCOMPARE(widget.saturation(), expectedValue); + QCOMPARE(spy.count(), 1); +} + +static const uchar rgb32ImageData[] = +{ + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00 +}; + +void tst_QVideoWidget::paintRendererControl() +{ + QtTestVideoObject object(0, 0, new QtTestRendererControl); + + QVideoWidget widget; + widget.setMediaObject(&object); + widget.setWindowFlags(Qt::X11BypassWindowManagerHint); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + QPainterVideoSurface *surface = qobject_cast( + object.testService->rendererControl->surface()); + + QVideoSurfaceFormat format(QSize(2, 2), QVideoFrame::Format_RGB32); + + QVERIFY(surface->start(format)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QCoreApplication::processEvents(QEventLoop::AllEvents); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QVideoFrame frame(sizeof(rgb32ImageData), QSize(2, 2), 8, QVideoFrame::Format_RGB32); + + frame.map(QAbstractVideoBuffer::WriteOnly); + memcpy(frame.bits(), rgb32ImageData, frame.mappedBytes()); + frame.unmap(); + + QVERIFY(surface->present(frame)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), false); + + QCoreApplication::processEvents(QEventLoop::AllEvents); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); +} + +QTEST_MAIN(tst_QVideoWidget) + +#include "tst_qvideowidget.moc" diff --git a/tests/auto/tests.xml b/tests/auto/tests.xml index f197de0..96c3094 100644 --- a/tests/auto/tests.xml +++ b/tests/auto/tests.xml @@ -276,6 +276,17 @@ + + + + + + + + + + + -- cgit v0.12 From 9095df7d5454be2a0814f59fb3f3270c7783847a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 10:42:38 +0100 Subject: Compile Some errors introduced by merges. --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 21 +++------------------ .../gl2paintengineex/qpaintengineex_opengl2_p.h | 2 +- src/opengl/qpaintengine_opengl.cpp | 2 +- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 638e4d3..4c3b343 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1228,17 +1228,6 @@ void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const d->drawTexture(dest, srcRect, size, false); } -void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) -{ - Q_D(QGL2PaintEngineEx); - - ensureActive(); - - // ### What about transformations and huge fonts? These are not passed through cache - // in drawTextItem(). - d->drawCachedGlyphs(textItem); -} - void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) { Q_D(QGL2PaintEngineEx); @@ -1287,7 +1276,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem staticTextItem.numGlyphs = glyphs.size(); staticTextItem.glyphPositions = positions.data(); - d->drawCachedGlyphs(&staticTextItem); + d->drawCachedGlyphs(glyphType, &staticTextItem); } return; } @@ -1295,14 +1284,10 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem QPaintEngineEx::drawTextItem(p, ti); } -void QGL2PaintEngineExPrivate::drawCachedGlyphs(QStaticTextItem *staticTextItem) +void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem) { Q_Q(QGL2PaintEngineEx); - QFontEngineGlyphCache::Type glyphType = staticTextItem->fontEngine->glyphFormat >= 0 - ? QFontEngineGlyphCache::Type(staticTextItem->fontEngine->glyphFormat) - : QFontEngineGlyphCache::Raster_A8; - QGLTextureGlyphCache *cache = (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { @@ -1434,7 +1419,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QStaticTextItem *staticTextItem) updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); - glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); + glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index b683b8b..a7a40a8 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -195,7 +195,7 @@ public: void stroke(const QVectorPath &path, const QPen &pen); void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); - void drawCachedGlyphs(QStaticTextItem *staticTextItem); + void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem); // Calls glVertexAttributePointer if the pointer has changed inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer); diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index fecbc45..a2f085c 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -4914,7 +4914,7 @@ void QOpenGLPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) d->flushDrawQueue(); // make sure the glyphs we want to draw are in the cache - qt_glyph_cache()->cacheGlyphs(d->device.context(), textItem->fontEngine, textItem->glyphs, + qt_glyph_cache()->cacheGlyphs(d->device->context(), textItem->fontEngine, textItem->glyphs, textItem->numGlyphs); d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops -- cgit v0.12 From 9ec5972b3d7b972e74f6d7504d81d062ccdd863d Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 13:06:30 +0100 Subject: Update size comment The pointers are included in the per item overhead. --- src/gui/text/qstatictext_p.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 8c8cea8..33d2d39 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -68,11 +68,12 @@ public: // ================= // 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 // ================ - // 12 bytes per item + // 24 bytes per item }; class QStaticText; -- cgit v0.12 From 7d2d897eca62d70943a8e7c3aba99336f368e19f Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 13:07:09 +0100 Subject: Fix crash when wrapping text The two runs (counting the number of items and then storing the information) needs to be identical, so they need to have the same text flags set. Otherwise we would count more items than we actually generated and crash later when we tried to access an uninitialized item. --- src/gui/text/qstatictext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 85d3c81..79f8aa5 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -484,7 +484,7 @@ void QStaticTextPrivate::init() if (size.isValid()) { QRectF boundingRect; - painter.drawText(QRectF(QPointF(0, 0), size), 0, text, &boundingRect); + painter.drawText(QRectF(QPointF(0, 0), size), Qt::TextWordWrap, text, &boundingRect); needsClipRect = boundingRect.width() > size.width() || boundingRect.height() > size.height(); -- cgit v0.12 From 5ff3ab8f2ddcac57df3f3d9114fe3913659fcee8 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 13:19:22 +0100 Subject: Add tests for QStaticText::prepare() --- tests/auto/qstatictext/tst_qstatictext.cpp | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 0e1532b..66275b2 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -61,6 +61,8 @@ private slots: void drawToRect(); void setFont(); void setMaximumSize(); + void prepareToCorrectData(); + void prepareToWrongData(); void translatedPainter(); void rotatedPainter(); @@ -116,9 +118,58 @@ void tst_QStaticText::drawToRect() p.drawStaticText(11, 12, text); } + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::prepareToCorrectData() +{ + QTransform transform; + transform.scale(2.0, 2.0); + transform.rotate(90, Qt::ZAxis); + + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.setTransform(transform); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + p.setTransform(transform); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.prepare(transform, p.font()); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::prepareToWrongData() +{ + QTransform transform; + transform.scale(2.0, 2.0); + transform.rotate(90, Qt::ZAxis); + + QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawText); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.prepare(transform, p.font()); + p.drawStaticText(11, 12, text); + } + QCOMPARE(imageDrawStaticText, imageDrawText); } + void tst_QStaticText::setFont() { QFont font = QApplication::font(); -- cgit v0.12 From 629b565a697911904558ad0127a240a535489787 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 13:20:15 +0100 Subject: Remove translationDoesNotCauseRelayout test This is more suited to be a benchmark, as it doesn't cover the functionality of the class. --- tests/auto/qstatictext/tst_qstatictext.cpp | 45 ------------------------------ 1 file changed, 45 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 66275b2..c41b34b1 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -69,7 +69,6 @@ private slots: void scaledPainter(); void rotatedScaledAndTranslatedPainter(); void transformationChanged(); - void translationDoesntCauseRelayout(); }; void tst_QStaticText::init() @@ -351,49 +350,5 @@ void tst_QStaticText::transformationChanged() QCOMPARE(imageDrawStaticText, imageDrawText); } -void tst_QStaticText::translationDoesntCauseRelayout() -{ - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); - { - QPainter p(&imageDrawText); - p.scale(2.0, 2.0); - p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - - p.translate(100, 200); - p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - } - - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); - { - QPainter p(&imageDrawStaticText); - p.scale(2.0, 2.0); - QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(0, 0, text); - - QStaticTextPrivate *textd = QStaticTextPrivate::get(&text); - glyph_t *glyphPool = textd->glyphPool; - QFixedPoint *positionPool = textd->positionPool; - QStaticTextItem *items = textd->items; - - p.translate(100, 200); - p.drawStaticText(0, 0, text); - - // ### - // If the layout is recalculated, the data is reallocated. Not a entirely deterministic - // test, since the memory can be reused. - QCOMPARE(textd->glyphPool, glyphPool); - QCOMPARE(textd->positionPool, positionPool); - QCOMPARE(textd->items, items); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("translationDoesntCauseRelayout_imageDrawText.png"); - imageDrawStaticText.save("translationDoesntCauseRelayout_imageDrawStaticText.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); -} - - QTEST_MAIN(tst_QStaticText) #include "tst_qstatictext.moc" -- cgit v0.12 From 4e568e32ccfc758caa302ca1e785f2208073c991 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 13:25:41 +0100 Subject: Test current graphics system + initialize memory Using QImage would only let us test the raster engine. Substitute QPixmap, so we can test different graphics systems. Also initialize the memory in the pixmaps (this was missed because memory is initialized by default in debug builds.) --- tests/auto/qstatictext/tst_qstatictext.cpp | 67 ++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index c41b34b1..adc9593 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -86,13 +86,15 @@ void tst_QStaticText::constructionAndDestruction() void tst_QStaticText::drawToPoint() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); @@ -104,13 +106,15 @@ void tst_QStaticText::drawToPoint() void tst_QStaticText::drawToRect() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500)); @@ -126,14 +130,16 @@ void tst_QStaticText::prepareToCorrectData() transform.scale(2.0, 2.0); transform.rotate(90, Qt::ZAxis); - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.setTransform(transform); p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); p.setTransform(transform); @@ -151,13 +157,15 @@ void tst_QStaticText::prepareToWrongData() transform.scale(2.0, 2.0); transform.rotate(90, Qt::ZAxis); - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); @@ -175,7 +183,8 @@ void tst_QStaticText::setFont() font.setBold(true); font.setPointSize(28); - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); @@ -184,7 +193,8 @@ void tst_QStaticText::setFont() p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); @@ -201,13 +211,15 @@ void tst_QStaticText::setFont() void tst_QStaticText::setMaximumSize() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); @@ -220,7 +232,8 @@ void tst_QStaticText::setMaximumSize() void tst_QStaticText::translatedPainter() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.translate(100, 200); @@ -228,7 +241,8 @@ void tst_QStaticText::translatedPainter() p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); p.translate(100, 200); @@ -242,14 +256,16 @@ void tst_QStaticText::translatedPainter() void tst_QStaticText::rotatedPainter() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.rotate(30.0); p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); @@ -268,7 +284,8 @@ void tst_QStaticText::rotatedPainter() void tst_QStaticText::scaledPainter() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.scale(2.0, 0.2); @@ -276,7 +293,8 @@ void tst_QStaticText::scaledPainter() p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); p.scale(2.0, 0.2); @@ -290,7 +308,8 @@ void tst_QStaticText::scaledPainter() void tst_QStaticText::rotatedScaledAndTranslatedPainter() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.rotate(45.0); @@ -300,7 +319,8 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); p.rotate(45.0); @@ -316,8 +336,8 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() void tst_QStaticText::transformationChanged() { - QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied); - + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); p.rotate(33.0); @@ -329,7 +349,8 @@ void tst_QStaticText::transformationChanged() p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } - QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied); + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); p.rotate(33.0); -- cgit v0.12 From 4b01aa0eb6e4f13b5b3a822a9e60f88a61b4d591 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 14:18:43 +0100 Subject: Use fallback when drawing projected text Projected text always has to go via paths, so we use the fall back for this. --- src/gui/painting/qpainter.cpp | 2 +- tests/auto/qstatictext/tst_qstatictext.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 114492d..54eed03 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5735,7 +5735,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // If we don't have an extended paint engine, or if the painter is transformed, // we go through standard code path - if (d->extended == 0) { + if (d->extended == 0 || !d->state->matrix.isAffine()) { if (staticText_d->size.isValid()) drawText(QRectF(position, staticText_d->size), staticText_d->text); else diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index adc9593..ca83f2f 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -67,6 +67,7 @@ private slots: void translatedPainter(); void rotatedPainter(); void scaledPainter(); + void projectedPainter(); void rotatedScaledAndTranslatedPainter(); void transformationChanged(); }; @@ -306,6 +307,34 @@ void tst_QStaticText::scaledPainter() QCOMPARE(imageDrawStaticText, imageDrawText); } +void tst_QStaticText::projectedPainter() +{ + QTransform transform; + transform.rotate(90, Qt::XAxis); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.setTransform(transform); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.setTransform(transform); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawStaticText(11, 12, text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); + +} + void tst_QStaticText::rotatedScaledAndTranslatedPainter() { QPixmap imageDrawText(1000, 1000); -- cgit v0.12 From c2337d7f1d3b4239c21809d664cc60009d08449c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 15 Jan 2010 14:43:49 +0100 Subject: doc: Add some performance hints to the documentation --- src/gui/text/qstatictext.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 79f8aa5..307d2e6 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -64,8 +64,15 @@ QT_BEGIN_NAMESPACE The class primarily provides an optimization for cases where text and the transformations on the painter are static over several paint events. If the text or its layout is changed regularly, QPainter::drawText() is the more efficient alternative. Translating the painter - will not affect the performance of drawStaticText(), but altering any other parts of the - painter's transformation will cause the layout of the static text to be recalculated. + 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 @@ -95,8 +102,8 @@ QT_BEGIN_NAMESPACE 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 without affecting - performance. + passed to QPainter::drawStaticText() and can change from call to call with a minimal impact + on performance. \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument */ -- cgit v0.12 From 70f1fc423cbd6676f4b872fd87579cf41f5240e5 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 18 Jan 2010 12:35:39 +1000 Subject: Multimedia; Add player demo. --- demos/multimedia/player/main.cpp | 54 +++++ demos/multimedia/player/player.cpp | 325 +++++++++++++++++++++++++++++ demos/multimedia/player/player.h | 109 ++++++++++ demos/multimedia/player/player.pro | 22 ++ demos/multimedia/player/playercontrols.cpp | 205 ++++++++++++++++++ demos/multimedia/player/playercontrols.h | 107 ++++++++++ demos/multimedia/player/playlistmodel.cpp | 160 ++++++++++++++ demos/multimedia/player/playlistmodel.h | 95 +++++++++ demos/multimedia/player/videowidget.cpp | 72 +++++++ demos/multimedia/player/videowidget.h | 66 ++++++ 10 files changed, 1215 insertions(+) create mode 100644 demos/multimedia/player/main.cpp create mode 100644 demos/multimedia/player/player.cpp create mode 100644 demos/multimedia/player/player.h create mode 100644 demos/multimedia/player/player.pro create mode 100644 demos/multimedia/player/playercontrols.cpp create mode 100644 demos/multimedia/player/playercontrols.h create mode 100644 demos/multimedia/player/playlistmodel.cpp create mode 100644 demos/multimedia/player/playlistmodel.h create mode 100644 demos/multimedia/player/videowidget.cpp create mode 100644 demos/multimedia/player/videowidget.h diff --git a/demos/multimedia/player/main.cpp b/demos/multimedia/player/main.cpp new file mode 100644 index 0000000..87c5b87 --- /dev/null +++ b/demos/multimedia/player/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 "player.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + Player player; + player.show(); + + return app.exec(); +}; diff --git a/demos/multimedia/player/player.cpp b/demos/multimedia/player/player.cpp new file mode 100644 index 0000000..38d96d6 --- /dev/null +++ b/demos/multimedia/player/player.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 "player.h" + +#include "playercontrols.h" +#include "playlistmodel.h" +#include "videowidget.h" + +#include +#include + +#include + +Player::Player(QWidget *parent) + : QWidget(parent) + , videoWidget(0) + , coverLabel(0) + , slider(0) + , colorDialog(0) +{ + player = new QMediaPlayer(this); + playlist = new QMediaPlaylist(this); + playlist->setMediaObject(player); + + connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64))); + connect(player, SIGNAL(positionChanged(qint64)), SLOT(positionChanged(qint64))); + connect(player, SIGNAL(metaDataChanged()), SLOT(metaDataChanged())); + connect(playlist, SIGNAL(currentIndexChanged(int)), SLOT(playlistPositionChanged(int))); + connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SLOT(statusChanged(QMediaPlayer::MediaStatus))); + connect(player, SIGNAL(bufferStatusChanged(int)), this, SLOT(bufferingProgress(int))); + + videoWidget = new VideoWidget; + videoWidget->setMediaObject(player); + + playlistModel = new PlaylistModel(this); + playlistModel->setPlaylist(playlist); + + playlistView = new QListView; + playlistView->setModel(playlistModel); + playlistView->setCurrentIndex(playlistModel->index(playlist->currentIndex(), 0)); + + connect(playlistView, SIGNAL(activated(QModelIndex)), this, SLOT(jump(QModelIndex))); + + slider = new QSlider(Qt::Horizontal); + slider->setRange(0, player->duration() / 1000); + + connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int))); + + QPushButton *openButton = new QPushButton(tr("Open")); + + connect(openButton, SIGNAL(clicked()), this, SLOT(open())); + + PlayerControls *controls = new PlayerControls; + controls->setState(player->state()); + controls->setVolume(player->volume()); + controls->setMuted(controls->isMuted()); + + connect(controls, SIGNAL(play()), player, SLOT(play())); + connect(controls, SIGNAL(pause()), player, SLOT(pause())); + connect(controls, SIGNAL(stop()), player, SLOT(stop())); + connect(controls, SIGNAL(next()), playlist, SLOT(next())); + connect(controls, SIGNAL(previous()), playlist, SLOT(previous())); + connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int))); + connect(controls, SIGNAL(changeMuting(bool)), player, SLOT(setMuted(bool))); + connect(controls, SIGNAL(changeRate(qreal)), player, SLOT(setPlaybackRate(qreal))); + + connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), + controls, SLOT(setState(QMediaPlayer::State))); + connect(player, SIGNAL(volumeChanged(int)), controls, SLOT(setVolume(int))); + connect(player, SIGNAL(mutedChanged(bool)), controls, SLOT(setMuted(bool))); + + QPushButton *fullScreenButton = new QPushButton(tr("FullScreen")); + fullScreenButton->setCheckable(true); + + if (videoWidget != 0) { + connect(fullScreenButton, SIGNAL(clicked(bool)), videoWidget, SLOT(setFullScreen(bool))); + connect(videoWidget, SIGNAL(fullScreenChanged(bool)), + fullScreenButton, SLOT(setChecked(bool))); + } else { + fullScreenButton->setEnabled(false); + } + + QPushButton *colorButton = new QPushButton(tr("Color Options...")); + if (videoWidget) + connect(colorButton, SIGNAL(clicked()), this, SLOT(showColorDialog())); + else + colorButton->setEnabled(false); + + QBoxLayout *displayLayout = new QHBoxLayout; + if (videoWidget) + displayLayout->addWidget(videoWidget, 2); + else + displayLayout->addWidget(coverLabel, 2); + displayLayout->addWidget(playlistView); + + QBoxLayout *controlLayout = new QHBoxLayout; + controlLayout->setMargin(0); + controlLayout->addWidget(openButton); + controlLayout->addStretch(1); + controlLayout->addWidget(controls); + controlLayout->addStretch(1); + controlLayout->addWidget(fullScreenButton); + controlLayout->addWidget(colorButton); + + QBoxLayout *layout = new QVBoxLayout; + layout->addLayout(displayLayout); + layout->addWidget(slider); + layout->addLayout(controlLayout); + + setLayout(layout); + + metaDataChanged(); + + QStringList fileNames = qApp->arguments(); + fileNames.removeAt(0); + foreach (QString const &fileName, fileNames) { + if (QFileInfo(fileName).exists()) + playlist->addMedia(QUrl::fromLocalFile(fileName)); + } +} + +Player::~Player() +{ + delete playlist; + delete player; +} + +void Player::open() +{ + QStringList fileNames = QFileDialog::getOpenFileNames(); + foreach (QString const &fileName, fileNames) + playlist->addMedia(QUrl::fromLocalFile(fileName)); +} + +void Player::durationChanged(qint64 duration) +{ + slider->setMaximum(duration / 1000); +} + +void Player::positionChanged(qint64 progress) +{ + slider->setValue(progress / 1000); +} + +void Player::metaDataChanged() +{ + //qDebug() << "update metadata" << player->metaData(QtMedia::Title).toString(); + if (player->isMetaDataAvailable()) { + setTrackInfo(QString("%1 - %2") + .arg(player->metaData(QtMedia::AlbumArtist).toString()) + .arg(player->metaData(QtMedia::Title).toString())); + + if (coverLabel) { + QUrl url = player->metaData(QtMedia::CoverArtUrlLarge).value(); + + coverLabel->setPixmap(!url.isEmpty() + ? QPixmap(url.toString()) + : QPixmap()); + } + } +} + +void Player::jump(const QModelIndex &index) +{ + if (index.isValid()) { + playlist->setCurrentIndex(index.row()); + player->play(); + } +} + +void Player::playlistPositionChanged(int currentItem) +{ + playlistView->setCurrentIndex(playlistModel->index(currentItem, 0)); +} + +void Player::seek(int seconds) +{ + player->setPosition(seconds * 1000); +} + +void Player::statusChanged(QMediaPlayer::MediaStatus status) +{ + switch (status) { + case QMediaPlayer::UnknownMediaStatus: + case QMediaPlayer::NoMedia: + case QMediaPlayer::LoadedMedia: + case QMediaPlayer::BufferingMedia: + case QMediaPlayer::BufferedMedia: +#ifndef QT_NO_CURSOR + unsetCursor(); +#endif + setStatusInfo(QString()); + break; + case QMediaPlayer::LoadingMedia: +#ifndef QT_NO_CURSOR + setCursor(QCursor(Qt::BusyCursor)); +#endif + setStatusInfo(tr("Loading...")); + break; + case QMediaPlayer::StalledMedia: +#ifndef QT_NO_CURSOR + setCursor(QCursor(Qt::BusyCursor)); +#endif + break; + case QMediaPlayer::EndOfMedia: +#ifndef QT_NO_CURSOR + unsetCursor(); +#endif + setStatusInfo(QString()); + QApplication::alert(this); + break; + case QMediaPlayer::InvalidMedia: +#ifndef QT_NO_CURSOR + unsetCursor(); +#endif + setStatusInfo(player->errorString()); + break; + } +} + +void Player::bufferingProgress(int progress) +{ + setStatusInfo(tr("Buffering %4%%").arg(progress)); +} + +void Player::setTrackInfo(const QString &info) +{ + trackInfo = info; + + if (!statusInfo.isEmpty()) + setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo)); + else + setWindowTitle(trackInfo); + +} + +void Player::setStatusInfo(const QString &info) +{ + statusInfo = info; + + if (!statusInfo.isEmpty()) + setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo)); + else + setWindowTitle(trackInfo); +} + +void Player::showColorDialog() +{ + if (!colorDialog) { + QSlider *brightnessSlider = new QSlider(Qt::Horizontal); + brightnessSlider->setRange(-100, 100); + brightnessSlider->setValue(videoWidget->brightness()); + connect(brightnessSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setBrightness(int))); + connect(videoWidget, SIGNAL(brightnessChanged(int)), brightnessSlider, SLOT(setValue(int))); + + QSlider *contrastSlider = new QSlider(Qt::Horizontal); + contrastSlider->setRange(-100, 100); + contrastSlider->setValue(videoWidget->contrast()); + connect(contrastSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setContrast(int))); + connect(videoWidget, SIGNAL(contrastChanged(int)), contrastSlider, SLOT(setValue(int))); + + QSlider *hueSlider = new QSlider(Qt::Horizontal); + hueSlider->setRange(-100, 100); + hueSlider->setValue(videoWidget->hue()); + connect(hueSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setHue(int))); + connect(videoWidget, SIGNAL(hueChanged(int)), hueSlider, SLOT(setValue(int))); + + QSlider *saturationSlider = new QSlider(Qt::Horizontal); + saturationSlider->setRange(-100, 100); + saturationSlider->setValue(videoWidget->saturation()); + connect(saturationSlider, SIGNAL(sliderMoved(int)), videoWidget, SLOT(setSaturation(int))); + connect(videoWidget, SIGNAL(saturationChanged(int)), saturationSlider, SLOT(setValue(int))); + + QFormLayout *layout = new QFormLayout; + layout->addRow(tr("Brightness"), brightnessSlider); + layout->addRow(tr("Contrast"), contrastSlider); + layout->addRow(tr("Hue"), hueSlider); + layout->addRow(tr("Saturation"), saturationSlider); + + colorDialog = new QDialog(this); + colorDialog->setWindowTitle(tr("Color Options")); + colorDialog->setLayout(layout); + } + colorDialog->show(); +} diff --git a/demos/multimedia/player/player.h b/demos/multimedia/player/player.h new file mode 100644 index 0000000..0ad609b --- /dev/null +++ b/demos/multimedia/player/player.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 PLAYER_H +#define PLAYER_H + +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractItemView; +class QLabel; +class QModelIndex; +class QSlider; +class QMediaPlayer; +class QVideoWidget; +class PlaylistModel; + +class Player : public QWidget +{ + Q_OBJECT +public: + Player(QWidget *parent = 0); + ~Player(); + +Q_SIGNALS: + void fullScreenChanged(bool fullScreen); + +private slots: + void open(); + void durationChanged(qint64 duration); + void positionChanged(qint64 progress); + void metaDataChanged(); + + void seek(int seconds); + void jump(const QModelIndex &index); + void playlistPositionChanged(int); + + void statusChanged(QMediaPlayer::MediaStatus status); + void bufferingProgress(int progress); + + void showColorDialog(); + +private: + void setTrackInfo(const QString &info); + void setStatusInfo(const QString &info); + + QMediaPlayer *player; + QMediaPlaylist *playlist; + QVideoWidget *videoWidget; + QLabel *coverLabel; + QSlider *slider; + PlaylistModel *playlistModel; + QAbstractItemView *playlistView; + QDialog *colorDialog; + QString trackInfo; + QString statusInfo; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/demos/multimedia/player/player.pro b/demos/multimedia/player/player.pro new file mode 100644 index 0000000..dc731e4 --- /dev/null +++ b/demos/multimedia/player/player.pro @@ -0,0 +1,22 @@ +TEMPLATE = app +TARGET = player + +QT += gui multimedia + + +HEADERS = \ + player.h \ + playercontrols.h \ + playlistmodel.h \ + videowidget.h + +SOURCES = \ + main.cpp \ + player.cpp \ + playercontrols.cpp \ + playlistmodel.cpp \ + videowidget.cpp + +target.path = $$[QT_INSTALL_DEMOS]/multimedia/player +INSTALLS += target + diff --git a/demos/multimedia/player/playercontrols.cpp b/demos/multimedia/player/playercontrols.cpp new file mode 100644 index 0000000..3798a71 --- /dev/null +++ b/demos/multimedia/player/playercontrols.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 "playercontrols.h" + +#include +#include +#include +#include +#include + +PlayerControls::PlayerControls(QWidget *parent) + : QWidget(parent) + , playerState(QMediaPlayer::StoppedState) + , playerMuted(false) + , playButton(0) + , stopButton(0) + , nextButton(0) + , previousButton(0) + , muteButton(0) + , volumeSlider(0) + , rateBox(0) +{ + playButton = new QToolButton; + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + + connect(playButton, SIGNAL(clicked()), this, SLOT(playClicked())); + + stopButton = new QToolButton; + stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop)); + stopButton->setEnabled(false); + + connect(stopButton, SIGNAL(clicked()), this, SIGNAL(stop())); + + nextButton = new QToolButton; + nextButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); + + connect(nextButton, SIGNAL(clicked()), this, SIGNAL(next())); + + previousButton = new QToolButton; + previousButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); + + connect(previousButton, SIGNAL(clicked()), this, SIGNAL(previous())); + + muteButton = new QToolButton; + muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume)); + + connect(muteButton, SIGNAL(clicked()), this, SLOT(muteClicked())); + + volumeSlider = new QSlider(Qt::Horizontal); + volumeSlider->setRange(0, 100); + + connect(volumeSlider, SIGNAL(sliderMoved(int)), this, SIGNAL(changeVolume(int))); + + rateBox = new QComboBox; + rateBox->addItem("0.5x", QVariant(0.5)); + rateBox->addItem("1.0x", QVariant(1.0)); + rateBox->addItem("2.0x", QVariant(2.0)); + rateBox->setCurrentIndex(1); + + connect(rateBox, SIGNAL(activated(int)), SLOT(updateRate())); + + QBoxLayout *layout = new QHBoxLayout; + layout->setMargin(0); + layout->addWidget(stopButton); + layout->addWidget(previousButton); + layout->addWidget(playButton); + layout->addWidget(nextButton); + layout->addWidget(muteButton); + layout->addWidget(volumeSlider); + layout->addWidget(rateBox); + setLayout(layout); +} + +QMediaPlayer::State PlayerControls::state() const +{ + return playerState; +} + +void PlayerControls::setState(QMediaPlayer::State state) +{ + if (state != playerState) { + playerState = state; + + switch (state) { + case QMediaPlayer::StoppedState: + stopButton->setEnabled(false); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + case QMediaPlayer::PlayingState: + stopButton->setEnabled(true); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); + break; + case QMediaPlayer::PausedState: + stopButton->setEnabled(true); + playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + } + } +} + +int PlayerControls::volume() const +{ + return volumeSlider->value(); +} + +void PlayerControls::setVolume(int volume) +{ + volumeSlider->setValue(volume); +} + +bool PlayerControls::isMuted() const +{ + return playerMuted; +} + +void PlayerControls::setMuted(bool muted) +{ + if (muted != playerMuted) { + playerMuted = muted; + + muteButton->setIcon(style()->standardIcon(muted + ? QStyle::SP_MediaVolumeMuted + : QStyle::SP_MediaVolume)); + } +} + +void PlayerControls::playClicked() +{ + switch (playerState) { + case QMediaPlayer::StoppedState: + case QMediaPlayer::PausedState: + emit play(); + break; + case QMediaPlayer::PlayingState: + emit pause(); + break; + } +} + +void PlayerControls::muteClicked() +{ + emit changeMuting(!playerMuted); +} + +qreal PlayerControls::playbackRate() const +{ + return rateBox->itemData(rateBox->currentIndex()).toDouble(); +} + +void PlayerControls::setPlaybackRate(float rate) +{ + for (int i=0; icount(); i++) { + if (qFuzzyCompare(rate, float(rateBox->itemData(i).toDouble()))) { + rateBox->setCurrentIndex(i); + return; + } + } + + rateBox->addItem( QString("%1x").arg(rate), QVariant(rate)); + rateBox->setCurrentIndex(rateBox->count()-1); +} + +void PlayerControls::updateRate() +{ + emit changeRate(playbackRate()); +} diff --git a/demos/multimedia/player/playercontrols.h b/demos/multimedia/player/playercontrols.h new file mode 100644 index 0000000..99894ff --- /dev/null +++ b/demos/multimedia/player/playercontrols.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 PLAYERCONTROLS_H +#define PLAYERCONTROLS_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractButton; +class QAbstractSlider; +class QComboBox; + +class PlayerControls : public QWidget +{ + Q_OBJECT +public: + PlayerControls(QWidget *parent = 0); + + QMediaPlayer::State state() const; + + int volume() const; + bool isMuted() const; + qreal playbackRate() const; + +public slots: + void setState(QMediaPlayer::State state); + void setVolume(int volume); + void setMuted(bool muted); + void setPlaybackRate(float rate); + +signals: + void play(); + void pause(); + void stop(); + void next(); + void previous(); + void changeVolume(int volume); + void changeMuting(bool muting); + void changeRate(qreal rate); + +private slots: + void playClicked(); + void muteClicked(); + void updateRate(); + +private: + QMediaPlayer::State playerState; + bool playerMuted; + QAbstractButton *playButton; + QAbstractButton *stopButton; + QAbstractButton *nextButton; + QAbstractButton *previousButton; + QAbstractButton *muteButton; + QAbstractSlider *volumeSlider; + QComboBox *rateBox; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/demos/multimedia/player/playlistmodel.cpp b/demos/multimedia/player/playlistmodel.cpp new file mode 100644 index 0000000..b60f914 --- /dev/null +++ b/demos/multimedia/player/playlistmodel.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 "playlistmodel.h" + +#include +#include + +#include + +PlaylistModel::PlaylistModel(QObject *parent) + : QAbstractItemModel(parent) + , m_playlist(0) +{ +} + +int PlaylistModel::rowCount(const QModelIndex &parent) const +{ + return m_playlist && !parent.isValid() ? m_playlist->mediaCount() : 0; +} + +int PlaylistModel::columnCount(const QModelIndex &parent) const +{ + return !parent.isValid() ? ColumnCount : 0; +} + +QModelIndex PlaylistModel::index(int row, int column, const QModelIndex &parent) const +{ + return m_playlist && !parent.isValid() + && row >= 0 && row < m_playlist->mediaCount() + && column >= 0 && column < ColumnCount + ? createIndex(row, column) + : QModelIndex(); +} + +QModelIndex PlaylistModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child); + + return QModelIndex(); +} + +QVariant PlaylistModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && role == Qt::DisplayRole) { + QVariant value = m_data[index]; + if (!value.isValid() && index.column() == Title) { + QUrl location = m_playlist->media(index.row()).canonicalUrl(); + return QFileInfo(location.path()).fileName(); + } + + return value; + } + return QVariant(); +} + +QMediaPlaylist *PlaylistModel::playlist() const +{ + return m_playlist; +} + +void PlaylistModel::setPlaylist(QMediaPlaylist *playlist) +{ + if (m_playlist) { + disconnect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int))); + disconnect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems())); + disconnect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int))); + disconnect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems())); + disconnect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int))); + } + + m_playlist = playlist; + + if (m_playlist) { + connect(m_playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SLOT(beginInsertItems(int,int))); + connect(m_playlist, SIGNAL(mediaInserted(int,int)), this, SLOT(endInsertItems())); + connect(m_playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SLOT(beginRemoveItems(int,int))); + connect(m_playlist, SIGNAL(mediaRemoved(int,int)), this, SLOT(endRemoveItems())); + connect(m_playlist, SIGNAL(mediaChanged(int,int)), this, SLOT(changeItems(int,int))); + } + + + reset(); +} + +bool PlaylistModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + Q_UNUSED(role); + m_data[index] = value; + emit dataChanged(index, index); + return true; +} + +void PlaylistModel::beginInsertItems(int start, int end) +{ + m_data.clear(); + beginInsertRows(QModelIndex(), start, end); +} + +void PlaylistModel::endInsertItems() +{ + endInsertRows(); +} + +void PlaylistModel::beginRemoveItems(int start, int end) +{ + m_data.clear(); + beginRemoveRows(QModelIndex(), start, end); +} + +void PlaylistModel::endRemoveItems() +{ + endInsertRows(); +} + +void PlaylistModel::changeItems(int start, int end) +{ + m_data.clear(); + emit dataChanged(index(start,0), index(end,ColumnCount)); +} + + diff --git a/demos/multimedia/player/playlistmodel.h b/demos/multimedia/player/playlistmodel.h new file mode 100644 index 0000000..0180282 --- /dev/null +++ b/demos/multimedia/player/playlistmodel.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 PLAYLISTMODEL_H +#define PLAYLISTMODEL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; + +class PlaylistModel : public QAbstractItemModel +{ + Q_OBJECT +public: + enum Column + { + Title = 0, + ColumnCount + }; + + PlaylistModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + QMediaPlaylist *playlist() const; + void setPlaylist(QMediaPlaylist *playlist); + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole); + +private slots: + void beginInsertItems(int start, int end); + void endInsertItems(); + void beginRemoveItems(int start, int end); + void endRemoveItems(); + void changeItems(int start, int end); + +private: + QMediaPlaylist *m_playlist; + QMap m_data; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/demos/multimedia/player/videowidget.cpp b/demos/multimedia/player/videowidget.cpp new file mode 100644 index 0000000..3bf36c3 --- /dev/null +++ b/demos/multimedia/player/videowidget.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 "videowidget.h" + +#include + +VideoWidget::VideoWidget(QWidget *parent) + : QVideoWidget(parent) +{ + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); +} + +void VideoWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape && isFullScreen()) { + showNormal(); + + event->accept(); + } else if (event->key() == Qt::Key_Enter && event->modifiers() & Qt::Key_Alt) { + setFullScreen(!isFullScreen()); + + event->accept(); + } else { + QVideoWidget::keyPressEvent(event); + } +} + +void VideoWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + setFullScreen(!isFullScreen()); + + event->accept(); +} diff --git a/demos/multimedia/player/videowidget.h b/demos/multimedia/player/videowidget.h new file mode 100644 index 0000000..543e1e0 --- /dev/null +++ b/demos/multimedia/player/videowidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class VideoWidget : public QVideoWidget +{ + Q_OBJECT +public: + VideoWidget(QWidget *parent = 0); + +protected: + void keyPressEvent(QKeyEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif -- cgit v0.12 From 29ae7af90a5bb86f9add481e8236b6ac91f22ad3 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 18 Jan 2010 12:36:30 +1000 Subject: Multimedia; fixes for linux --- src/multimedia/base/qmediaserviceprovider.cpp | 2 +- src/multimedia/base/qpaintervideosurface_p.h | 3 +++ src/plugins/mediaservices/mediaservices.pro | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/multimedia/base/qmediaserviceprovider.cpp b/src/multimedia/base/qmediaserviceprovider.cpp index 37115e7..f7c4e1f 100644 --- a/src/multimedia/base/qmediaserviceprovider.cpp +++ b/src/multimedia/base/qmediaserviceprovider.cpp @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include "qmediapluginloader_p.h" #include diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h index 2a146d0..a7d3e3a 100644 --- a/src/multimedia/base/qpaintervideosurface_p.h +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -65,6 +65,9 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +class QGLContext; + + class QVideoSurfacePainter; class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface { diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro index 765477d..03859bd 100644 --- a/src/plugins/mediaservices/mediaservices.pro +++ b/src/plugins/mediaservices/mediaservices.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -SUBDIRS += qt7 +mac:SUBDIRS += qt7 -- cgit v0.12 From 0b830897c6256b26289c912e28257d040e9c1b4c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 18 Jan 2010 15:26:19 +0100 Subject: Implement QPaintBufferEngine::drawStaticTextItem() Make QPaintEngineEx::drawStaticTextItem() pure virtual to make sure it's implemented in all engines, and implement the paint buffer version to make gui compile. --- src/gui/painting/qpaintbuffer.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/gui/painting/qpaintbuffer_p.h | 2 ++ src/gui/painting/qpaintengineex_p.h | 2 +- src/gui/text/qstatictext.h | 2 ++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 2344c04..e0067b0 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include @@ -960,6 +961,30 @@ 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); + + QFontDef fontDef = staticTextItem->fontEngine->fontDef; + QFont font(fontDef.family, fontDef.pointSize, fontDef.weight, fontDef.style == QFont::StyleItalic); + + QTransform xform; + for (int i=buffer->commands.size()-1; i>=0; --i) { + const QPaintBufferCommand &cmd = buffer->commands.at(i); + if (cmd.id == QPaintBufferPrivate::Cmd_SetTransform) { + xform = qVariantValue(buffer->variants.at(cmd.offset)); + break; + } + } + + QStaticText staticText(text); + staticText.prepare(xform, font); + + QVariantList variants; + variants << QVariant(font) << QVariant::fromValue(staticText); + buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants)); +} + void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) { #ifdef QPAINTBUFFER_DEBUG_DRAW @@ -1425,6 +1450,18 @@ 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()); + + QFont font(variants.at(0).value()); + QStaticText text(variants.at(0).value()); + + 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)); diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h index 79d7b35..41a26c5 100644 --- a/src/gui/painting/qpaintbuffer_p.h +++ b/src/gui/painting/qpaintbuffer_p.h @@ -175,6 +175,7 @@ public: Cmd_DrawText, Cmd_DrawTextItem, + Cmd_DrawStaticText, Cmd_DrawImagePos, Cmd_DrawImageRect, @@ -394,6 +395,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/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 1370e82..90c4f9f 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -201,7 +201,7 @@ public: virtual void updateState(const QPaintEngineState &state); - virtual void drawStaticTextItem(QStaticTextItem *) { /* ### should be pure virtual ### */ }; + virtual void drawStaticTextItem(QStaticTextItem *) = 0; virtual void setState(QPainterState *s); inline QPainterState *state() { return static_cast(QPaintEngine::state); } diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index e507d82..6c70816 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -85,6 +85,8 @@ private: friend class QStaticTextPrivate; }; +Q_DECLARE_METATYPE(QStaticText) + QT_END_NAMESPACE QT_END_HEADER -- cgit v0.12 From 07144fabe351f3a6021a2d213cfdba7ee55602a0 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Tue, 19 Jan 2010 12:16:42 +1000 Subject: Multimedia; Add GStreamer backend --- src/plugins/mediaservices/gstreamer/gstreamer.pro | 57 ++ .../gstreamer/mediaplayer/mediaplayer.pri | 19 + .../mediaplayer/qgstreamermetadataprovider.cpp | 204 ++++++ .../mediaplayer/qgstreamermetadataprovider.h | 83 +++ .../mediaplayer/qgstreamerplayercontrol.cpp | 334 ++++++++++ .../mediaplayer/qgstreamerplayercontrol.h | 128 ++++ .../mediaplayer/qgstreamerplayerservice.cpp | 137 +++++ .../mediaplayer/qgstreamerplayerservice.h | 101 +++ .../mediaplayer/qgstreamerplayersession.cpp | 683 +++++++++++++++++++++ .../mediaplayer/qgstreamerplayersession.h | 168 +++++ .../mediaplayer/qgstreamerstreamscontrol.cpp | 89 +++ .../mediaplayer/qgstreamerstreamscontrol.h | 71 +++ .../qgstreameraudioinputendpointselector.cpp | 172 ++++++ .../qgstreameraudioinputendpointselector.h | 83 +++ .../gstreamer/qgstreamerbushelper.cpp | 203 ++++++ .../mediaservices/gstreamer/qgstreamerbushelper.h | 87 +++ .../mediaservices/gstreamer/qgstreamermessage.cpp | 93 +++ .../mediaservices/gstreamer/qgstreamermessage.h | 76 +++ .../gstreamer/qgstreamerserviceplugin.cpp | 186 ++++++ .../gstreamer/qgstreamerserviceplugin.h | 76 +++ .../qgstreamervideoinputdevicecontrol.cpp | 157 +++++ .../gstreamer/qgstreamervideoinputdevicecontrol.h | 85 +++ .../gstreamer/qgstreamervideooutputcontrol.cpp | 72 +++ .../gstreamer/qgstreamervideooutputcontrol.h | 86 +++ .../gstreamer/qgstreamervideooverlay.cpp | 210 +++++++ .../gstreamer/qgstreamervideooverlay.h | 114 ++++ .../gstreamer/qgstreamervideorenderer.cpp | 82 +++ .../gstreamer/qgstreamervideorenderer.h | 78 +++ .../gstreamer/qgstreamervideorendererinterface.cpp | 46 ++ .../gstreamer/qgstreamervideorendererinterface.h | 69 +++ .../gstreamer/qgstreamervideowidget.cpp | 322 ++++++++++ .../gstreamer/qgstreamervideowidget.h | 109 ++++ .../mediaservices/gstreamer/qgstvideobuffer.cpp | 85 +++ .../mediaservices/gstreamer/qgstvideobuffer.h | 75 +++ .../gstreamer/qvideosurfacegstsink.cpp | 553 +++++++++++++++++ .../mediaservices/gstreamer/qvideosurfacegstsink.h | 141 +++++ .../mediaservices/gstreamer/qx11videosurface.cpp | 471 ++++++++++++++ .../mediaservices/gstreamer/qx11videosurface.h | 117 ++++ src/plugins/mediaservices/mediaservices.pro | 11 + 39 files changed, 5933 insertions(+) create mode 100644 src/plugins/mediaservices/gstreamer/gstreamer.pro create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp create mode 100644 src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamermessage.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h create mode 100644 src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstvideobuffer.h create mode 100644 src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h create mode 100644 src/plugins/mediaservices/gstreamer/qx11videosurface.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qx11videosurface.h diff --git a/src/plugins/mediaservices/gstreamer/gstreamer.pro b/src/plugins/mediaservices/gstreamer/gstreamer.pro new file mode 100644 index 0000000..e4e8d5a --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/gstreamer.pro @@ -0,0 +1,57 @@ +TARGET = gstengine +include(../../qpluginbase.pri) + +QT += multimedia + +unix:contains(QT_CONFIG, alsa) { + DEFINES += HAVE_ALSA + LIBS += -lasound +} + +LIBS += -lXv + +CONFIG += link_pkgconfig + +PKGCONFIG += \ + gstreamer-0.10 \ + gstreamer-base-0.10 \ + gstreamer-interfaces-0.10 \ + gstreamer-audio-0.10 \ + gstreamer-video-0.10 + +# Input +HEADERS += \ + qgstreamermessage.h \ + qgstreamerbushelper.h \ + qgstreamervideooutputcontrol.h \ + qgstreamervideorendererinterface.h \ + qgstreamervideowidget.h \ + qgstreamerserviceplugin.h \ +# qgstreameraudioinputendpointselector.h \ + qgstreamervideoinputdevicecontrol.h \ + qgstreamervideooverlay.h \ + qgstreamervideorenderer.h \ + qgstvideobuffer.h \ + qvideosurfacegstsink.h \ + qx11videosurface.h + +SOURCES += \ + qgstreamermessage.cpp \ + qgstreamerbushelper.cpp \ + qgstreamervideooutputcontrol.cpp \ + qgstreamervideorendererinterface.cpp \ + qgstreamervideowidget.cpp \ + qgstreamerserviceplugin.cpp \ +# qgstreameraudioinputendpointselector.cpp \ + qgstreamervideoinputdevicecontrol.cpp \ + qgstreamervideooverlay.cpp \ + qgstreamervideorenderer.cpp \ + qgstvideobuffer.cpp \ + qvideosurfacegstsink.cpp \ + qx11videosurface.cpp + +include(mediaplayer/mediaplayer.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices +target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices +INSTALLS += target diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri new file mode 100644 index 0000000..dda641c --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/mediaplayer.pri @@ -0,0 +1,19 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_GSTREAMER_PLAYER + +HEADERS += \ + $$PWD/qgstreamerplayercontrol.h \ + $$PWD/qgstreamerplayerservice.h \ + $$PWD/qgstreamerplayersession.h \ +# $$PWD/qgstreamerstreamscontrol.h \ + $$PWD/qgstreamermetadataprovider.h + +SOURCES += \ + $$PWD/qgstreamerplayercontrol.cpp \ + $$PWD/qgstreamerplayerservice.cpp \ + $$PWD/qgstreamerplayersession.cpp \ +# $$PWD/qgstreamerstreamscontrol.cpp \ + $$PWD/qgstreamermetadataprovider.cpp + + diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp new file mode 100644 index 0000000..c22e83c --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamermetadataprovider.h" +#include "qgstreamerplayersession.h" +#include + +#include + +struct QGstreamerMetaDataKeyLookup +{ + QtMedia::MetaData key; + const char *token; +}; + +static const QGstreamerMetaDataKeyLookup qt_gstreamerMetaDataKeys[] = +{ + { QtMedia::Title, GST_TAG_TITLE }, + //{ QtMedia::SubTitle, 0 }, + //{ QtMedia::Author, 0 }, + { QtMedia::Comment, GST_TAG_COMMENT }, + { QtMedia::Description, GST_TAG_DESCRIPTION }, + //{ QtMedia::Category, 0 }, + { QtMedia::Genre, GST_TAG_GENRE }, + { QtMedia::Year, "year" }, + //{ QtMedia::UserRating, 0 }, + + { QtMedia::Language, GST_TAG_LANGUAGE_CODE }, + + { QtMedia::Publisher, GST_TAG_ORGANIZATION }, + { QtMedia::Copyright, GST_TAG_COPYRIGHT }, + //{ QtMedia::ParentalRating, 0 }, + //{ QtMedia::RatingOrganisation, 0 }, + + // Media + //{ QtMedia::Size, 0 }, + //{ QtMedia::MediaType, 0 }, + { QtMedia::Duration, GST_TAG_DURATION }, + + // Audio + { QtMedia::AudioBitRate, GST_TAG_BITRATE }, + { QtMedia::AudioCodec, GST_TAG_AUDIO_CODEC }, + //{ QtMedia::ChannelCount, 0 }, + //{ QtMedia::Frequency, 0 }, + + // Music + { QtMedia::AlbumTitle, GST_TAG_ALBUM }, + { QtMedia::AlbumArtist, GST_TAG_ARTIST}, + { QtMedia::ContributingArtist, GST_TAG_PERFORMER }, +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 19) + { QtMedia::Composer, GST_TAG_COMPOSER }, +#endif + //{ QtMedia::Conductor, 0 }, + //{ QtMedia::Lyrics, 0 }, + //{ QtMedia::Mood, 0 }, + { QtMedia::TrackNumber, GST_TAG_TRACK_NUMBER }, + + //{ QtMedia::CoverArtUrlSmall, 0 }, + //{ QtMedia::CoverArtUrlLarge, 0 }, + + // Image/Video + //{ QtMedia::Resolution, 0 }, + //{ QtMedia::PixelAspectRatio, 0 }, + + // Video + //{ QtMedia::VideoFrameRate, 0 }, + //{ QtMedia::VideoBitRate, 0 }, + { QtMedia::VideoCodec, GST_TAG_VIDEO_CODEC }, + + //{ QtMedia::PosterUrl, 0 }, + + // Movie + //{ QtMedia::ChapterNumber, 0 }, + //{ QtMedia::Director, 0 }, + { QtMedia::LeadPerformer, GST_TAG_PERFORMER }, + //{ QtMedia::Writer, 0 }, + + // Photos + //{ QtMedia::CameraManufacturer, 0 }, + //{ QtMedia::CameraModel, 0 }, + //{ QtMedia::Event, 0 }, + //{ QtMedia::Subject, 0 } +}; + +QGstreamerMetaDataProvider::QGstreamerMetaDataProvider(QGstreamerPlayerSession *session, QObject *parent) + :QMetaDataControl(parent), m_session(session) +{ + connect(m_session, SIGNAL(tagsChanged()), SLOT(updateTags())); +} + +QGstreamerMetaDataProvider::~QGstreamerMetaDataProvider() +{ +} + +bool QGstreamerMetaDataProvider::isMetaDataAvailable() const +{ + return !m_session->tags().isEmpty(); +} + +bool QGstreamerMetaDataProvider::isWritable() const +{ + return false; +} + +QVariant QGstreamerMetaDataProvider::metaData(QtMedia::MetaData key) const +{ + static const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + + for (int i = 0; i < count; ++i) { + if (qt_gstreamerMetaDataKeys[i].key == key) { + return m_session->tags().value(QByteArray(qt_gstreamerMetaDataKeys[i].token)); + } + } + return QVariant(); +} + +void QGstreamerMetaDataProvider::setMetaData(QtMedia::MetaData key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QList QGstreamerMetaDataProvider::availableMetaData() const +{ + static QMap keysMap; + if (keysMap.isEmpty()) { + const int count = sizeof(qt_gstreamerMetaDataKeys) / sizeof(QGstreamerMetaDataKeyLookup); + for (int i = 0; i < count; ++i) { + keysMap[QByteArray(qt_gstreamerMetaDataKeys[i].token)] = qt_gstreamerMetaDataKeys[i].key; + } + } + + QList res; + foreach (const QByteArray &key, m_session->tags().keys()) { + QtMedia::MetaData tag = keysMap.value(key, QtMedia::MetaData(-1)); + if (tag != -1) + res.append(tag); + } + + return res; +} + +QVariant QGstreamerMetaDataProvider::extendedMetaData(const QString &key) const +{ + return m_session->tags().value(key.toLatin1()); +} + +void QGstreamerMetaDataProvider::setExtendedMetaData(const QString &key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QStringList QGstreamerMetaDataProvider::availableExtendedMetaData() const +{ + QStringList res; + foreach (const QByteArray &key, m_session->tags().keys()) + res.append(QString(key)); + + return res; +} + +void QGstreamerMetaDataProvider::updateTags() +{ + emit metaDataChanged(); +} diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h new file mode 100644 index 0000000..7e9af23 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERMETADATAPROVIDER_H +#define QGSTREAMERMETADATAPROVIDER_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerPlayerSession; + +class QGstreamerMetaDataProvider : public QMetaDataControl +{ + Q_OBJECT +public: + QGstreamerMetaDataProvider( QGstreamerPlayerSession *session, QObject *parent ); + virtual ~QGstreamerMetaDataProvider(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QGstreamerPlayerSession *m_session; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERMETADATAPROVIDER_H diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp new file mode 100644 index 0000000..730279a --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamerplayercontrol.h" +#include "qgstreamerplayersession.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +QGstreamerPlayerControl::QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent) + : QMediaPlayerControl(parent) + , m_session(session) + , m_stream(0) + , m_fifoNotifier(0) + , m_fifoCanWrite(false) + , m_bufferSize(0) + , m_bufferOffset(0) +{ + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + + connect(m_session, SIGNAL(positionChanged(qint64)), + this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(mutedStateChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(volumeChanged(int)), + this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_session,SIGNAL(bufferingProgressChanged(int)), + this, SIGNAL(bufferStatusChanged(int))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), + this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(seekableChanged(bool)), + this, SIGNAL(seekableChanged(bool))); +} + +QGstreamerPlayerControl::~QGstreamerPlayerControl() +{ + if (m_fifoFd[0] >= 0) { + ::close(m_fifoFd[0]); + ::close(m_fifoFd[1]); + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + } +} + +qint64 QGstreamerPlayerControl::position() const +{ + return m_session->position(); +} + +qint64 QGstreamerPlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QGstreamerPlayerControl::state() const +{ + return m_session->state(); +} + +QMediaPlayer::MediaStatus QGstreamerPlayerControl::mediaStatus() const +{ + return m_session->mediaStatus(); +} + +int QGstreamerPlayerControl::bufferStatus() const +{ + return 100; +} + +int QGstreamerPlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QGstreamerPlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QGstreamerPlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QGstreamerPlayerControl::availablePlaybackRanges() const +{ + QMediaTimeRange ranges; + + if (m_session->isSeekable()) + ranges.addInterval(0, m_session->duration()); + + return ranges; +} + +qreal QGstreamerPlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QGstreamerPlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QGstreamerPlayerControl::setPosition(qint64 pos) +{ + m_session->seek(pos); +} + +void QGstreamerPlayerControl::play() +{ + m_session->play(); + + if (m_fifoFd[1] >= 0) { + m_fifoCanWrite = true; + + writeFifo(); + } +} + +void QGstreamerPlayerControl::pause() +{ + m_session->pause(); +} + +void QGstreamerPlayerControl::stop() +{ + m_session->stop(); +} + +void QGstreamerPlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QGstreamerPlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QGstreamerPlayerControl::media() const +{ + return m_currentResource; +} + +const QIODevice *QGstreamerPlayerControl::mediaStream() const +{ + return m_stream; +} + +void QGstreamerPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + m_session->stop(); + + if (m_stream) { + closeFifo(); + + disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(writeFifo())); + m_stream = 0; + } + + m_currentResource = content; + m_stream = stream; + + QUrl url; + + if (m_stream) { + if (m_stream->isReadable() && openFifo()) { + url = QUrl(QString(QLatin1String("fd://%1")).arg(m_fifoFd[0])); + } + } else if (!content.isNull()) { + url = content.canonicalUrl(); + } + + m_session->load(url); + + emit mediaChanged(m_currentResource); +} + +void QGstreamerPlayerControl::setVideoOutput(QObject *output) +{ + m_session->setVideoRenderer(output); +} + +bool QGstreamerPlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + +void QGstreamerPlayerControl::writeFifo() +{ + if (m_fifoCanWrite) { + qint64 bytesToRead = qMin( + m_stream->bytesAvailable(), PIPE_BUF - m_bufferSize); + + if (bytesToRead > 0) { + int bytesRead = m_stream->read(&m_buffer[m_bufferOffset + m_bufferSize], bytesToRead); + + if (bytesRead > 0) + m_bufferSize += bytesRead; + } + + if (m_bufferSize > 0) { + int bytesWritten = ::write(m_fifoFd[1], &m_buffer[m_bufferOffset], size_t(m_bufferSize)); + + if (bytesWritten > 0) { + m_bufferOffset += bytesWritten; + m_bufferSize -= bytesWritten; + + if (m_bufferSize == 0) + m_bufferOffset = 0; + } else if (errno == EAGAIN) { + m_fifoCanWrite = false; + } else { + closeFifo(); + } + } + } + + m_fifoNotifier->setEnabled(m_stream->bytesAvailable() > 0); +} + +void QGstreamerPlayerControl::fifoReadyWrite(int socket) +{ + if (socket == m_fifoFd[1]) { + m_fifoCanWrite = true; + + writeFifo(); + } +} + +bool QGstreamerPlayerControl::openFifo() +{ + Q_ASSERT(m_fifoFd[0] < 0); + Q_ASSERT(m_fifoFd[1] < 0); + + if (::pipe(m_fifoFd) == 0) { + int flags = ::fcntl(m_fifoFd[1], F_GETFD); + + if (::fcntl(m_fifoFd[1], F_SETFD, flags | O_NONBLOCK) >= 0) { + m_fifoNotifier = new QSocketNotifier(m_fifoFd[1], QSocketNotifier::Write); + + connect(m_fifoNotifier, SIGNAL(activated(int)), this, SLOT(fifoReadyWrite(int))); + + return true; + } else { + qWarning("Failed to make pipe non blocking %d", errno); + + ::close(m_fifoFd[0]); + ::close(m_fifoFd[1]); + + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + + return false; + } + } else { + qWarning("Failed to create pipe %d", errno); + + return false; + } +} + +void QGstreamerPlayerControl::closeFifo() +{ + if (m_fifoFd[0] >= 0) { + delete m_fifoNotifier; + m_fifoNotifier = 0; + + ::close(m_fifoFd[0]); + ::close(m_fifoFd[1]); + m_fifoFd[0] = -1; + m_fifoFd[1] = -1; + + m_fifoCanWrite = false; + + m_bufferSize = 0; + m_bufferOffset = 0; + } +} diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h new file mode 100644 index 0000000..ec0253b --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERPLAYERCONTROL_H +#define QGSTREAMERPLAYERCONTROL_H + +#include + +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlaylist; +class QGstreamerPlayerSession; +class QGstreamerPlayerService; +class QMediaPlaylistNavigator; +class QSocketNotifier; + +class QGstreamerPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT + +public: + QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent = 0); + ~QGstreamerPlayerControl(); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + void setVideoOutput(QObject *output); + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent&, QIODevice *); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +private Q_SLOTS: + void writeFifo(); + void fifoReadyWrite(int socket); + +private: + bool openFifo(); + void closeFifo(); + + QGstreamerPlayerSession *m_session; + QMediaContent m_currentResource; + QIODevice *m_stream; + QSocketNotifier *m_fifoNotifier; + int m_fifoFd[2]; + bool m_fifoCanWrite; + int m_bufferSize; + int m_bufferOffset; + char m_buffer[PIPE_BUF]; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp new file mode 100644 index 0000000..0c83147 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include + +#include "qgstreamerplayerservice.h" +#include "qgstreamerplayercontrol.h" +#include "qgstreamerplayersession.h" +#include "qgstreamermetadataprovider.h" +#include "qgstreamervideooutputcontrol.h" + +#include "qgstreamervideooverlay.h" +#include "qgstreamervideorenderer.h" + +#include "qgstreamervideowidget.h" +//#include "qgstreamerstreamscontrol.h" + +#include +#include + + +QT_BEGIN_NAMESPACE + + +QGstreamerPlayerService::QGstreamerPlayerService(QObject *parent): + QMediaService(parent) +{ + m_session = new QGstreamerPlayerSession(this); + m_control = new QGstreamerPlayerControl(m_session, this); + m_metaData = new QGstreamerMetaDataProvider(m_session, this); + m_videoOutput = new QGstreamerVideoOutputControl(this); +// m_streamsControl = new QGstreamerStreamsControl(m_session,this); + + connect(m_videoOutput, SIGNAL(outputChanged(QVideoOutputControl::Output)), + this, SLOT(videoOutputChanged(QVideoOutputControl::Output))); + m_videoRenderer = new QGstreamerVideoRenderer(this); + m_videoWindow = new QGstreamerVideoOverlay(this); + m_videoWidget = new QGstreamerVideoWidgetControl(this); + + m_videoOutput->setAvailableOutputs(QList() + << QVideoOutputControl::RendererOutput + << QVideoOutputControl::WindowOutput + << QVideoOutputControl::WidgetOutput); +} + +QGstreamerPlayerService::~QGstreamerPlayerService() +{ +} + +QMediaControl *QGstreamerPlayerService::control(const char *name) const +{ + if (qstrcmp(name,QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name,QMetaDataControl_iid) == 0) + return m_metaData; + +// if (qstrcmp(name,QMediaStreamsControl_iid) == 0) +// return m_streamsControl; + + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return m_videoOutput; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + return m_videoWidget; + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return m_videoRenderer; + + if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return m_videoWindow; + + return 0; +} + +void QGstreamerPlayerService::videoOutputChanged(QVideoOutputControl::Output output) +{ + switch (output) { + case QVideoOutputControl::NoOutput: + m_control->setVideoOutput(0); + break; + case QVideoOutputControl::RendererOutput: + m_control->setVideoOutput(m_videoRenderer); + break; + case QVideoOutputControl::WindowOutput: + m_control->setVideoOutput(m_videoWindow); + break; + case QVideoOutputControl::WidgetOutput: + m_control->setVideoOutput(m_videoWidget); + break; + default: + qWarning("Invalid video output selection"); + break; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h new file mode 100644 index 0000000..b27c2ae --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERPLAYERSERVICE_H +#define QGSTREAMERPLAYERSERVICE_H + +#include +#include + +#include + +#include "qgstreamervideooutputcontrol.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QGstreamerMetaData; +class QGstreamerPlayerControl; +class QGstreamerPlayerSession; +class QGstreamerMetaDataProvider; +class QGstreamerStreamsControl; +class QGstreamerVideoRenderer; +class QGstreamerVideoOverlay; +class QGstreamerVideoWidgetControl; + + +class QGstreamerPlayerService : public QMediaService +{ + Q_OBJECT +public: + QGstreamerPlayerService(QObject *parent = 0); + ~QGstreamerPlayerService(); + + //void setVideoOutput(QObject *output); + + QMediaControl *control(const char *name) const; + +private slots: + void videoOutputChanged(QVideoOutputControl::Output output); + +private: + QGstreamerPlayerControl *m_control; + QGstreamerPlayerSession *m_session; + QGstreamerMetaDataProvider *m_metaData; + QGstreamerVideoOutputControl *m_videoOutput; + QGstreamerStreamsControl *m_streamsControl; + + QGstreamerVideoRenderer *m_videoRenderer; + QGstreamerVideoOverlay *m_videoWindow; + QGstreamerVideoWidgetControl *m_videoWidget; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp new file mode 100644 index 0000000..baece67 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -0,0 +1,683 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamerplayersession.h" +#include "qgstreamerbushelper.h" + +#include "qgstreamervideorendererinterface.h" + +#include + +#include +#include + +//#define USE_PLAYBIN2 + +QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent) + :QObject(parent), + m_state(QMediaPlayer::StoppedState), + m_mediaStatus(QMediaPlayer::UnknownMediaStatus), + m_busHelper(0), + m_playbin(0), + m_nullVideoOutput(0), + m_bus(0), + m_renderer(0), + m_volume(100), + m_playbackRate(1.0), + m_muted(false), + m_videoAvailable(false), + m_seekable(false), + m_lastPosition(0), + m_duration(-1) +{ + static bool initialized = false; + if (!initialized) { + initialized = true; + gst_init(NULL, NULL); + } + +#ifdef USE_PLAYBIN2 + m_playbin = gst_element_factory_make("playbin2", NULL); +#else + m_playbin = gst_element_factory_make("playbin", NULL); +#endif + + if (m_playbin != 0) { + // Sort out messages + m_bus = gst_element_get_bus(m_playbin); + m_busHelper = new QGstreamerBusHelper(m_bus, this); + connect(m_busHelper, SIGNAL(message(QGstreamerMessage)), SLOT(busMessage(QGstreamerMessage))); + m_busHelper->installSyncEventFilter(this); + + m_nullVideoOutput = gst_element_factory_make("fakesink", NULL); + g_object_set(G_OBJECT(m_playbin), "video-sink", m_nullVideoOutput, NULL); + + // Initial volume + double volume = 1.0; + g_object_get(G_OBJECT(m_playbin), "volume", &volume, NULL); + m_volume = int(volume*100); + } +} + +QGstreamerPlayerSession::~QGstreamerPlayerSession() +{ + if (m_playbin) { + stop(); + + delete m_busHelper; + gst_object_unref(GST_OBJECT(m_bus)); + gst_object_unref(GST_OBJECT(m_playbin)); + } +} + +void QGstreamerPlayerSession::load(const QUrl &url) +{ + m_url = url; + if (m_playbin) { + m_tags.clear(); + emit tagsChanged(); + + g_object_set(G_OBJECT(m_playbin), "uri", m_url.toString().toLocal8Bit().constData(), NULL); + +// if (!m_streamTypes.isEmpty()) { +// m_streamProperties.clear(); +// m_streamTypes.clear(); +// +// emit streamsChanged(); +// } + } +} + +qint64 QGstreamerPlayerSession::duration() const +{ + return m_duration; +} + +qint64 QGstreamerPlayerSession::position() const +{ + GstFormat format = GST_FORMAT_TIME; + gint64 position = 0; + + if ( m_playbin && gst_element_query_position(m_playbin, &format, &position)) + return position / 1000000; + else + return 0; +} + +qreal QGstreamerPlayerSession::playbackRate() const +{ + return m_playbackRate; +} + +void QGstreamerPlayerSession::setPlaybackRate(qreal rate) +{ + if (!qFuzzyCompare(m_playbackRate, rate)) { + m_playbackRate = rate; + if (m_playbin) { + gst_element_seek(m_playbin, rate, GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT), + GST_SEEK_TYPE_NONE,0, + GST_SEEK_TYPE_NONE,0 ); + } + } +} + + +//int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType streamType) const +//{ +// int streamNumber = -1; +// if (m_playbin) { +// switch (streamType) { +// case QMediaStreamsControl::AudioStream: +// g_object_set(G_OBJECT(m_playbin), "current-audio", streamNumber, NULL); +// break; +// case QMediaStreamsControl::VideoStream: +// g_object_set(G_OBJECT(m_playbin), "current-video", streamNumber, NULL); +// break; +// case QMediaStreamsControl::SubPictureStream: +// g_object_set(G_OBJECT(m_playbin), "current-text", streamNumber, NULL); +// break; +// default: +// break; +// } +// } +// +//#ifdef USE_PLAYBIN2 +// streamNumber += m_playbin2StreamOffset.value(streamType,0); +//#endif +// +// return streamNumber; +//} + +//void QGstreamerPlayerSession::setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber) +//{ +//#ifdef USE_PLAYBIN2 +// streamNumber -= m_playbin2StreamOffset.value(streamType,0); +//#endif +// +// if (m_playbin) { +// switch (streamType) { +// case QMediaStreamsControl::AudioStream: +// g_object_get(G_OBJECT(m_playbin), "current-audio", &streamNumber, NULL); +// break; +// case QMediaStreamsControl::VideoStream: +// g_object_get(G_OBJECT(m_playbin), "current-video", &streamNumber, NULL); +// break; +// case QMediaStreamsControl::SubPictureStream: +// g_object_get(G_OBJECT(m_playbin), "current-text", &streamNumber, NULL); +// break; +// default: +// break; +// } +// } +//} + + +bool QGstreamerPlayerSession::isBuffering() const +{ + return false; +} + +int QGstreamerPlayerSession::bufferingProgress() const +{ + return 0; +} + +int QGstreamerPlayerSession::volume() const +{ + return m_volume; +} + +bool QGstreamerPlayerSession::isMuted() const +{ + return m_muted; +} + +void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) +{ + m_renderer = qobject_cast(videoOutput); + if (m_renderer) + g_object_set(G_OBJECT(m_playbin), "video-sink", m_renderer->videoSink(), NULL); + else + g_object_set(G_OBJECT(m_playbin), "video-sink", m_nullVideoOutput, NULL); +} + +bool QGstreamerPlayerSession::isVideoAvailable() const +{ + return m_videoAvailable; +} + +bool QGstreamerPlayerSession::isSeekable() const +{ + return m_seekable; +} + +void QGstreamerPlayerSession::play() +{ + if (m_playbin) { + if (gst_element_set_state(m_playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + qWarning() << "GStreamer; Unable to play -" << m_url.toString(); + m_state = QMediaPlayer::StoppedState; + m_mediaStatus = QMediaPlayer::InvalidMedia; + + emit stateChanged(m_state); + emit mediaStatusChanged(m_mediaStatus); + } + } +} + +void QGstreamerPlayerSession::pause() +{ + if (m_playbin) + gst_element_set_state(m_playbin, GST_STATE_PAUSED); +} + +void QGstreamerPlayerSession::stop() +{ + if (m_playbin) { + gst_element_set_state(m_playbin, GST_STATE_NULL); + + //we have to do it here, since gstreamer will not emit bus messages any more + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + } +} + +void QGstreamerPlayerSession::seek(qint64 ms) +{ + if (m_playbin && m_state != QMediaPlayer::StoppedState) { + gint64 position = (gint64)ms * 1000000; + gst_element_seek_simple(m_playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position); + } +} + +void QGstreamerPlayerSession::setVolume(int volume) +{ + m_volume = volume; + emit volumeChanged(m_volume); + + if (!m_muted && m_playbin) + g_object_set(G_OBJECT(m_playbin), "volume", m_volume/100.0, NULL); + +} + +void QGstreamerPlayerSession::setMuted(bool muted) +{ + m_muted = muted; + + g_object_set(G_OBJECT(m_playbin), "volume", (m_muted ? 0 : m_volume/100.0), NULL); + + emit mutedStateChanged(m_muted); +} + +static void addTagToMap(const GstTagList *list, + const gchar *tag, + gpointer user_data) +{ + QMap *map = reinterpret_cast* >(user_data); + + GValue val; + val.g_type = 0; + gst_tag_list_copy_value(&val,list,tag); + + switch( G_VALUE_TYPE(&val) ) { + case G_TYPE_STRING: + { + const gchar *str_value = g_value_get_string(&val); + map->insert(QByteArray(tag), QString::fromUtf8(str_value)); + break; + } + case G_TYPE_INT: + map->insert(QByteArray(tag), g_value_get_int(&val)); + break; + case G_TYPE_UINT: + map->insert(QByteArray(tag), g_value_get_uint(&val)); + break; + case G_TYPE_LONG: + map->insert(QByteArray(tag), qint64(g_value_get_long(&val))); + break; + case G_TYPE_BOOLEAN: + map->insert(QByteArray(tag), g_value_get_boolean(&val)); + break; + case G_TYPE_CHAR: + map->insert(QByteArray(tag), g_value_get_char(&val)); + break; + case G_TYPE_DOUBLE: + map->insert(QByteArray(tag), g_value_get_double(&val)); + break; + default: + // GST_TYPE_DATE is a function, not a constant, so pull it out of the switch + if (G_VALUE_TYPE(&val) == GST_TYPE_DATE) { + const GDate *date = gst_value_get_date(&val); + if (g_date_valid(date)) { + int year = g_date_get_year(date); + int month = g_date_get_month(date); + int day = g_date_get_day(date); + map->insert(QByteArray(tag), QDate(year,month,day)); + if (!map->contains("year")) + map->insert("year", year); + } + } else if (G_VALUE_TYPE(&val) == GST_TYPE_FRACTION) { + int nom = gst_value_get_fraction_numerator(&val); + int denom = gst_value_get_fraction_denominator(&val); + + if (denom > 0) { + map->insert(QByteArray(tag), double(nom)/denom); + } + } + break; + } + + g_value_unset(&val); +} + +void QGstreamerPlayerSession::setSeekable(bool seekable) +{ + if (seekable != m_seekable) { + m_seekable = seekable; + emit seekableChanged(m_seekable); + } +} + +void QGstreamerPlayerSession::setMediaStatus(QMediaPlayer::MediaStatus status) +{ + if (m_mediaStatus != status) { + m_mediaStatus = status; + emit mediaStatusChanged(status); + } +} + +bool QGstreamerPlayerSession::processSyncMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm && + GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT && + gst_structure_has_name(gm->structure, "prepare-xwindow-id")) + { + if (m_renderer) + m_renderer->precessNewStream(); + return true; + } + + return false; +} + +void QGstreamerPlayerSession::busMessage(const QGstreamerMessage &message) +{ + GstMessage* gm = message.rawMessage(); + + if (gm == 0) { + // Null message, query current position + quint32 newPos = position(); + + if (newPos/1000 != m_lastPosition) { + m_lastPosition = newPos/1000; + emit positionChanged(newPos); + } + + } else { + //tag message comes from elements inside playbin, not from playbin itself + if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_TAG) { + //qDebug() << "tag message"; + GstTagList *tag_list; + gst_message_parse_tag(gm, &tag_list); + gst_tag_list_foreach(tag_list, addTagToMap, &m_tags); + + //qDebug() << m_tags; + + emit tagsChanged(); + } + + if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_playbin)) { + switch (GST_MESSAGE_TYPE(gm)) { + case GST_MESSAGE_DURATION: + break; + + case GST_MESSAGE_STATE_CHANGED: + { + GstState oldState; + GstState newState; + GstState pending; + + gst_message_parse_state_changed(gm, &oldState, &newState, &pending); + + /*QStringList states; + states << "GST_STATE_VOID_PENDING" << "GST_STATE_NULL" << "GST_STATE_READY" << "GST_STATE_PAUSED" << "GST_STATE_PLAYING"; + + qDebug() << QString("state changed: old: %1 new: %2 pending: %3") \ + .arg(states[oldState]) \ + .arg(states[newState]) \ + .arg(states[pending]);*/ + + switch (newState) { + case GST_STATE_VOID_PENDING: + case GST_STATE_NULL: + setMediaStatus(QMediaPlayer::UnknownMediaStatus); + setSeekable(false); + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + break; + case GST_STATE_READY: + setMediaStatus(QMediaPlayer::LoadedMedia); + setSeekable(false); + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + break; + case GST_STATE_PAUSED: + //don't emit state changes for intermediate states + if (m_state != QMediaPlayer::PausedState && pending == GST_STATE_VOID_PENDING) + emit stateChanged(m_state = QMediaPlayer::PausedState); + + setMediaStatus(QMediaPlayer::LoadedMedia); + + //check for seekable + if (oldState == GST_STATE_READY) { + /* + //gst_element_seek_simple doesn't work reliably here, have to find a better solution + + GstFormat format = GST_FORMAT_TIME; + gint64 position = 0; + bool seekable = false; + if (gst_element_query_position(m_playbin, &format, &position)) { + seekable = gst_element_seek_simple(m_playbin, format, GST_SEEK_FLAG_NONE, position); + } + + setSeekable(seekable); + */ + + setSeekable(true); + + if (!qFuzzyCompare(m_playbackRate, qreal(1.0))) + setPlaybackRate(m_playbackRate); + + if (m_renderer) + m_renderer->precessNewStream(); + + } + + + break; + case GST_STATE_PLAYING: + if (oldState == GST_STATE_PAUSED) + getStreamsInfo(); + + if (m_state != QMediaPlayer::PlayingState) + emit stateChanged(m_state = QMediaPlayer::PlayingState); + break; + } + } + break; + + case GST_MESSAGE_EOS: + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + + setMediaStatus(QMediaPlayer::EndOfMedia); + + emit playbackFinished(); + break; + + case GST_MESSAGE_TAG: + case GST_MESSAGE_STREAM_STATUS: + case GST_MESSAGE_UNKNOWN: + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + case GST_MESSAGE_INFO: + break; + case GST_MESSAGE_BUFFERING: + setMediaStatus(QMediaPlayer::BufferingMedia); + break; + case GST_MESSAGE_STATE_DIRTY: + case GST_MESSAGE_STEP_DONE: + case GST_MESSAGE_CLOCK_PROVIDE: + case GST_MESSAGE_CLOCK_LOST: + case GST_MESSAGE_NEW_CLOCK: + case GST_MESSAGE_STRUCTURE_CHANGE: + case GST_MESSAGE_APPLICATION: + case GST_MESSAGE_ELEMENT: + case GST_MESSAGE_SEGMENT_START: + case GST_MESSAGE_SEGMENT_DONE: + case GST_MESSAGE_LATENCY: +#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 13) + case GST_MESSAGE_ASYNC_START: + case GST_MESSAGE_ASYNC_DONE: +#if GST_VERSION_MICRO >= 23 + case GST_MESSAGE_REQUEST_STATE: +#endif +#endif + case GST_MESSAGE_ANY: + break; + } + } + } +} + +void QGstreamerPlayerSession::getStreamsInfo() +{ + GstFormat format = GST_FORMAT_TIME; + gint64 duration = 0; + + if (gst_element_query_duration(m_playbin, &format, &duration)) { + int newDuration = duration / 1000000; + if (m_duration != newDuration) { + m_duration = newDuration; + emit durationChanged(m_duration); + } + } + + //check if video is available: + bool haveVideo = false; +// m_streamProperties.clear(); +// m_streamTypes.clear(); + +#ifdef USE_PLAYBIN2 + gint audioStreamsCount = 0; + gint videoStreamsCount = 0; + gint textStreamsCount = 0; + + g_object_get(G_OBJECT(m_playbin), "n-audio", &audioStreamsCount, NULL); + g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, NULL); + g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, NULL); + + m_playbin2StreamOffset[QMediaStreamsControl::AudioStream] = 0; + m_playbin2StreamOffset[QMediaStreamsControl::VideoStream] = audioStreamsCount; + m_playbin2StreamOffset[QMediaStreamsControl::SubPictureStream] = audioStreamsCount+videoStreamsCount; + + for (int i=0; i streamProperties; + + int streamIndex = i - m_playbin2StreamOffset[streamType]; + + GstTagList *tags = 0; + switch (streamType) { + case QMediaStreamsControl::AudioStream: + g_signal_emit_by_name(G_OBJECT(m_playbin), "get-audio-tags", streamIndex, &tags); + break; + case QMediaStreamsControl::VideoStream: + g_signal_emit_by_name(G_OBJECT(m_playbin), "get-video-tags", streamIndex, &tags); + break; + case QMediaStreamsControl::SubPictureStream: + g_signal_emit_by_name(G_OBJECT(m_playbin), "get-text-tags", streamIndex, &tags); + break; + default: + break; + } + + if (tags && gst_is_tag_list(tags)) { + gchar *languageCode = 0; + if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode)) + streamProperties[QtMedia::Language] = QString::fromUtf8(languageCode); + + //qDebug() << "language for setream" << i << QString::fromUtf8(languageCode); + g_free (languageCode); + } + + m_streamProperties.append(streamProperties); + } + +#else + enum { + GST_STREAM_TYPE_UNKNOWN, + GST_STREAM_TYPE_AUDIO, + GST_STREAM_TYPE_VIDEO, + GST_STREAM_TYPE_TEXT, + GST_STREAM_TYPE_SUBPICTURE, + GST_STREAM_TYPE_ELEMENT + }; + + GList* streamInfo; + g_object_get(G_OBJECT(m_playbin), "stream-info", &streamInfo, NULL); + + for (; streamInfo != 0; streamInfo = g_list_next(streamInfo)) { + gint type; + gchar *languageCode = 0; + + GObject* obj = G_OBJECT(streamInfo->data); + + g_object_get(obj, "type", &type, NULL); + g_object_get(obj, "language-code", &languageCode, NULL); + + if (type == GST_STREAM_TYPE_VIDEO) + haveVideo = true; + +// QMediaStreamsControl::StreamType streamType = QMediaStreamsControl::UnknownStream; +// +// switch (type) { +// case GST_STREAM_TYPE_VIDEO: +// streamType = QMediaStreamsControl::VideoStream; +// break; +// case GST_STREAM_TYPE_AUDIO: +// streamType = QMediaStreamsControl::AudioStream; +// break; +// case GST_STREAM_TYPE_SUBPICTURE: +// streamType = QMediaStreamsControl::SubPictureStream; +// break; +// default: +// streamType = QMediaStreamsControl::UnknownStream; +// break; +// } +// +// QMap streamProperties; +// streamProperties[QtMedia::Language] = QString::fromUtf8(languageCode); +// +// m_streamProperties.append(streamProperties); +// m_streamTypes.append(streamType); + } +#endif + + if (haveVideo != m_videoAvailable) { + m_videoAvailable = haveVideo; + emit videoAvailableChanged(m_videoAvailable); + } + + emit streamsChanged(); +} diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h new file mode 100644 index 0000000..a0f5f1a --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERPLAYERSESSION_H +#define QGSTREAMERPLAYERSESSION_H + +#include +#include +#include "qgstreamerplayercontrol.h" +#include "qgstreamerbushelper.h" +#include +//#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerBusHelper; +class QGstreamerMessage; +class QGstreamerVideoRendererInterface; + +class QGstreamerPlayerSession : public QObject, public QGstreamerSyncEventFilter +{ +Q_OBJECT + +public: + QGstreamerPlayerSession(QObject *parent); + virtual ~QGstreamerPlayerSession(); + + QUrl url() const; + + QMediaPlayer::State state() const { return m_state; } + QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; } + + qint64 duration() const; + qint64 position() const; + + bool isBuffering() const; + + int bufferingProgress() const; + + int volume() const; + bool isMuted() const; + + void setVideoRenderer(QObject *renderer); + bool isVideoAvailable() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QMap tags() const { return m_tags; } + QMap streamProperties(int streamNumber) const { return m_streamProperties[streamNumber]; } +// int streamCount() const { return m_streamProperties.count(); } +// QMediaStreamsControl::StreamType streamType(int streamNumber) { return m_streamTypes.value(streamNumber, QMediaStreamsControl::UnknownStream); } +// +// int activeStream(QMediaStreamsControl::StreamType streamType) const; +// void setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber); + + bool processSyncMessage(const QGstreamerMessage &message); + +public slots: + void load(const QUrl &url); + + void play(); + void pause(); + void stop(); + + void seek(qint64 pos); + + void setVolume(int volume); + void setMuted(bool muted); + +signals: + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State state); + void mediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus); + void volumeChanged(int volume); + void mutedStateChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void bufferingChanged(bool buffering); + void bufferingProgressChanged(int percentFilled); + void playbackFinished(); + void tagsChanged(); + void streamsChanged(); + void seekableChanged(bool); + +private slots: + void busMessage(const QGstreamerMessage &message); + void getStreamsInfo(); + void setSeekable(bool); + +private: + void setMediaStatus(QMediaPlayer::MediaStatus); + + QUrl m_url; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QGstreamerBusHelper* m_busHelper; + GstElement* m_playbin; + GstElement* m_nullVideoOutput; + GstBus* m_bus; + QGstreamerVideoRendererInterface *m_renderer; + + QMap m_tags; + QList< QMap > m_streamProperties; +// QList m_streamTypes; +// QMap m_playbin2StreamOffset; + + + int m_volume; + qreal m_playbackRate; + bool m_muted; + bool m_videoAvailable; + bool m_seekable; + + qint64 m_lastPosition; + qint64 m_duration; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERPLAYERSESSION_H diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp new file mode 100644 index 0000000..22c0b95 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamerstreamscontrol.h" +#include "qgstreamerplayersession.h" + +QGstreamerStreamsControl::QGstreamerStreamsControl(QGstreamerPlayerSession *session, QObject *parent) + :QMediaStreamsControl(parent), m_session(session) +{ + connect(m_session, SIGNAL(streamsChanged()), SIGNAL(streamsChanged())); +} + +QGstreamerStreamsControl::~QGstreamerStreamsControl() +{ +} + +int QGstreamerStreamsControl::streamCount() +{ + return m_session->streamCount(); +} + +QMediaStreamsControl::StreamType QGstreamerStreamsControl::streamType(int streamNumber) +{ + return m_session->streamType(streamNumber); +} + +QVariant QGstreamerStreamsControl::metaData(int streamNumber, QtMedia::MetaData key) +{ + return m_session->streamProperties(streamNumber).value(key); +} + +bool QGstreamerStreamsControl::isActive(int streamNumber) +{ + return streamNumber != -1 && streamNumber == m_session->activeStream(streamType(streamNumber)); +} + +void QGstreamerStreamsControl::setActive(int streamNumber, bool state) +{ + QMediaStreamsControl::StreamType type = m_session->streamType(streamNumber); + if (type == QMediaStreamsControl::UnknownStream) + return; + + if (state) + m_session->setActiveStream(type, streamNumber); + else { + //only one active stream of certain type is supported + if (m_session->activeStream(type) == streamNumber) + m_session->setActiveStream(type, -1); + } +} + diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.h new file mode 100644 index 0000000..c115bce --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerstreamscontrol.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERSTREAMSCONTROL_H +#define QGSTREAMERSTREAMSCONTROL_H + +#include + +QTM_USE_NAMESPACE + +class QGstreamerPlayerSession; + +class QGstreamerStreamsControl : public QMediaStreamsControl +{ + Q_OBJECT +public: + QGstreamerStreamsControl(QGstreamerPlayerSession *session, QObject *parent); + virtual ~QGstreamerStreamsControl(); + + virtual int streamCount(); + virtual StreamType streamType(int streamNumber); + + virtual QVariant metaData(int streamNumber, QtMedia::MetaData key); + + virtual bool isActive(int streamNumber); + virtual void setActive(int streamNumber, bool state); + +private: + QGstreamerPlayerSession *m_session; +}; + +#endif // QGSTREAMERSTREAMSCONTROL_H + diff --git a/src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.cpp b/src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.cpp new file mode 100644 index 0000000..ce6ab30 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreameraudioinputendpointselector.h" + +#include +#include +#include + +#include + +#ifdef HAVE_ALSA +#include +#endif + +QGstreamerAudioInputEndpointSelector::QGstreamerAudioInputEndpointSelector(QObject *parent) + :QAudioEndpointSelector(parent) +{ + update(); +} + +QGstreamerAudioInputEndpointSelector::~QGstreamerAudioInputEndpointSelector() +{ +} + +QList QGstreamerAudioInputEndpointSelector::availableEndpoints() const +{ + return m_names; +} + +QString QGstreamerAudioInputEndpointSelector::endpointDescription(const QString& name) const +{ + QString desc; + + for (int i = 0; i < m_names.size(); i++) { + if (m_names.at(i).compare(name) == 0) { + desc = m_descriptions.at(i); + break; + } + } + return desc; +} + +QString QGstreamerAudioInputEndpointSelector::defaultEndpoint() const +{ + if (m_names.size() > 0) + return m_names.at(0); + + return QString(); +} + +QString QGstreamerAudioInputEndpointSelector::activeEndpoint() const +{ + return m_audioInput; +} + +void QGstreamerAudioInputEndpointSelector::setActiveEndpoint(const QString& name) +{ + if (m_audioInput.compare(name) != 0) { + m_audioInput = name; + emit activeEndpointChanged(name); + } +} + +void QGstreamerAudioInputEndpointSelector::update() +{ + m_names.clear(); + m_descriptions.clear(); + updateAlsaDevices(); + updateOssDevices(); + updatePulseDevices(); + if (m_names.size() > 0) + m_audioInput = m_names.at(0); +} + +void QGstreamerAudioInputEndpointSelector::updateAlsaDevices() +{ +#ifdef HAVE_ALSA + void **hints, **n; + if (snd_device_name_hint(-1, "pcm", &hints) < 0) { + qWarning()<<"no alsa devices available"; + return; + } + n = hints; + + while (*n != NULL) { + char *name = snd_device_name_get_hint(*n, "NAME"); + char *descr = snd_device_name_get_hint(*n, "DESC"); + char *io = snd_device_name_get_hint(*n, "IOID"); + + if ((name != NULL) && (descr != NULL)) { + if ( io == NULL || qstrcmp(io,"Input") == 0 ) { + m_names.append(QLatin1String("alsa:")+QString::fromUtf8(name)); + m_descriptions.append(QString::fromUtf8(descr)); + } + } + + if (name != NULL) + free(name); + if (descr != NULL) + free(descr); + if (io != NULL) + free(io); + n++; + } + snd_device_name_free_hint(hints); +#endif +} + +void QGstreamerAudioInputEndpointSelector::updateOssDevices() +{ + QDir devDir("/dev"); + devDir.setFilter(QDir::System); +#ifndef QT_QWS_N810 + QFileInfoList entries = devDir.entryInfoList(QStringList() << "dsp*"); + foreach(const QFileInfo& entryInfo, entries) { + m_names.append(QLatin1String("oss:")+entryInfo.filePath()); + m_descriptions.append(QString("OSS device %1").arg(entryInfo.fileName())); + } +#else + m_names.append("dsppcm"); + m_descriptions.append("PCM audio input"); +#endif +} + +void QGstreamerAudioInputEndpointSelector::updatePulseDevices() +{ + GstElementFactory *factory = gst_element_factory_find("pulsesrc"); + if (factory) { + m_names.append("pulseaudio:"); + m_descriptions.append("PulseAudio device."); + gst_object_unref(GST_OBJECT(factory)); + } +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.h b/src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.h new file mode 100644 index 0000000..9b15939 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreameraudioinputendpointselector.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERAUDIOINPUTENDPOINTSELECTOR_H +#define QGSTREAMERAUDIOINPUTENDPOINTSELECTOR_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerAudioInputEndpointSelector : public QAudioEndpointSelector +{ +Q_OBJECT +public: + QGstreamerAudioInputEndpointSelector(QObject *parent); + ~QGstreamerAudioInputEndpointSelector(); + + QList availableEndpoints() const; + QString endpointDescription(const QString& name) const; + QString defaultEndpoint() const; + QString activeEndpoint() const; + +public Q_SLOTS: + void setActiveEndpoint(const QString& name); + +private: + void update(); + void updateAlsaDevices(); + void updateOssDevices(); + void updatePulseDevices(); + + QString m_audioInput; + QList m_names; + QList m_descriptions; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERAUDIOINPUTENDPOINTSELECTOR_H diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp new file mode 100644 index 0000000..0f09c6b --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include + +#include "qgstreamerbushelper.h" + + +#ifndef QT_NO_GLIB +class QGstreamerBusHelperPrivate : public QObject +{ + Q_OBJECT + +public: + void addWatch(GstBus* bus, QGstreamerBusHelper* helper) + { + setParent(helper); + m_tag = gst_bus_add_watch_full(bus, 0, busCallback, this, NULL); + m_helper = helper; + filter = 0; + } + + void removeWatch(QGstreamerBusHelper* helper) + { + Q_UNUSED(helper); + g_source_remove(m_tag); + } + + static QGstreamerBusHelperPrivate* instance() + { + return new QGstreamerBusHelperPrivate; + } + +private: + void processMessage(GstBus* bus, GstMessage* message) + { + Q_UNUSED(bus); + emit m_helper->message(message); + } + + static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data) + { + reinterpret_cast(data)->processMessage(bus, message); + return TRUE; + } + + guint m_tag; + QGstreamerBusHelper* m_helper; + +public: + GstBus* bus; + QGstreamerSyncEventFilter *filter; + QMutex filterMutex; +}; + +#else + +class QGstreamerBusHelperPrivate : public QObject +{ + Q_OBJECT + typedef QMap HelperMap; + +public: + void addWatch(GstBus* bus, QGstreamerBusHelper* helper) + { + m_helperMap.insert(helper, bus); + + if (m_helperMap.size() == 1) + m_intervalTimer->start(); + } + + void removeWatch(QGstreamerBusHelper* helper) + { + m_helperMap.remove(helper); + + if (m_helperMap.size() == 0) + m_intervalTimer->stop(); + } + + static QGstreamerBusHelperPrivate* instance() + { + static QGstreamerBusHelperPrivate self; + + return &self; + } + +private slots: + void interval() + { + for (HelperMap::iterator it = m_helperMap.begin(); it != m_helperMap.end(); ++it) { + GstMessage* message; + + while ((message = gst_bus_poll(it.value(), GST_MESSAGE_ANY, 0)) != 0) { + emit it.key()->message(message); + gst_message_unref(message); + } + + emit it.key()->message(QGstreamerMessage()); + } + } + +private: + QGstreamerBusHelperPrivate() + { + m_intervalTimer = new QTimer(this); + m_intervalTimer->setInterval(250); + + connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval())); + } + + HelperMap m_helperMap; + QTimer* m_intervalTimer; + +public: + GstBus* bus; + QGstreamerSyncEventFilter *filter; + QMutex filterMutex; +}; +#endif + + +static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstreamerBusHelperPrivate *d) +{ + Q_UNUSED(bus); + QMutexLocker lock(&d->filterMutex); + + bool res = false; + + if (d->filter) + res = d->filter->processSyncMessage(QGstreamerMessage(message)); + + return res ? GST_BUS_DROP : GST_BUS_PASS; +} + + +/*! + \class gstreamer::QGstreamerBusHelper + \internal +*/ + +QGstreamerBusHelper::QGstreamerBusHelper(GstBus* bus, QObject* parent): + QObject(parent), + d(QGstreamerBusHelperPrivate::instance()) +{ + d->bus = bus; + d->addWatch(bus, this); + + gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, d); +} + +QGstreamerBusHelper::~QGstreamerBusHelper() +{ + d->removeWatch(this); + gst_bus_set_sync_handler(d->bus,0,0); +} + +void QGstreamerBusHelper::installSyncEventFilter(QGstreamerSyncEventFilter *filter) +{ + QMutexLocker lock(&d->filterMutex); + d->filter = filter; +} + +#include "qgstreamerbushelper.moc" diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h new file mode 100644 index 0000000..471ca50 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERBUSHELPER_H +#define QGSTREAMERBUSHELPER_H + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerSyncEventFilter { +public: + //returns true if message was processed and should be dropped, false otherwise + virtual bool processSyncMessage(const QGstreamerMessage &message) = 0; +}; + +class QGstreamerBusHelperPrivate; + +class QGstreamerBusHelper : public QObject +{ + Q_OBJECT + friend class QGstreamerBusHelperPrivate; + +public: + QGstreamerBusHelper(GstBus* bus, QObject* parent = 0); + ~QGstreamerBusHelper(); + + void installSyncEventFilter(QGstreamerSyncEventFilter *filter); + +signals: + void message(QGstreamerMessage const& message); + + +private: + QGstreamerBusHelperPrivate* d; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp b/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp new file mode 100644 index 0000000..19cdfb1 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include "qgstreamermessage.h" + + +static int wuchi = qRegisterMetaType(); + + +/*! + \class gstreamer::QGstreamerMessage + \internal +*/ + +QGstreamerMessage::QGstreamerMessage(): + m_message(0) +{ +} + +QGstreamerMessage::QGstreamerMessage(GstMessage* message): + m_message(message) +{ + gst_message_ref(m_message); +} + +QGstreamerMessage::QGstreamerMessage(QGstreamerMessage const& m): + m_message(m.m_message) +{ + gst_message_ref(m_message); +} + + +QGstreamerMessage::~QGstreamerMessage() +{ + if (m_message != 0) + gst_message_unref(m_message); +} + +GstMessage* QGstreamerMessage::rawMessage() const +{ + return m_message; +} + +QGstreamerMessage& QGstreamerMessage::operator=(QGstreamerMessage const& rhs) +{ + if (m_message != 0) + gst_message_unref(m_message); + + if ((m_message = rhs.m_message) != 0) + gst_message_ref(m_message); + + return *this; +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreamermessage.h b/src/plugins/mediaservices/gstreamer/qgstreamermessage.h new file mode 100644 index 0000000..70f35f3 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamermessage.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERMESSAGE_H +#define QGSTREAMERMESSAGE_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerMessage +{ +public: + QGstreamerMessage(); + QGstreamerMessage(GstMessage* message); + QGstreamerMessage(QGstreamerMessage const& m); + ~QGstreamerMessage(); + + GstMessage* rawMessage() const; + + QGstreamerMessage& operator=(QGstreamerMessage const& rhs); + +private: + GstMessage* m_message; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QGstreamerMessage); + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp new file mode 100644 index 0000000..e892e45 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include +#include +#include +#include + +#include "qgstreamerserviceplugin.h" + +#ifdef QMEDIA_GSTREAMER_PLAYER +#include "qgstreamerplayerservice.h" +#endif +#ifdef QMEDIA_GSTREAMER_CAPTURE +#include "qgstreamercaptureservice.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + + +QStringList QGstreamerServicePlugin::keys() const +{ + return QStringList() +#ifdef QMEDIA_GSTREAMER_PLAYER + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) +#endif +#ifdef QMEDIA_GSTREAMER_CAPTURE + << QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE) + << QLatin1String(Q_MEDIASERVICE_CAMERA) +#endif + ; +} + +QMediaService* QGstreamerServicePlugin::create(const QString &key) +{ +#ifdef QMEDIA_GSTREAMER_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new QGstreamerPlayerService; +#endif +#ifdef QMEDIA_GSTREAMER_CAPTURE + if (key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) + return new QGstreamerCaptureService(key); + + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new QGstreamerCaptureService(key); +#endif + + qDebug() << "unsupported key:" << key; + return 0; +} + +void QGstreamerServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList QGstreamerServicePlugin::devices(const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } + + return QList(); +} + +QString QGstreamerServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + for (int i=0; i= 0; ++input.index) { + if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) { + isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0; + break; + } + } + + if (isCamera) { + // find out its driver "name" + QString name; + struct v4l2_capability vcap; + memset(&vcap, 0, sizeof(struct v4l2_capability)); + + if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0) + name = entryInfo.fileName(); + else + name = QString((const char*)vcap.card); + qDebug() << "found camera: " << name; + + m_cameraDevices.append(entryInfo.filePath().toLocal8Bit()); + m_cameraDescriptions.append(name); + } + ::close(fd); + } +} + +Q_EXPORT_PLUGIN2(gstengine, QGstreamerServicePlugin); + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h new file mode 100644 index 0000000..33148ac --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERSERVICEPLUGIN_H +#define QGSTREAMERSERVICEPLUGIN_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: + void updateDevices() const; + + mutable QList m_cameraDevices; + mutable QStringList m_cameraDescriptions; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERSERVICEPLUGIN_H diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp new file mode 100644 index 0000000..5059409 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamervideoinputdevicecontrol.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent) + :QVideoDeviceControl(parent), m_selectedDevice(0) +{ + update(); +} + +QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl() +{ +} + +int QGstreamerVideoInputDeviceControl::deviceCount() const +{ + return m_names.size(); +} + +QString QGstreamerVideoInputDeviceControl::deviceName(int index) const +{ + return m_names[index]; +} + +QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const +{ + return m_descriptions[index]; +} + +QIcon QGstreamerVideoInputDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index); + return QIcon(); +} + +int QGstreamerVideoInputDeviceControl::defaultDevice() const +{ + return 0; +} + +int QGstreamerVideoInputDeviceControl::selectedDevice() const +{ + return m_selectedDevice; +} + + +void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index) +{ + if (index != m_selectedDevice) { + m_selectedDevice = index; + emit selectedDeviceChanged(index); + emit selectedDeviceChanged(deviceName(index)); + } +} + + +void QGstreamerVideoInputDeviceControl::update() +{ + m_names.clear(); + m_descriptions.clear(); + + QDir devDir("/dev"); + devDir.setFilter(QDir::System); + + QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*"); + + foreach( const QFileInfo &entryInfo, entries ) { + qDebug() << "Try" << entryInfo.filePath(); + + int fd = ::open(entryInfo.filePath().toLatin1().constData(), O_RDWR ); + if (fd == -1) + continue; + + bool isCamera = false; + + v4l2_input input; + memset(&input, 0, sizeof(input)); + for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) { + if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) { + isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0; + break; + } + } + + if (isCamera) { + // find out its driver "name" + QString name; + struct v4l2_capability vcap; + memset(&vcap, 0, sizeof(struct v4l2_capability)); + + if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0) + name = entryInfo.fileName(); + else + name = QString((const char*)vcap.card); + qDebug() << "found camera: " << name; + + m_names.append(entryInfo.filePath()); + m_descriptions.append(name); + } + ::close(fd); + } +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h new file mode 100644 index 0000000..5cdc05f --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERVIDEOINPUTDEVICECONTROL_H +#define QGSTREAMERVIDEOINPUTDEVICECONTROL_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QGstreamerVideoInputDeviceControl : public QVideoDeviceControl +{ +Q_OBJECT +public: + QGstreamerVideoInputDeviceControl(QObject *parent); + ~QGstreamerVideoInputDeviceControl(); + + int deviceCount() const; + + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + + int defaultDevice() const; + int selectedDevice() const; + +public Q_SLOTS: + void setSelectedDevice(int index); + +private: + void update(); + + int m_selectedDevice; + QStringList m_names; + QStringList m_descriptions; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERAUDIOINPUTDEVICECONTROL_H diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp new file mode 100644 index 0000000..10d446f --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamervideooutputcontrol.h" + +QGstreamerVideoOutputControl::QGstreamerVideoOutputControl(QObject *parent) + : QVideoOutputControl(parent) + , m_output(NoOutput) +{ +} + +QList QGstreamerVideoOutputControl::availableOutputs() const +{ + return m_outputs; +} + +void QGstreamerVideoOutputControl::setAvailableOutputs(const QList &outputs) +{ + emit availableOutputsChanged(m_outputs = outputs); +} + +QVideoOutputControl::Output QGstreamerVideoOutputControl::output() const +{ + return m_output; +} + +void QGstreamerVideoOutputControl::setOutput(Output output) +{ + if (!m_outputs.contains(output)) + output = NoOutput; + + if (m_output != output) + emit outputChanged(m_output = output); +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h new file mode 100644 index 0000000..0d618f2 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERVIDEOOUTPUTCONTROL_H +#define QGSTREAMERVIDEOOUTPUTCONTROL_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerVideoRendererInterface +{ +public: + virtual ~QGstreamerVideoRendererInterface(); + virtual GstElement *videoSink() = 0; + virtual void precessNewStream() {} +}; + +class QGstreamerVideoOutputControl : public QVideoOutputControl +{ + Q_OBJECT +public: + QGstreamerVideoOutputControl(QObject *parent = 0); + + QList availableOutputs() const; + void setAvailableOutputs(const QList &outputs); + + Output output() const; + void setOutput(Output output); + +Q_SIGNALS: + void outputChanged(QVideoOutputControl::Output output); + +private: + QList m_outputs; + Output m_output; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp new file mode 100644 index 0000000..8dbe3db --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamervideooverlay.h" +#include "qvideosurfacegstsink.h" + +#include + +#include "qx11videosurface.h" + +QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent) + : QVideoWindowControl(parent) + , m_surface(new QX11VideoSurface) + , m_videoSink(reinterpret_cast(QVideoSurfaceGstSink::createSink(m_surface))) + , m_aspectRatioMode(QVideoWidget::KeepAspectRatio) + , m_fullScreen(false) +{ + if (m_videoSink) { + gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership + gst_object_sink(GST_OBJECT(m_videoSink)); + } + + connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(surfaceFormatChanged())); +} + +QGstreamerVideoOverlay::~QGstreamerVideoOverlay() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + delete m_surface; +} + +WId QGstreamerVideoOverlay::winId() const +{ + return m_surface->winId(); +} + +void QGstreamerVideoOverlay::setWinId(WId id) +{ + m_surface->setWinId(id); +} + +QRect QGstreamerVideoOverlay::displayRect() const +{ + return m_displayRect; +} + +void QGstreamerVideoOverlay::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; + + setScaledDisplayRect(); +} + +QVideoWidget::AspectRatioMode QGstreamerVideoOverlay::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QGstreamerVideoOverlay::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + m_aspectRatioMode = mode; + + setScaledDisplayRect(); +} + +void QGstreamerVideoOverlay::repaint() +{ +} + +int QGstreamerVideoOverlay::brightness() const +{ + return m_surface->brightness(); +} + +void QGstreamerVideoOverlay::setBrightness(int brightness) +{ + m_surface->setBrightness(brightness); + + emit brightnessChanged(m_surface->brightness()); +} + +int QGstreamerVideoOverlay::contrast() const +{ + return m_surface->contrast(); +} + +void QGstreamerVideoOverlay::setContrast(int contrast) +{ + m_surface->setContrast(contrast); + + emit contrastChanged(m_surface->contrast()); +} + +int QGstreamerVideoOverlay::hue() const +{ + return m_surface->hue(); +} + +void QGstreamerVideoOverlay::setHue(int hue) +{ + m_surface->setHue(hue); + + emit hueChanged(m_surface->hue()); +} + +int QGstreamerVideoOverlay::saturation() const +{ + return m_surface->saturation(); +} + +void QGstreamerVideoOverlay::setSaturation(int saturation) +{ + m_surface->setSaturation(saturation); + + emit saturationChanged(m_surface->saturation()); +} + +bool QGstreamerVideoOverlay::isFullScreen() const +{ + return m_fullScreen; +} + +void QGstreamerVideoOverlay::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +QSize QGstreamerVideoOverlay::nativeSize() const +{ + return m_surface->surfaceFormat().sizeHint(); +} + +QAbstractVideoSurface *QGstreamerVideoOverlay::surface() const +{ + return m_surface; +} + +GstElement *QGstreamerVideoOverlay::videoSink() +{ + return m_videoSink; +} + +void QGstreamerVideoOverlay::surfaceFormatChanged() +{ + setScaledDisplayRect(); + + emit nativeSizeChanged(); +} + +void QGstreamerVideoOverlay::setScaledDisplayRect() +{ + switch (m_aspectRatioMode) { + case QVideoWidget::KeepAspectRatio: + { + QSize size = m_surface->surfaceFormat().viewport().size(); + + size.scale(m_displayRect.size(), Qt::KeepAspectRatio); + + QRect rect(QPoint(0, 0), size); + rect.moveCenter(m_displayRect.center()); + + m_surface->setDisplayRect(rect); + } + break; + case QVideoWidget::IgnoreAspectRatio: + m_surface->setDisplayRect(m_displayRect); + break; + }; +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h new file mode 100644 index 0000000..518d8ce --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERVIDEOOVERLAY_H +#define QGSTREAMERVIDEOOVERLAY_H + +#include + +#include "qgstreamervideorendererinterface.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; +class QX11VideoSurface; + +class QGstreamerVideoOverlay : public QVideoWindowControl, public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) +public: + QGstreamerVideoOverlay(QObject *parent = 0); + ~QGstreamerVideoOverlay(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + QSize nativeSize() const; + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + void repaint(); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QAbstractVideoSurface *surface() const; + + GstElement *videoSink(); + +private slots: + void surfaceFormatChanged(); + +private: + void setScaledDisplayRect(); + + QX11VideoSurface *m_surface; + GstElement *m_videoSink; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + QRect m_displayRect; + bool m_fullScreen; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp new file mode 100644 index 0000000..7e10fbf --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamervideorenderer.h" +#include "qvideosurfacegstsink.h" + +#include +#include + +#include + +QGstreamerVideoRenderer::QGstreamerVideoRenderer(QObject *parent) + :QVideoRendererControl(parent),m_videoSink(0) +{ +} + +QGstreamerVideoRenderer::~QGstreamerVideoRenderer() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); +} + +GstElement *QGstreamerVideoRenderer::videoSink() +{ + if (!m_videoSink) { + m_videoSink = reinterpret_cast(QVideoSurfaceGstSink::createSink(m_surface)); + gst_object_ref(GST_OBJECT(m_videoSink)); //Take ownership + gst_object_sink(GST_OBJECT(m_videoSink)); + } + + return m_videoSink; +} + + +QAbstractVideoSurface *QGstreamerVideoRenderer::surface() const +{ + return m_surface; +} + +void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface) +{ + m_surface = surface; +} + diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h new file mode 100644 index 0000000..f476730 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERVIDEORENDERER_H +#define QGSTREAMERVIDEORENDERER_H + +#include +#include "qvideosurfacegstsink.h" + +#include "qgstreamervideorendererinterface.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerVideoRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) +public: + QGstreamerVideoRenderer(QObject *parent = 0); + virtual ~QGstreamerVideoRenderer(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + GstElement *videoSink(); + void precessNewStream() {} + +private: + GstElement *m_videoSink; + QAbstractVideoSurface *m_surface; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERVIDEORENDRER_H diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp new file mode 100644 index 0000000..57df692 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamervideorendererinterface.h" + +QGstreamerVideoRendererInterface::~QGstreamerVideoRendererInterface() +{ +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h new file mode 100644 index 0000000..2700965 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERVIDEOOUTPUTCONTROL_H +#define QGSTREAMERVIDEOOUTPUTCONTROL_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerVideoRendererInterface +{ +public: + virtual ~QGstreamerVideoRendererInterface(); + virtual GstElement *videoSink() = 0; + virtual void precessNewStream() {} +}; + +QT_END_NAMESPACE + +#define QGstreamerVideoRendererInterface_iid "com.nokia.Qt.QGstreamerVideoRendererInterface/1.0" +Q_DECLARE_INTERFACE(QGstreamerVideoRendererInterface, QGstreamerVideoRendererInterface_iid) + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp new file mode 100644 index 0000000..7b2ec14 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstreamervideowidget.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +class QGstreamerVideoWidget : public QWidget +{ +public: + QGstreamerVideoWidget(QWidget *parent = 0) + :QWidget(parent) + { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QPalette palette; + palette.setColor(QPalette::Background, Qt::black); + setPalette(palette); + } + + virtual ~QGstreamerVideoWidget() {} + + QSize sizeHint() const + { + return m_nativeSize; + } + + void setNativeSize( const QSize &size) + { + if (size != m_nativeSize) { + m_nativeSize = size; + if (size.isEmpty()) + setMinimumSize(0,0); + else + setMinimumSize(160,120); + + updateGeometry(); + } + } + +protected: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.fillRect(rect(), palette().background()); + } + + QSize m_nativeSize; +}; + +QGstreamerVideoWidgetControl::QGstreamerVideoWidgetControl(QObject *parent) + : QVideoWidgetControl(parent) + , m_videoSink(0) + , m_widget(new QGstreamerVideoWidget) + , m_fullScreen(false) +{ + m_widget->installEventFilter(this); + m_windowId = m_widget->winId(); + + m_videoSink = gst_element_factory_make ("xvimagesink", NULL); + if (m_videoSink) { + // Check if the xv sink is usable + if (gst_element_set_state(m_videoSink, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) { + gst_object_unref(GST_OBJECT(m_videoSink)); + m_videoSink = 0; + } else { + gst_element_set_state(m_videoSink, GST_STATE_NULL); + + g_object_set(G_OBJECT(m_videoSink), "force-aspect-ratio", 1, (const char*)NULL); + } + } + + if (!m_videoSink) + m_videoSink = gst_element_factory_make ("ximagesink", NULL); + + gst_object_ref (GST_OBJECT (m_videoSink)); //Take ownership + gst_object_sink (GST_OBJECT (m_videoSink)); +} + +QGstreamerVideoWidgetControl::~QGstreamerVideoWidgetControl() +{ + if (m_videoSink) + gst_object_unref(GST_OBJECT(m_videoSink)); + + delete m_widget; +} + +GstElement *QGstreamerVideoWidgetControl::videoSink() +{ + return m_videoSink; +} + +bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e) +{ + if (object == m_widget) { + if (e->type() == QEvent::ParentChange || e->type() == QEvent::Show) { + WId newWId = m_widget->winId(); + if (newWId != m_windowId) { + m_windowId = newWId; + // Even if we have created a winId at this point, other X applications + // need to be aware of it. + QApplication::syncX(); + setOverlay(); + } + } + + if (e->type() == QEvent::Show) { + // Setting these values ensures smooth resizing since it + // will prevent the system from clearing the background + m_widget->setAttribute(Qt::WA_NoSystemBackground, true); + m_widget->setAttribute(Qt::WA_PaintOnScreen, true); + } else if (e->type() == QEvent::Resize) { + // This is a workaround for missing background repaints + // when reducing window size + windowExposed(); + } + } + + return false; +} + +void QGstreamerVideoWidgetControl::precessNewStream() +{ + setOverlay(); + QMetaObject::invokeMethod(this, "updateNativeVideoSize", Qt::QueuedConnection); +} + +void QGstreamerVideoWidgetControl::setOverlay() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), m_windowId); + } +} + +void QGstreamerVideoWidgetControl::updateNativeVideoSize() +{ + if (m_videoSink) { + //find video native size to update video widget size hint + GstPad *pad = gst_element_get_static_pad(m_videoSink,"sink"); + GstCaps *caps = gst_pad_get_negotiated_caps(pad); + + if (caps) { + GstStructure *str; + gint width, height; + + if ((str = gst_caps_get_structure (caps, 0))) { + if (gst_structure_get_int (str, "width", &width) && gst_structure_get_int (str, "height", &height)) { + gint aspectNum = 0; + gint aspectDenum = 0; + if (gst_structure_get_fraction(str, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { + if (aspectDenum > 0) + width = width*aspectNum/aspectDenum; + } + m_widget->setNativeSize(QSize(width, height)); + } + } + gst_caps_unref(caps); + } + } else { + m_widget->setNativeSize(QSize()); + } +} + + +void QGstreamerVideoWidgetControl::windowExposed() +{ + if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) + gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink)); +} + +QWidget *QGstreamerVideoWidgetControl::videoWidget() +{ + return m_widget; +} + +QVideoWidget::AspectRatioMode QGstreamerVideoWidgetControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void QGstreamerVideoWidgetControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + if (m_videoSink) { + g_object_set(G_OBJECT(m_videoSink), + "force-aspect-ratio", + (mode == QVideoWidget::KeepAspectRatio), + (const char*)NULL); + } + + m_aspectRatioMode = mode; +} + +bool QGstreamerVideoWidgetControl::isFullScreen() const +{ + return m_fullScreen; +} + +void QGstreamerVideoWidgetControl::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +int QGstreamerVideoWidgetControl::brightness() const +{ + int brightness = 0; + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) + g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, NULL); + + return brightness / 10; +} + +void QGstreamerVideoWidgetControl::setBrightness(int brightness) +{ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness")) { + g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, NULL); + + emit brightnessChanged(brightness); + } +} + +int QGstreamerVideoWidgetControl::contrast() const +{ + int contrast = 0; + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) + g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, NULL); + + return contrast / 10; +} + +void QGstreamerVideoWidgetControl::setContrast(int contrast) +{ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast")) { + g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, NULL); + + emit contrastChanged(contrast); + } +} + +int QGstreamerVideoWidgetControl::hue() const +{ + int hue = 0; + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) + g_object_get(G_OBJECT(m_videoSink), "hue", &hue, NULL); + + return hue / 10; +} + +void QGstreamerVideoWidgetControl::setHue(int hue) +{ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue")) { + g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, NULL); + + emit hueChanged(hue); + } +} + +int QGstreamerVideoWidgetControl::saturation() const +{ + int saturation = 0; + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) + g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, NULL); + + return saturation / 10; +} + +void QGstreamerVideoWidgetControl::setSaturation(int saturation) +{ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation")) { + g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, NULL); + + emit saturationChanged(saturation); + } +} diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h new file mode 100644 index 0000000..9edd1dd --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTREAMERVIDEOWIDGET_H +#define QGSTREAMERVIDEOWIDGET_H + +#include + +#include "qgstreamervideorendererinterface.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstreamerVideoWidget; + +class QGstreamerVideoWidgetControl + : public QVideoWidgetControl + , public QGstreamerVideoRendererInterface +{ + Q_OBJECT + Q_INTERFACES(QGstreamerVideoRendererInterface) +public: + QGstreamerVideoWidgetControl(QObject *parent = 0); + virtual ~QGstreamerVideoWidgetControl(); + + GstElement *videoSink(); + void precessNewStream(); + + QWidget *videoWidget(); + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + void setOverlay(); + + bool eventFilter(QObject *object, QEvent *event); + +public slots: + void updateNativeVideoSize(); + +private: + void windowExposed(); + + GstElement *m_videoSink; + QGstreamerVideoWidget *m_widget; + WId m_windowId; + QVideoWidget::AspectRatioMode m_aspectRatioMode; + bool m_fullScreen; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGSTREAMERVIDEOWIDGET_H diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp new file mode 100644 index 0000000..80943b5 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qgstvideobuffer.h" + + +QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_bytesPerLine(bytesPerLine) + , m_mode(NotMapped) +{ + gst_buffer_ref(m_buffer); +} + +QGstVideoBuffer::~QGstVideoBuffer() +{ + gst_buffer_unref(m_buffer); +} + + +QAbstractVideoBuffer::MapMode QGstVideoBuffer::mapMode() const +{ + return m_mode; +} + +uchar *QGstVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (mode != NotMapped && m_mode == NotMapped) { + if (numBytes) + *numBytes = m_buffer->size; + + if (bytesPerLine) + *bytesPerLine = m_bytesPerLine; + + m_mode = mode; + + return m_buffer->data; + } else { + return 0; + } +} +void QGstVideoBuffer::unmap() +{ + m_mode = NotMapped; +} + diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h new file mode 100644 index 0000000..487832c --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QGSTVIDEOBUFFER_H +#define QGSTVIDEOBUFFER_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGstVideoBuffer : public QAbstractVideoBuffer +{ +public: + QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine); + ~QGstVideoBuffer(); + + MapMode mapMode() const; + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + +private: + GstBuffer *m_buffer; + int m_bytesPerLine; + MapMode m_mode; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp new file mode 100644 index 0000000..7c5805c --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp @@ -0,0 +1,553 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qvideosurfacegstsink.h" + +#include "qgstvideobuffer.h" + +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QVideoSurfaceFormat) + +QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface) + : m_surface(surface) + , m_renderReturn(GST_FLOW_ERROR) + , m_bytesPerLine(0) +{ + m_supportedPixelFormats = m_surface->supportedPixelFormats(); + + connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged())); +} + +QList QVideoSurfaceGstDelegate::supportedPixelFormats() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + return m_supportedPixelFormats; +} + +bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int bytesPerLine) +{ + QMutexLocker locker(&m_mutex); + + m_format = format; + m_bytesPerLine = bytesPerLine; + + if (QThread::currentThread() == thread()) { + m_started = !m_surface.isNull() ? m_surface->start(m_format) : false; + } else { + QMetaObject::invokeMethod(this, "queuedStart", Qt::QueuedConnection); + + m_setupCondition.wait(&m_mutex); + } + + return m_started; +} + +void QVideoSurfaceGstDelegate::stop() +{ + QMutexLocker locker(&m_mutex); + + if (QThread::currentThread() == thread()) { + if (!m_surface.isNull()) + m_surface->stop(); + } else { + QMetaObject::invokeMethod(this, "queuedStop", Qt::QueuedConnection); + + m_setupCondition.wait(&m_mutex); + } + + m_started = false; +} + +GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) +{ + QMutexLocker locker(&m_mutex); + + m_frame = QVideoFrame( + new QGstVideoBuffer(buffer, m_bytesPerLine), + m_format.frameSize(), + m_format.pixelFormat()); + + qint64 startTime = GST_BUFFER_TIMESTAMP(buffer); + + if (startTime >= 0) { + m_frame.setStartTime(startTime/G_GINT64_CONSTANT (1000000)); + + qint64 duration = GST_BUFFER_DURATION(buffer); + + if (duration >= 0) + m_frame.setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000000)); + } + + QMetaObject::invokeMethod(this, "queuedRender", Qt::QueuedConnection); + + if (!m_renderCondition.wait(&m_mutex, 300)) { + m_frame = QVideoFrame(); + + return GST_FLOW_OK; + } else { + return m_renderReturn; + } +} + + +void QVideoSurfaceGstDelegate::queuedStart() +{ + QMutexLocker locker(&m_mutex); + + m_started = m_surface->start(m_format); + + m_setupCondition.wakeAll(); +} + +void QVideoSurfaceGstDelegate::queuedStop() +{ + QMutexLocker locker(&m_mutex); + + m_surface->stop(); + + m_setupCondition.wakeAll(); +} + +void QVideoSurfaceGstDelegate::queuedRender() +{ + QMutexLocker locker(&m_mutex); + + if (m_surface.isNull()) { + m_renderReturn = GST_FLOW_ERROR; + } else if (m_surface->present(m_frame)) { + m_renderReturn = GST_FLOW_OK; + } else { + switch (m_surface->error()) { + case QAbstractVideoSurface::NoError: + m_renderReturn = GST_FLOW_OK; + break; + case QAbstractVideoSurface::StoppedError: + m_renderReturn = GST_FLOW_NOT_NEGOTIATED; + break; + default: + m_renderReturn = GST_FLOW_ERROR; + break; + } + } + + m_renderCondition.wakeAll(); +} + +void QVideoSurfaceGstDelegate::supportedFormatsChanged() +{ + QMutexLocker locker(&m_mutex); + + m_supportedPixelFormats = m_surface->supportedPixelFormats(); +} + +struct YuvFormat +{ + QVideoFrame::PixelFormat pixelFormat; + guint32 fourcc; + int bitsPerPixel; +}; + +static const YuvFormat qt_yuvColorLookup[] = +{ + { QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 }, + { QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 }, + { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 8 }, + { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','V'), 8 }, + { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 8 }, + { QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 }, + { QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 } +}; + +static int indexOfYuvColor(QVideoFrame::PixelFormat format) +{ + const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat); + + for (int i = 0; i < count; ++i) + if (qt_yuvColorLookup[i].pixelFormat == format) + return i; + return -1; +} + +static int indexOfYuvColor(guint32 fourcc) +{ + const int count = sizeof(YuvFormat) / sizeof(YuvFormat); + + for (int i = 0; i < count; ++i) + if (qt_yuvColorLookup[i].fourcc == fourcc) + return i; + return -1; +} + +struct RgbFormat +{ + QVideoFrame::PixelFormat pixelFormat; + int bitsPerPixel; + int depth; + int endianness; + int red; + int green; + int blue; + int alpha; +}; + +static const RgbFormat qt_rgbColorLookup[] = +{ + { QVideoFrame::Format_RGB32 , 32, 24, 4321, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000 }, + { QVideoFrame::Format_RGB32 , 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, + { QVideoFrame::Format_ARGB32, 32, 24, 4321, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF }, + { QVideoFrame::Format_ARGB32, 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 }, + { QVideoFrame::Format_RGB24 , 24, 24, 4321, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, + { QVideoFrame::Format_RGB565, 16, 16, 1234, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 } +}; + +static int indexOfRgbColor( + int bits, int depth, int endianness, int red, int green, int blue, int alpha) +{ + const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat); + + for (int i = 0; i < count; ++i) { + if (qt_rgbColorLookup[i].bitsPerPixel == bits + && qt_rgbColorLookup[i].depth == depth + && qt_rgbColorLookup[i].endianness == endianness + && qt_rgbColorLookup[i].red == red + && qt_rgbColorLookup[i].green == green + && qt_rgbColorLookup[i].blue == blue + && qt_rgbColorLookup[i].alpha == alpha) { + return i; + } + } + return -1; +} + +static GstVideoSinkClass *sink_parent_class; + +#define VO_SINK(s) QVideoSurfaceGstSink *sink(reinterpret_cast(s)) + +QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *surface) +{ + QVideoSurfaceGstSink *sink = reinterpret_cast( + g_object_new(QVideoSurfaceGstSink::get_type(), 0)); + + sink->delegate = new QVideoSurfaceGstDelegate(surface); + + return sink; +} + +GType QVideoSurfaceGstSink::get_type() +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = + { + sizeof(QVideoSurfaceGstSinkClass), // class_size + base_init, // base_init + NULL, // base_finalize + class_init, // class_init + NULL, // class_finalize + NULL, // class_data + sizeof(QVideoSurfaceGstSink), // instance_size + 0, // n_preallocs + instance_init, // instance_init + 0 // value_table + }; + + type = g_type_register_static( + GST_TYPE_VIDEO_SINK, "QVideoSurfaceGstSink", &info, GTypeFlags(0)); + } + + return type; +} + +void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data) +{ + Q_UNUSED(class_data); + + sink_parent_class = reinterpret_cast(g_type_class_peek_parent(g_class)); + + GstBaseSinkClass *base_sink_class = reinterpret_cast(g_class); + base_sink_class->get_caps = QVideoSurfaceGstSink::get_caps; + base_sink_class->set_caps = QVideoSurfaceGstSink::set_caps; + // base_sink_class->buffer_alloc = QVideoSurfaceGstSink::buffer_alloc; // Not implemented. + base_sink_class->start = QVideoSurfaceGstSink::start; + base_sink_class->stop = QVideoSurfaceGstSink::stop; + // base_sink_class->unlock = QVideoSurfaceGstSink::unlock; // Not implemented. + // base_sink_class->event = QVideoSurfaceGstSink::event; // Not implemented. + base_sink_class->preroll = QVideoSurfaceGstSink::preroll; + base_sink_class->render = QVideoSurfaceGstSink::render; + + GstElementClass *element_class = reinterpret_cast(g_class); + element_class->change_state = QVideoSurfaceGstSink::change_state; + + GObjectClass *object_class = reinterpret_cast(g_class); + object_class->finalize = QVideoSurfaceGstSink::finalize; +} + +void QVideoSurfaceGstSink::base_init(gpointer g_class) +{ + static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE( + "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS( + "video/x-raw-rgb, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ]; " + "video/x-raw-yuv, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " + "height = (int) [ 1, MAX ]")); + + gst_element_class_add_pad_template( + GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template)); +} + +void QVideoSurfaceGstSink::instance_init(GTypeInstance *instance, gpointer g_class) +{ + VO_SINK(instance); + + Q_UNUSED(g_class); + + sink->delegate = 0; +} + +void QVideoSurfaceGstSink::finalize(GObject *object) +{ + Q_UNUSED(object); +} + +GstStateChangeReturn QVideoSurfaceGstSink::change_state( + GstElement *element, GstStateChange transition) +{ + Q_UNUSED(element); + + return GST_ELEMENT_CLASS(sink_parent_class)->change_state( + element, transition); +} + +GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base) +{ + VO_SINK(base); + + GstCaps *caps = gst_caps_new_empty(); + + foreach (QVideoFrame::PixelFormat format, sink->delegate->supportedPixelFormats()) { + int index = indexOfYuvColor(format); + + if (index != -1) { + gst_caps_append_structure(caps, gst_structure_new( + "video/x-raw-yuv", + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1, + "width" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "height" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "format" , GST_TYPE_FOURCC, qt_yuvColorLookup[index].fourcc, + NULL)); + continue; + } + + const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat); + + for (int i = 0; i < count; ++i) { + if (qt_rgbColorLookup[i].pixelFormat == format) { + GstStructure *structure = gst_structure_new( + "video/x-raw-rgb", + "framerate" , GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1, + "width" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "height" , GST_TYPE_INT_RANGE, 1, INT_MAX, + "bpp" , G_TYPE_INT, qt_rgbColorLookup[i].bitsPerPixel, + "depth" , G_TYPE_INT, qt_rgbColorLookup[i].depth, + "endianness", G_TYPE_INT, qt_rgbColorLookup[i].endianness, + "red_mask" , G_TYPE_INT, qt_rgbColorLookup[i].red, + "green_mask", G_TYPE_INT, qt_rgbColorLookup[i].green, + "blue_mask" , G_TYPE_INT, qt_rgbColorLookup[i].blue, + NULL); + + if (qt_rgbColorLookup[i].alpha != 0) { + gst_structure_set( + structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, NULL); + } + gst_caps_append_structure(caps, structure); + } + } + } + + return caps; +} + +gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps) +{ + VO_SINK(base); + + if (!caps) { + sink->delegate->stop(); + + return TRUE; + } else { + const GstStructure *structure = gst_caps_get_structure(caps, 0); + + //qDebug() << gst_caps_to_string(caps); + + QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid; + int bitsPerPixel = 0; + + QSize size; + gst_structure_get_int(structure, "width", &size.rwidth()); + gst_structure_get_int(structure, "height", &size.rheight()); + + if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { + guint32 fourcc = 0; + gst_structure_get_fourcc(structure, "format", &fourcc); + + int index = indexOfYuvColor(fourcc); + if (index != -1) { + pixelFormat = qt_yuvColorLookup[index].pixelFormat; + bitsPerPixel = qt_yuvColorLookup[index].bitsPerPixel; + } + } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { + int depth = 0; + int endianness = 0; + int red = 0; + int green = 0; + int blue = 0; + int alpha = 0; + + gst_structure_get_int(structure, "bpp", &bitsPerPixel); + gst_structure_get_int(structure, "depth", &depth); + gst_structure_get_int(structure, "endianness", &endianness); + gst_structure_get_int(structure, "red_mask", &red); + gst_structure_get_int(structure, "green_mask", &green); + gst_structure_get_int(structure, "blue_mask", &blue); + gst_structure_get_int(structure, "alpha_mask", &alpha); + + int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha); + + if (index != -1) + pixelFormat = qt_rgbColorLookup[index].pixelFormat; + } + + if (pixelFormat != QVideoFrame::Format_Invalid) { + QVideoSurfaceFormat format(size, pixelFormat); + + QPair rate; + gst_structure_get_fraction(structure, "framerate", &rate.first, &rate.second); + + if (rate.second) + format.setFrameRate(qreal(rate.first)/rate.second); + + gint aspectNum = 0; + gint aspectDenum = 0; + if (gst_structure_get_fraction( + structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { + if (aspectDenum > 0) + format.setPixelAspectRatio(aspectNum, aspectDenum); + } + + int bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3; + + if (sink->delegate->start(format, bytesPerLine)) + return TRUE; + } + + } + + return FALSE; +} + +GstFlowReturn QVideoSurfaceGstSink::buffer_alloc( + GstBaseSink *base, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer) +{ + // Should implement this when the buffer pool situation is sorted. + Q_UNUSED(base); + Q_UNUSED(offset); + Q_UNUSED(size); + Q_UNUSED(caps); + Q_UNUSED(buffer); + + return GST_FLOW_NOT_SUPPORTED; +} + +gboolean QVideoSurfaceGstSink::start(GstBaseSink *base) +{ + Q_UNUSED(base); + + return TRUE; +} + +gboolean QVideoSurfaceGstSink::stop(GstBaseSink *base) +{ + Q_UNUSED(base); + + return TRUE; +} + +gboolean QVideoSurfaceGstSink::unlock(GstBaseSink *base) +{ + Q_UNUSED(base); + + return TRUE; +} + +gboolean QVideoSurfaceGstSink::event(GstBaseSink *base, GstEvent *event) +{ + Q_UNUSED(base); + Q_UNUSED(event); + + return TRUE; +} + +GstFlowReturn QVideoSurfaceGstSink::preroll(GstBaseSink *base, GstBuffer *buffer) +{ + VO_SINK(base); + + return sink->delegate->render(buffer); +} + +GstFlowReturn QVideoSurfaceGstSink::render(GstBaseSink *base, GstBuffer *buffer) +{ + VO_SINK(base); + return sink->delegate->render(buffer); +} + diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h new file mode 100644 index 0000000..99d7007 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 VIDEOSURFACEGSTSINK_H +#define VIDEOSURFACEGSTSINK_H + +#include + +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAbstractVideoSurface; + +class QVideoSurfaceGstDelegate : public QObject +{ + Q_OBJECT +public: + QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface); + + QList supportedPixelFormats() const; + + bool start(const QVideoSurfaceFormat &format, int bytesPerLine); + void stop(); + + GstFlowReturn render(GstBuffer *buffer); + +private slots: + void queuedStart(); + void queuedStop(); + void queuedRender(); + + void supportedFormatsChanged(); + +private: + QPointer m_surface; + QList m_supportedPixelFormats; + QMutex m_mutex; + QWaitCondition m_setupCondition; + QWaitCondition m_renderCondition; + QVideoSurfaceFormat m_format; + QVideoFrame m_frame; + GstFlowReturn m_renderReturn; + int m_bytesPerLine; + bool m_started; +}; + +class QVideoSurfaceGstSink +{ +public: + GstVideoSink parent; + + static QVideoSurfaceGstSink *createSink(QAbstractVideoSurface *surface); + +private: + static GType get_type(); + static void class_init(gpointer g_class, gpointer class_data); + static void base_init(gpointer g_class); + static void instance_init(GTypeInstance *instance, gpointer g_class); + + static void finalize(GObject *object); + + static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition); + + static GstCaps *get_caps(GstBaseSink *sink); + static gboolean set_caps(GstBaseSink *sink, GstCaps *caps); + + static GstFlowReturn buffer_alloc( + GstBaseSink *sink, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer); + + static gboolean start(GstBaseSink *sink); + static gboolean stop(GstBaseSink *sink); + + static gboolean unlock(GstBaseSink *sink); + + static gboolean event(GstBaseSink *sink, GstEvent *event); + static GstFlowReturn preroll(GstBaseSink *sink, GstBuffer *buffer); + static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer); + +private: + QVideoSurfaceGstDelegate *delegate; +}; + + +class QVideoSurfaceGstSinkClass +{ +public: + GstVideoSinkClass parent_class; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp new file mode 100644 index 0000000..56c1405 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 +#include + +#include "qx11videosurface.h" + +struct XvFormatRgb +{ + QVideoFrame::PixelFormat pixelFormat; + int bits_per_pixel; + int format; + int num_planes; + + int depth; + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; + +}; + +bool operator ==(const XvImageFormatValues &format, const XvFormatRgb &rgb) +{ + return format.type == XvRGB + && format.bits_per_pixel == rgb.bits_per_pixel + && format.format == rgb.format + && format.num_planes == rgb.num_planes + && format.depth == rgb.depth + && format.red_mask == rgb.red_mask + && format.blue_mask == rgb.blue_mask; +} + +static const XvFormatRgb qt_xvRgbLookup[] = +{ + { QVideoFrame::Format_ARGB32, 32, XvPacked, 1, 32, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_RGB565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F }, + { QVideoFrame::Format_BGRA32, 32, XvPacked, 1, 32, 0xFF000000, 0x00FF0000, 0x0000FF00 }, + { QVideoFrame::Format_BGR32 , 32, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_BGR24 , 24, XvPacked, 1, 24, 0x00FF0000, 0x0000FF00, 0x000000FF }, + { QVideoFrame::Format_BGR565, 16, XvPacked, 1, 16, 0x0000F800, 0x000007E0, 0x0000001F } +}; + +struct XvFormatYuv +{ + QVideoFrame::PixelFormat pixelFormat; + int bits_per_pixel; + int format; + int num_planes; + + unsigned int y_sample_bits; + unsigned int u_sample_bits; + unsigned int v_sample_bits; + unsigned int horz_y_period; + unsigned int horz_u_period; + unsigned int horz_v_period; + unsigned int vert_y_period; + unsigned int vert_u_period; + unsigned int vert_v_period; + char component_order[32]; +}; + +bool operator ==(const XvImageFormatValues &format, const XvFormatYuv &yuv) +{ + return format.type == XvYUV + && format.bits_per_pixel == yuv.bits_per_pixel + && format.format == yuv.format + && format.num_planes == yuv.num_planes + && format.y_sample_bits == yuv.y_sample_bits + && format.u_sample_bits == yuv.u_sample_bits + && format.v_sample_bits == yuv.v_sample_bits + && format.horz_y_period == yuv.horz_y_period + && format.horz_u_period == yuv.horz_u_period + && format.horz_v_period == yuv.horz_v_period + && format.horz_y_period == yuv.vert_y_period + && format.vert_u_period == yuv.vert_u_period + && format.vert_v_period == yuv.vert_v_period + && qstrncmp(format.component_order, yuv.component_order, 32) == 0; +} + +static const XvFormatYuv qt_xvYuvLookup[] = +{ + { QVideoFrame::Format_YUV444 , 24, XvPacked, 1, 8, 8, 8, 1, 1, 1, 1, 1, 1, "YUV" }, + { QVideoFrame::Format_YUV420P, 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, + { QVideoFrame::Format_YV12 , 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, + { QVideoFrame::Format_UYVY , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY" }, + { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUYV" }, + { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, + { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, + { QVideoFrame::Format_Y8 , 8 , XvPlanar, 1, 8, 0, 0, 1, 0, 0, 1, 0, 0, "Y" } +}; + +QX11VideoSurface::QX11VideoSurface(QObject *parent) + : QAbstractVideoSurface(parent) + , m_winId(0) + , m_portId(0) + , m_gc(0) + , m_image(0) +{ +} + +QX11VideoSurface::~QX11VideoSurface() +{ + if (m_gc) + XFreeGC(QX11Info::display(), m_gc); + + if (m_portId != 0) + XvUngrabPort(QX11Info::display(), m_portId, 0); +} + +WId QX11VideoSurface::winId() const +{ + return m_winId; +} + +void QX11VideoSurface::setWinId(WId id) +{ + if (id == m_winId) + return; + + if (m_image) + XFree(m_image); + + if (m_gc) { + XFreeGC(QX11Info::display(), m_gc); + m_gc = 0; + } + + if (m_portId != 0) + XvUngrabPort(QX11Info::display(), m_portId, 0); + + m_supportedPixelFormats.clear(); + m_formatIds.clear(); + + m_winId = id; + + if (m_winId && findPort()) { + querySupportedFormats(); + + m_gc = XCreateGC(QX11Info::display(), m_winId, 0, 0); + + if (m_image) { + m_image = 0; + + if (!start(surfaceFormat())) + QAbstractVideoSurface::stop(); + } + } else if (m_image) { + m_image = 0; + + QAbstractVideoSurface::stop(); + } + + emit supportedFormatsChanged(); +} + +QRect QX11VideoSurface::displayRect() const +{ + return m_displayRect; +} + +void QX11VideoSurface::setDisplayRect(const QRect &rect) +{ + m_displayRect = rect; +} + +int QX11VideoSurface::brightness() const +{ + return getAttribute("XV_BRIGHTNESS", m_brightnessRange.first, m_brightnessRange.second); +} + +void QX11VideoSurface::setBrightness(int brightness) +{ + setAttribute("XV_BRIGHTNESS", brightness, m_brightnessRange.first, m_brightnessRange.second); +} + +int QX11VideoSurface::contrast() const +{ + return getAttribute("XV_CONTRAST", m_contrastRange.first, m_contrastRange.second); +} + +void QX11VideoSurface::setContrast(int contrast) +{ + setAttribute("XV_CONTRAST", contrast, m_contrastRange.first, m_contrastRange.second); +} + +int QX11VideoSurface::hue() const +{ + return getAttribute("XV_HUE", m_hueRange.first, m_hueRange.second); +} + +void QX11VideoSurface::setHue(int hue) +{ + setAttribute("XV_HUE", hue, m_hueRange.first, m_hueRange.second); +} + +int QX11VideoSurface::saturation() const +{ + return getAttribute("XV_SATURATION", m_saturationRange.first, m_saturationRange.second); +} + +void QX11VideoSurface::setSaturation(int saturation) +{ + setAttribute("XV_SATURATION", saturation, m_saturationRange.first, m_saturationRange.second); +} + +int QX11VideoSurface::getAttribute(const char *attribute, int minimum, int maximum) const +{ + if (m_portId != 0) { + Display *display = QX11Info::display(); + + Atom atom = XInternAtom(display, attribute, True); + + int value = 0; + + XvGetPortAttribute(display, m_portId, atom, &value); + + return redistribute(value, minimum, maximum, -100, 100); + } else { + return 0; + } +} + +void QX11VideoSurface::setAttribute(const char *attribute, int value, int minimum, int maximum) +{ + if (m_portId != 0) { + Display *display = QX11Info::display(); + + Atom atom = XInternAtom(display, attribute, True); + + XvSetPortAttribute( + display, m_portId, atom, redistribute(value, -100, 100, minimum, maximum)); + } +} + +int QX11VideoSurface::redistribute( + int value, int fromLower, int fromUpper, int toLower, int toUpper) +{ + return fromUpper != fromLower + ? ((value - fromLower) * (toUpper - toLower) / (fromUpper - fromLower)) + toLower + : 0; +} + +QList QX11VideoSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + return handleType == QAbstractVideoBuffer::NoHandle + ? m_supportedPixelFormats + : QList(); +} + +bool QX11VideoSurface::start(const QVideoSurfaceFormat &format) +{ + if (m_image) + XFree(m_image); + + int xvFormatId = 0; + for (int i = 0; i < m_supportedPixelFormats.count(); ++i) { + if (m_supportedPixelFormats.at(i) == format.pixelFormat()) { + xvFormatId = m_formatIds.at(i); + break; + } + } + + if (xvFormatId == 0) { + setError(UnsupportedFormatError); + } else { + XvImage *image = XvCreateImage( + QX11Info::display(), + m_portId, + xvFormatId, + 0, + format.frameWidth(), + format.frameHeight()); + + if (!image) { + setError(ResourceError); + } else { + m_viewport = format.viewport(); + m_image = image; + + return QAbstractVideoSurface::start(format); + } + } + + if (m_image) { + m_image = 0; + + QAbstractVideoSurface::stop(); + } + + return false; +} + +void QX11VideoSurface::stop() +{ + if (m_image) { + XFree(m_image); + m_image = 0; + + QAbstractVideoSurface::stop(); + } +} + +bool QX11VideoSurface::present(const QVideoFrame &frame) +{ + if (!m_image) { + setError(StoppedError); + return false; + } else if (m_image->width != frame.width() || m_image->height != frame.height()) { + setError(IncorrectFormatError); + return false; + } else { + QVideoFrame frameCopy(frame); + + if (!frameCopy.map(QAbstractVideoBuffer::ReadOnly)) { + setError(IncorrectFormatError); + return false; + } else { + bool presented = false; + + if (m_image->data_size > frame.mappedBytes()) { + qWarning("Insufficient frame buffer size"); + setError(IncorrectFormatError); + } else if (m_image->num_planes > 0 && m_image->pitches[0] != frame.bytesPerLine()) { + qWarning("Incompatible frame pitches"); + setError(IncorrectFormatError); + } else { + m_image->data = reinterpret_cast(frameCopy.bits()); + + XvPutImage( + QX11Info::display(), + m_portId, + m_winId, + m_gc, + m_image, + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height()); + + m_image->data = 0; + + presented = true; + } + + frameCopy.unmap(); + + return presented; + } + } +} + +bool QX11VideoSurface::findPort() +{ + unsigned int count = 0; + XvAdaptorInfo *adaptors = 0; + bool portFound = false; + + if (XvQueryAdaptors(QX11Info::display(), m_winId, &count, &adaptors) == Success) { + for (unsigned int i = 0; i < count && !portFound; ++i) { + if (adaptors[i].type & XvImageMask) { + m_portId = adaptors[i].base_id; + + for (unsigned int j = 0; j < adaptors[i].num_ports && !portFound; ++j, ++m_portId) + portFound = XvGrabPort(QX11Info::display(), m_portId, 0) == Success; + } + } + XvFreeAdaptorInfo(adaptors); + } + + return portFound; +} + +void QX11VideoSurface::querySupportedFormats() +{ + int count = 0; + if (XvImageFormatValues *imageFormats = XvListImageFormats( + QX11Info::display(), m_portId, &count)) { + const int rgbCount = sizeof(qt_xvRgbLookup) / sizeof(XvFormatRgb); + const int yuvCount = sizeof(qt_xvYuvLookup) / sizeof(XvFormatYuv); + + for (int i = 0; i < count; ++i) { + switch (imageFormats[i].type) { + case XvRGB: + for (int j = 0; j < rgbCount; ++j) { + if (imageFormats[i] == qt_xvRgbLookup[j]) { + m_supportedPixelFormats.append(qt_xvRgbLookup[j].pixelFormat); + m_formatIds.append(imageFormats[i].id); + break; + } + } + break; + case XvYUV: + for (int j = 0; j < yuvCount; ++j) { + if (imageFormats[i] == qt_xvYuvLookup[j]) { + m_supportedPixelFormats.append(qt_xvYuvLookup[j].pixelFormat); + m_formatIds.append(imageFormats[i].id); + break; + } + } + break; + } + } + XFree(imageFormats); + } + + m_brightnessRange = qMakePair(0, 0); + m_contrastRange = qMakePair(0, 0); + m_hueRange = qMakePair(0, 0); + m_saturationRange = qMakePair(0, 0); + + if (XvAttribute *attributes = XvQueryPortAttributes(QX11Info::display(), m_portId, &count)) { + for (int i = 0; i < count; ++i) { + if (qstrcmp(attributes[i].name, "XV_BRIGHTNESS") == 0) + m_brightnessRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + else if (qstrcmp(attributes[i].name, "XV_CONTRAST") == 0) + m_contrastRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + else if (qstrcmp(attributes[i].name, "XV_HUE") == 0) + m_hueRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + else if (qstrcmp(attributes[i].name, "XV_SATURATION") == 0) + m_saturationRange = qMakePair(attributes[i].min_value, attributes[i].max_value); + } + + XFree(attributes); + } +} diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.h b/src/plugins/mediaservices/gstreamer/qx11videosurface.h new file mode 100644 index 0000000..e69517a --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QX11VIDEOSURFACE_H +#define QX11VIDEOSURFACE_H + +#include +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QX11VideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + QX11VideoSurface(QObject *parent = 0); + ~QX11VideoSurface(); + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool start(const QVideoSurfaceFormat &format); + void stop(); + + bool present(const QVideoFrame &frame); + +private: + WId m_winId; + XvPortID m_portId; + GC m_gc; + XvImage *m_image; + QList m_supportedPixelFormats; + QVector m_formatIds; + QRect m_viewport; + QRect m_displayRect; + QPair m_brightnessRange; + QPair m_contrastRange; + QPair m_hueRange; + QPair m_saturationRange; + + bool findPort(); + void querySupportedFormats(); + + int getAttribute(const char *attribute, int minimum, int maximum) const; + void setAttribute(const char *attribute, int value, int minimum, int maximum); + + static int redistribute(int value, int fromLower, int fromUpper, int toLower, int toUpper); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro index 03859bd..879d914 100644 --- a/src/plugins/mediaservices/mediaservices.pro +++ b/src/plugins/mediaservices/mediaservices.pro @@ -2,4 +2,15 @@ TEMPLATE = subdirs mac:SUBDIRS += qt7 +unix:!mac:!symbian { + TMP_GST_LIBS = \ + gstreamer-0.10 >= 0.10.19 \ + gstreamer-base-0.10 >= 0.10.19 \ + gstreamer-interfaces-0.10 >= 0.10.19 \ + gstreamer-audio-0.10 >= 0.10.19 \ + gstreamer-video-0.10 >= 0.10.19 + system(pkg-config --exists \'$${TMP_GST_LIBS}\' --print-errors): { + SUBDIRS += gstreamer + } +} -- cgit v0.12 From 65bca1935008012d096872647dc02c124abcab75 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Tue, 19 Jan 2010 13:54:25 +1000 Subject: Multimedia; reorganize qt7 mediaservice provider. --- .../mediaservices/qt7/mediaplayer/mediaplayer.pri | 18 + .../qt7/mediaplayer/qt7playercontrol.h | 128 +++++++ .../qt7/mediaplayer/qt7playercontrol.mm | 188 ++++++++++ .../qt7/mediaplayer/qt7playermetadata.h | 84 +++++ .../qt7/mediaplayer/qt7playermetadata.mm | 261 +++++++++++++ .../qt7/mediaplayer/qt7playerservice.h | 90 +++++ .../qt7/mediaplayer/qt7playerservice.mm | 151 ++++++++ .../qt7/mediaplayer/qt7playersession.h | 140 +++++++ .../qt7/mediaplayer/qt7playersession.mm | 402 +++++++++++++++++++++ src/plugins/mediaservices/qt7/qt7.pro | 9 +- src/plugins/mediaservices/qt7/qt7playercontrol.h | 128 ------- src/plugins/mediaservices/qt7/qt7playercontrol.mm | 188 ---------- src/plugins/mediaservices/qt7/qt7playermetadata.h | 84 ----- src/plugins/mediaservices/qt7/qt7playermetadata.mm | 261 ------------- src/plugins/mediaservices/qt7/qt7playerservice.h | 90 ----- src/plugins/mediaservices/qt7/qt7playerservice.mm | 151 -------- src/plugins/mediaservices/qt7/qt7playersession.h | 140 ------- src/plugins/mediaservices/qt7/qt7playersession.mm | 402 --------------------- src/plugins/mediaservices/qt7/qt7serviceplugin.mm | 10 +- 19 files changed, 1470 insertions(+), 1455 deletions(-) create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.mm create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.h create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.mm create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h create mode 100644 src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm delete mode 100644 src/plugins/mediaservices/qt7/qt7playercontrol.h delete mode 100644 src/plugins/mediaservices/qt7/qt7playercontrol.mm delete mode 100644 src/plugins/mediaservices/qt7/qt7playermetadata.h delete mode 100644 src/plugins/mediaservices/qt7/qt7playermetadata.mm delete mode 100644 src/plugins/mediaservices/qt7/qt7playerservice.h delete mode 100644 src/plugins/mediaservices/qt7/qt7playerservice.mm delete mode 100644 src/plugins/mediaservices/qt7/qt7playersession.h delete mode 100644 src/plugins/mediaservices/qt7/qt7playersession.mm diff --git a/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri new file mode 100644 index 0000000..f00d418 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +DEFINES += Q_MEDIASERVICE_MEDIAPLAYER_AVAILABLE + +HEADERS += \ + $$PWD/qt7playercontrol.h \ + $$PWD/qt7playermetadata.h \ + $$PWD/qt7playerservice.h \ + $$PWD/qt7playersession.h + +OBJECTIVE_SOURCES += \ + $$PWD/qt7playercontrol.mm \ + $$PWD/qt7playermetadata.mm \ + $$PWD/qt7playerservice.mm \ + $$PWD/qt7playersession.mm + + + diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h new file mode 100644 index 0000000..da86949 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERCONTROL_H +#define QT7PLAYERCONTROL_H + +#include +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; +class QMediaPlaylist; +class QMediaPlaylistNavigator; + +class QT7PlayerControl : public QMediaPlayerControl +{ +Q_OBJECT +public: + QT7PlayerControl(QObject *parent = 0); + ~QT7PlayerControl(); + + void setSession(QT7PlayerSession *session); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +Q_SIGNALS: + void mediaChanged(const QMediaContent& content); + void durationChanged(qint64 duration); + void positionChanged(qint64 position); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void bufferStatusChanged(int percentFilled); + void seekableChanged(bool); + void seekRangeChanged(const QPair&); + void playbackRateChanged(qreal rate); + void error(int error, const QString &errorString); + +private: + QT7PlayerSession *m_session; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm new file mode 100644 index 0000000..b74f434 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qt7playercontrol.h" +#include "qt7playersession.h" + +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +QT7PlayerControl::QT7PlayerControl(QObject *parent) + : QMediaPlayerControl(parent) +{ +} + +QT7PlayerControl::~QT7PlayerControl() +{ +} + +void QT7PlayerControl::setSession(QT7PlayerSession *session) +{ + m_session = session; + + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); +} + +qint64 QT7PlayerControl::position() const +{ + return m_session->position(); +} + +qint64 QT7PlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QT7PlayerControl::state() const +{ + return m_session->state(); +} + +QMediaPlayer::MediaStatus QT7PlayerControl::mediaStatus() const +{ + return m_session->mediaStatus(); +} + +int QT7PlayerControl::bufferStatus() const +{ + return m_session->bufferStatus(); +} + +int QT7PlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QT7PlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QT7PlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QT7PlayerControl::availablePlaybackRanges() const +{ + return isSeekable() ? QMediaTimeRange(0, duration()) : QMediaTimeRange(); +} + +qreal QT7PlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QT7PlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QT7PlayerControl::setPosition(qint64 pos) +{ + m_session->setPosition(pos); +} + +void QT7PlayerControl::play() +{ + m_session->play(); +} + +void QT7PlayerControl::pause() +{ + m_session->pause(); +} + +void QT7PlayerControl::stop() +{ + m_session->stop(); +} + +void QT7PlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QT7PlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QT7PlayerControl::media() const +{ + return m_session->media(); +} + +const QIODevice *QT7PlayerControl::mediaStream() const +{ + return m_session->mediaStream(); +} + +void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + m_session->setMedia(content, stream); + + emit mediaChanged(content); +} + + +bool QT7PlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + +#include "moc_qt7playercontrol.cpp" + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h new file mode 100644 index 0000000..9aa9887 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERMETADATACONTROL_H +#define QT7PLAYERMETADATACONTROL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; + +class QT7PlayerMetaDataControl : public QMetaDataControl +{ + Q_OBJECT +public: + QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent); + virtual ~QT7PlayerMetaDataControl(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QT7PlayerSession *m_session; + QMap m_tags; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.mm new file mode 100644 index 0000000..96b7a68 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playermetadata.mm @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "qt7backend.h" +#include "qt7playermetadata.h" +#include "qt7playersession.h" +#include + +#import + +#ifdef QUICKTIME_C_API_AVAILABLE + #include + #undef check // avoid name clash; +#endif + +QT_BEGIN_NAMESPACE + +QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) + :QMetaDataControl(parent), m_session(session) +{ +} + +QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() +{ +} + +bool QT7PlayerMetaDataControl::isMetaDataAvailable() const +{ + return !m_tags.isEmpty(); +} + +bool QT7PlayerMetaDataControl::isWritable() const +{ + return false; +} + +QVariant QT7PlayerMetaDataControl::metaData(QtMedia::MetaData key) const +{ + return m_tags.value(key); +} + +void QT7PlayerMetaDataControl::setMetaData(QtMedia::MetaData key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QList QT7PlayerMetaDataControl::availableMetaData() const +{ + return m_tags.keys(); +} + +QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const +{ + Q_UNUSED(key); + return QVariant(); +} + +void QT7PlayerMetaDataControl::setExtendedMetaData(const QString &key, QVariant const &value) +{ + Q_UNUSED(key); + Q_UNUSED(value); +} + +QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +#ifdef QUICKTIME_C_API_AVAILABLE + +static QString stripCopyRightSymbol(const QString &key) +{ + return key.right(key.length()-1); +} + +static QString convertQuickTimeKeyToUserKey(const QString &key) +{ + if (key == QLatin1String("com.apple.quicktime.displayname")) + return QLatin1String("nam"); + else if (key == QLatin1String("com.apple.quicktime.album")) + return QLatin1String("alb"); + else if (key == QLatin1String("com.apple.quicktime.artist")) + return QLatin1String("ART"); + else + return QLatin1String("???"); +} + +static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, + QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) +{ + QTPropertyValueType type; + ByteCount propSize; + UInt32 propFlags; + OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); + + + *value = malloc(propSize); + + err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); + + if (type == 'code' || type == 'itsk' || type == 'itlk') { + // convert from native endian to big endian + OSTypePtr pType = (OSTypePtr)*value; + *pType = EndianU32_NtoB(*pType); + } + + return err; +} + +static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) +{ + QTPropertyValuePtr value = 0; + ByteCount ignore = 0; + OSStatus err = readMetaValue( + metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); + + UInt32 type = *((UInt32 *) value); + if (value) + free(value); + return type; +} + +static QString cFStringToQString(CFStringRef str) +{ + if(!str) + return QString(); + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast(chars), length); + + QVarLengthArray buffer(length); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); + return QString(reinterpret_cast(buffer.constData()), length); +} + + +static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) +{ + QTPropertyValuePtr value = 0; + ByteCount size = 0; + OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); + + QString string; + UInt32 dataType = getMetaType(metaDataRef, item); + switch (dataType){ + case kQTMetaDataTypeUTF8: + case kQTMetaDataTypeMacEncodedText: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); + break; + case kQTMetaDataTypeUTF16BE: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); + break; + default: + break; + } + + if (value) + free(value); + return string; +} + + +static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap &result) +{ + QTMetaDataItem item = kQTMetaDataItemUninitialized; + OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + while (err == noErr){ + QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); + if (format == kQTMetaDataStorageFormatQuickTime) + key = convertQuickTimeKeyToUserKey(key); + else + key = stripCopyRightSymbol(key); + + if (!result.contains(key)){ + QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); + result.insert(key, val); + } + err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + } +} +#endif + + +void QT7PlayerMetaDataControl::updateTags() +{ + bool wasEmpty = m_tags.isEmpty(); + m_tags.clear(); + + QTMovie *movie = (QTMovie*)m_session->movie(); + + if (movie) { + QMultiMap metaMap; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTMetaDataRef metaDataRef; + OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); + + readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); +#else + NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; + metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); +#endif // QUICKTIME_C_API_AVAILABLE + + m_tags.insert(QtMedia::AlbumArtist, metaMap.value(QLatin1String("ART"))); + m_tags.insert(QtMedia::AlbumTitle, metaMap.value(QLatin1String("alb"))); + m_tags.insert(QtMedia::Title, metaMap.value(QLatin1String("nam"))); + m_tags.insert(QtMedia::Date, metaMap.value(QLatin1String("day"))); + m_tags.insert(QtMedia::Genre, metaMap.value(QLatin1String("gnre"))); + m_tags.insert(QtMedia::TrackNumber, metaMap.value(QLatin1String("trk"))); + m_tags.insert(QtMedia::Description, metaMap.value(QLatin1String("des"))); + } + + if (!wasEmpty || !m_tags.isEmpty()) + emit metaDataChanged(); +} + +QT_END_NAMESPACE + +#include "moc_qt7playermetadata.cpp" diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.h new file mode 100644 index 0000000..d4b30b8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERSERVICE_H +#define QT7PLAYERSERVICE_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerControl; +class QT7PlayerMetaDataControl; +class QT7VideoOutputControl; +class QT7VideoWindowControl; +class QT7VideoWidgetControl; +class QT7VideoRendererControl; +class QT7VideoOutput; +class QT7PlayerSession; + +class QT7PlayerService : public QMediaService +{ +Q_OBJECT +public: + QT7PlayerService(QObject *parent = 0); + ~QT7PlayerService(); + + QMediaControl *control(const char *name) const; + +private slots: + void updateVideoOutput(); + +private: + QT7PlayerSession *m_session; + QT7PlayerControl *m_control; + QT7VideoOutputControl *m_videoOutputControl; + QT7VideoWindowControl *m_videoWidnowControl; + QT7VideoWidgetControl *m_videoWidgetControl; + QT7VideoRendererControl *m_videoRendererControl; + QT7PlayerMetaDataControl *m_playerMetaDataControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.mm new file mode 100644 index 0000000..df15fa8 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playerservice.mm @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 +#include +#include + +#include "qt7backend.h" +#include "qt7playerservice.h" +#include "qt7playercontrol.h" +#include "qt7playersession.h" +#include "qt7videooutputcontrol.h" +#include "qt7movieviewoutput.h" +#include "qt7movieviewrenderer.h" +#include "qt7movierenderer.h" +#include "qt7movievideowidget.h" +#include "qt7playermetadata.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QT7PlayerService::QT7PlayerService(QObject *parent): + QMediaService(parent) +{ + m_session = new QT7PlayerSession; + + m_control = new QT7PlayerControl(this); + m_control->setSession(m_session); + + m_playerMetaDataControl = new QT7PlayerMetaDataControl(m_session, this); + connect(m_control, SIGNAL(mediaChanged(QMediaContent)), m_playerMetaDataControl, SLOT(updateTags())); + + m_videoOutputControl = new QT7VideoOutputControl(this); + + m_videoWidnowControl = 0; + m_videoWidgetControl = 0; + m_videoRendererControl = 0; + +#if defined(QT_MAC_USE_COCOA) + m_videoWidnowControl = new QT7MovieViewOutput(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::WindowOutput); + qDebug() << "Using cocoa"; +#endif + +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoRendererControl = new QT7MovieRenderer(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); + + m_videoWidgetControl = new QT7MovieVideoWidget(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::WidgetOutput); + qDebug() << "QuickTime C API is available"; +#else + m_videoRendererControl = new QT7MovieViewRenderer(this); + m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); + qDebug() << "QuickTime C API is not available"; +#endif + + + connect(m_videoOutputControl, SIGNAL(videoOutputChanged(QVideoOutputControl::Output)), + this, SLOT(updateVideoOutput())); +} + +QT7PlayerService::~QT7PlayerService() +{ +} + +QMediaControl *QT7PlayerService::control(const char *name) const +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return m_videoOutputControl; + + if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return m_videoWidnowControl; + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return m_videoRendererControl; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) + return m_videoWidgetControl; + + if (qstrcmp(name, QMetaDataControl_iid) == 0) + return m_playerMetaDataControl; + + return 0; +} + +void QT7PlayerService::updateVideoOutput() +{ + qDebug() << "QT7PlayerService::updateVideoOutput" << m_videoOutputControl->output(); + + switch (m_videoOutputControl->output()) { + case QVideoOutputControl::WindowOutput: + m_session->setVideoOutput(m_videoWidnowControl); + break; + case QVideoOutputControl::RendererOutput: + m_session->setVideoOutput(m_videoRendererControl); + break; + case QVideoOutputControl::WidgetOutput: + m_session->setVideoOutput(m_videoWidgetControl); + break; + default: + m_session->setVideoOutput(0); + } +} + +QT_END_NAMESPACE + +#include "moc_qt7playerservice.cpp" diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h new file mode 100644 index 0000000..55505ee --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QT7PLAYERSESSION_H +#define QT7PLAYERSESSION_H + +#include +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QT7PlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7VideoOutput; +class QT7PlayerSession; +class QT7PlayerService; + +class QT7PlayerSession : public QObject +{ +Q_OBJECT +public: + QT7PlayerSession(QObject *parent = 0); + ~QT7PlayerSession(); + + void *movie() const; + + void setControl(QT7PlayerControl *control); + void setVideoOutput(QT7VideoOutput *output); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isVideoAvailable() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + + void processEOS(); + +signals: + void positionChanged(qint64 position); + void durationChanged(qint64 duration); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void videoAvailableChanged(bool videoAvailable); + void error(int error, const QString &errorString); + +private: + void *m_QTMovie; + void *m_movieObserver; + + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QIODevice *m_mediaStream; + QMediaContent m_resources; + + QT7VideoOutput *m_videoOutput; + + mutable qint64 m_currentTime; + + bool m_muted; + int m_volume; + qreal m_rate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm new file mode 100644 index 0000000..3131a90 --- /dev/null +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#import +#import + +#include "qt7backend.h" + +#include "qt7playersession.h" +#include "qt7playercontrol.h" +#include "qt7videooutputcontrol.h" + +#include + +#include + +#include +#include + + +QT_BEGIN_NAMESPACE + +@interface QTMovieObserver : NSObject +{ +@private + QT7PlayerSession *m_session; + QTMovie *m_movie; +} + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; +- (void) setMovie:(QTMovie *)movie; +- (void) processEOS:(NSNotification *)notification; +@end + +@implementation QTMovieObserver + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session +{ + if (!(self = [super init])) + return nil; + + self->m_session = session; + return self; +} + +- (void) setMovie:(QTMovie *)movie +{ + if (m_movie == movie) + return; + + if (m_movie) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [m_movie release]; + } + + m_movie = movie; + + if (movie) { + [[NSNotificationCenter defaultCenter] addObserver: self selector: + @selector(processEOS:) name: QTMovieDidEndNotification object: m_movie]; + + [movie retain]; + } +} + +- (void) processEOS:(NSNotification *)notification +{ + Q_UNUSED(notification); + m_session->processEOS(); +} + +@end + +static CFStringRef qString2CFStringRef(const QString &string) +{ + return CFStringCreateWithCharacters(0, reinterpret_cast(string.unicode()), + string.length()); +} + +QT7PlayerSession::QT7PlayerSession(QObject *parent) + : QObject(parent) + , m_QTMovie(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_mediaStream(0) + , m_videoOutput(0) + , m_muted(false) + , m_volume(100) + , m_rate(1.0) +{ + m_movieObserver = [[QTMovieObserver alloc] initWithPlayerSession:this]; +} + +QT7PlayerSession::~QT7PlayerSession() +{ + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + [(QTMovieObserver*)m_movieObserver release]; +} + +void *QT7PlayerSession::movie() const +{ + return m_QTMovie; +} + +void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) +{ + if (m_videoOutput == output) + return; + + qDebug() << "set output" << output; + + if (m_videoOutput) { + m_videoOutput->setEnabled(false); + m_videoOutput->setMovie(0); + } + + m_videoOutput = output; + + if (m_videoOutput) { + m_videoOutput->setEnabled(m_QTMovie != 0); + m_videoOutput->setMovie(m_QTMovie); + } +} + + +qint64 QT7PlayerSession::position() const +{ + if (!m_QTMovie || m_state == QMediaPlayer::PausedState) + return m_currentTime; + + AutoReleasePool pool; + + QTTime qtTime = [(QTMovie*)m_QTMovie currentTime]; + quint64 t = static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); + m_currentTime = t; + + return m_currentTime; +} + +qint64 QT7PlayerSession::duration() const +{ + if (!m_QTMovie) + return 0; + + AutoReleasePool pool; + + QTTime qtTime = [(QTMovie*)m_QTMovie duration]; + + return static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +QMediaPlayer::State QT7PlayerSession::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QT7PlayerSession::mediaStatus() const +{ + return m_mediaStatus; +} + +int QT7PlayerSession::bufferStatus() const +{ + return 100; +} + +int QT7PlayerSession::volume() const +{ + return m_volume; +} + +bool QT7PlayerSession::isMuted() const +{ + return m_muted; +} + +bool QT7PlayerSession::isSeekable() const +{ + return true; +} + +qreal QT7PlayerSession::playbackRate() const +{ + return m_rate; +} + +void QT7PlayerSession::setPlaybackRate(qreal rate) +{ + if (qFuzzyCompare(m_rate, rate)) + return; + + m_rate = rate; + + if (m_QTMovie && m_state == QMediaPlayer::PlayingState) { + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; + } +} + +void QT7PlayerSession::setPosition(qint64 pos) +{ + if ( !isSeekable() || pos == position()) + return; + + AutoReleasePool pool; + + pos = qMin(pos, duration()); + + QTTime newQTTime = [(QTMovie*)m_QTMovie currentTime]; + newQTTime.timeValue = (pos / 1000.0f) * newQTTime.timeScale; + [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; +} + +void QT7PlayerSession::play() +{ + m_state = QMediaPlayer::PlayingState; + + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; + + emit stateChanged(m_state); +} + +void QT7PlayerSession::pause() +{ + m_state = QMediaPlayer::PausedState; + + [(QTMovie*)m_QTMovie setRate:0]; + + emit stateChanged(m_state); +} + +void QT7PlayerSession::stop() +{ + m_state = QMediaPlayer::StoppedState; + + [(QTMovie*)m_QTMovie setRate:0]; + setPosition(0); + + if (m_state == QMediaPlayer::StoppedState) + emit stateChanged(m_state); +} + +void QT7PlayerSession::setVolume(int volume) +{ + if (m_QTMovie) { + m_volume = volume; + [(QTMovie*)m_QTMovie setVolume:(volume/100.0f)]; + } +} + +void QT7PlayerSession::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + + if (m_QTMovie) + [(QTMovie*)m_QTMovie setMuted:m_muted]; + + emit mutedChanged(muted); + } +} + +QMediaContent QT7PlayerSession::media() const +{ + return m_resources; +} + +const QIODevice *QT7PlayerSession::mediaStream() const +{ + return m_mediaStream; +} + +void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) +{ + AutoReleasePool pool; + + if (m_QTMovie) { + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + + if (m_videoOutput) { + m_videoOutput->setEnabled(false); + m_videoOutput->setMovie(0); + } + + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + } + + m_resources = content; + m_mediaStream = stream; + + QUrl url; + + if (!content.isNull()) + url = content.canonicalUrl(); + else + return; + + NSError *err = 0; + QTDataReference *dataRef = 0; + + if ( url.scheme() == "file" ) { + NSString *nsFileName = (NSString *)qString2CFStringRef( url.toLocalFile() ); + dataRef = [QTDataReference dataReferenceWithReferenceToFile:nsFileName]; + } else { + NSString *urlString = (NSString *)qString2CFStringRef( url.toString() ); + NSURL *url = [NSURL URLWithString: urlString]; + dataRef = [QTDataReference dataReferenceWithReferenceToURL:url]; + } + + NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: + dataRef, QTMovieDataReferenceAttribute, + [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, + [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, + [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, + [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, + nil]; + + m_QTMovie = [[QTMovie movieWithAttributes:attr error:&err] retain]; + + if (err) { + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + QString description = QString::fromUtf8([[err localizedDescription] UTF8String]); + + qDebug() << "QT7PlayerSession::setMedia error" << description; + emit error(QMediaPlayer::FormatError, description ); + } else { + [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; + + if (m_videoOutput) { + m_videoOutput->setEnabled(true); + m_videoOutput->setMovie(m_QTMovie); + } + + emit durationChanged(duration()); + emit videoAvailableChanged(isVideoAvailable()); + + [(QTMovie*)m_QTMovie setMuted:m_muted]; + setVolume(m_volume); + } +} + +bool QT7PlayerSession::isVideoAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES; +} + +void QT7PlayerSession::processEOS() +{ + m_mediaStatus = QMediaPlayer::EndOfMedia; + emit stateChanged(m_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(m_mediaStatus); +} + +#include "moc_qt7playersession.cpp" + +QT_END_NAMESPACE + diff --git a/src/plugins/mediaservices/qt7/qt7.pro b/src/plugins/mediaservices/qt7/qt7.pro index 938bc97..13d14d7 100644 --- a/src/plugins/mediaservices/qt7/qt7.pro +++ b/src/plugins/mediaservices/qt7/qt7.pro @@ -19,32 +19,25 @@ contains(QMAKE_MAC_XARCH, no) { HEADERS += \ qt7backend.h \ - qt7playercontrol.h \ qt7videooutputcontrol.h \ qt7movieviewoutput.h \ qt7movievideowidget.h \ qt7movieviewrenderer.h \ - qt7playersession.h \ - qt7playerservice.h \ qt7serviceplugin.h \ qt7movierenderer.h \ - qt7playermetadata.h \ qcvdisplaylink.h OBJECTIVE_SOURCES += \ qt7backend.mm \ - qt7playersession.mm \ qt7serviceplugin.mm \ qt7movieviewoutput.mm \ qt7movievideowidget.mm \ qt7movieviewrenderer.mm \ - qt7playermetadata.mm \ qt7movierenderer.mm \ - qt7playercontrol.mm \ qt7videooutputcontrol.mm \ - qt7playerservice.mm \ qcvdisplaylink.mm +include(mediaplayer/mediaplayer.pri) QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices diff --git a/src/plugins/mediaservices/qt7/qt7playercontrol.h b/src/plugins/mediaservices/qt7/qt7playercontrol.h deleted file mode 100644 index da86949..0000000 --- a/src/plugins/mediaservices/qt7/qt7playercontrol.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 QT7PLAYERCONTROL_H -#define QT7PLAYERCONTROL_H - -#include -#include - -#include -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QT7PlayerSession; -class QT7PlayerService; -class QMediaPlaylist; -class QMediaPlaylistNavigator; - -class QT7PlayerControl : public QMediaPlayerControl -{ -Q_OBJECT -public: - QT7PlayerControl(QObject *parent = 0); - ~QT7PlayerControl(); - - void setSession(QT7PlayerSession *session); - - QMediaPlayer::State state() const; - QMediaPlayer::MediaStatus mediaStatus() const; - - QMediaContent media() const; - const QIODevice *mediaStream() const; - void setMedia(const QMediaContent &content, QIODevice *stream); - - qint64 position() const; - qint64 duration() const; - - int bufferStatus() const; - - int volume() const; - bool isMuted() const; - - bool isVideoAvailable() const; - - bool isSeekable() const; - - QMediaTimeRange availablePlaybackRanges() const; - - - qreal playbackRate() const; - void setPlaybackRate(qreal rate); - -public Q_SLOTS: - void setPosition(qint64 pos); - - void play(); - void pause(); - void stop(); - - void setVolume(int volume); - void setMuted(bool muted); - -Q_SIGNALS: - void mediaChanged(const QMediaContent& content); - void durationChanged(qint64 duration); - void positionChanged(qint64 position); - void stateChanged(QMediaPlayer::State newState); - void mediaStatusChanged(QMediaPlayer::MediaStatus status); - void volumeChanged(int volume); - void mutedChanged(bool muted); - void videoAvailableChanged(bool videoAvailable); - void bufferStatusChanged(int percentFilled); - void seekableChanged(bool); - void seekRangeChanged(const QPair&); - void playbackRateChanged(qreal rate); - void error(int error, const QString &errorString); - -private: - QT7PlayerSession *m_session; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/plugins/mediaservices/qt7/qt7playercontrol.mm b/src/plugins/mediaservices/qt7/qt7playercontrol.mm deleted file mode 100644 index b74f434..0000000 --- a/src/plugins/mediaservices/qt7/qt7playercontrol.mm +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 "qt7playercontrol.h" -#include "qt7playersession.h" - -#include - -#include -#include - - -QT_BEGIN_NAMESPACE - -QT7PlayerControl::QT7PlayerControl(QObject *parent) - : QMediaPlayerControl(parent) -{ -} - -QT7PlayerControl::~QT7PlayerControl() -{ -} - -void QT7PlayerControl::setSession(QT7PlayerSession *session) -{ - m_session = session; - - connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64))); - connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64))); - connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), - this, SIGNAL(stateChanged(QMediaPlayer::State))); - connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), - this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); - connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); - connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); - connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); - connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); -} - -qint64 QT7PlayerControl::position() const -{ - return m_session->position(); -} - -qint64 QT7PlayerControl::duration() const -{ - return m_session->duration(); -} - -QMediaPlayer::State QT7PlayerControl::state() const -{ - return m_session->state(); -} - -QMediaPlayer::MediaStatus QT7PlayerControl::mediaStatus() const -{ - return m_session->mediaStatus(); -} - -int QT7PlayerControl::bufferStatus() const -{ - return m_session->bufferStatus(); -} - -int QT7PlayerControl::volume() const -{ - return m_session->volume(); -} - -bool QT7PlayerControl::isMuted() const -{ - return m_session->isMuted(); -} - -bool QT7PlayerControl::isSeekable() const -{ - return m_session->isSeekable(); -} - -QMediaTimeRange QT7PlayerControl::availablePlaybackRanges() const -{ - return isSeekable() ? QMediaTimeRange(0, duration()) : QMediaTimeRange(); -} - -qreal QT7PlayerControl::playbackRate() const -{ - return m_session->playbackRate(); -} - -void QT7PlayerControl::setPlaybackRate(qreal rate) -{ - m_session->setPlaybackRate(rate); -} - -void QT7PlayerControl::setPosition(qint64 pos) -{ - m_session->setPosition(pos); -} - -void QT7PlayerControl::play() -{ - m_session->play(); -} - -void QT7PlayerControl::pause() -{ - m_session->pause(); -} - -void QT7PlayerControl::stop() -{ - m_session->stop(); -} - -void QT7PlayerControl::setVolume(int volume) -{ - m_session->setVolume(volume); -} - -void QT7PlayerControl::setMuted(bool muted) -{ - m_session->setMuted(muted); -} - -QMediaContent QT7PlayerControl::media() const -{ - return m_session->media(); -} - -const QIODevice *QT7PlayerControl::mediaStream() const -{ - return m_session->mediaStream(); -} - -void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) -{ - m_session->setMedia(content, stream); - - emit mediaChanged(content); -} - - -bool QT7PlayerControl::isVideoAvailable() const -{ - return m_session->isVideoAvailable(); -} - -#include "moc_qt7playercontrol.cpp" - -QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/qt7/qt7playermetadata.h b/src/plugins/mediaservices/qt7/qt7playermetadata.h deleted file mode 100644 index 9aa9887..0000000 --- a/src/plugins/mediaservices/qt7/qt7playermetadata.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 QT7PLAYERMETADATACONTROL_H -#define QT7PLAYERMETADATACONTROL_H - -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QT7PlayerSession; - -class QT7PlayerMetaDataControl : public QMetaDataControl -{ - Q_OBJECT -public: - QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent); - virtual ~QT7PlayerMetaDataControl(); - - bool isMetaDataAvailable() const; - bool isWritable() const; - - QVariant metaData(QtMedia::MetaData key) const; - void setMetaData(QtMedia::MetaData key, const QVariant &value); - QList availableMetaData() const; - - QVariant extendedMetaData(const QString &key) const ; - void setExtendedMetaData(const QString &key, const QVariant &value); - QStringList availableExtendedMetaData() const; - -private slots: - void updateTags(); - -private: - QT7PlayerSession *m_session; - QMap m_tags; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/plugins/mediaservices/qt7/qt7playermetadata.mm b/src/plugins/mediaservices/qt7/qt7playermetadata.mm deleted file mode 100644 index 96b7a68..0000000 --- a/src/plugins/mediaservices/qt7/qt7playermetadata.mm +++ /dev/null @@ -1,261 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 "qt7backend.h" -#include "qt7playermetadata.h" -#include "qt7playersession.h" -#include - -#import - -#ifdef QUICKTIME_C_API_AVAILABLE - #include - #undef check // avoid name clash; -#endif - -QT_BEGIN_NAMESPACE - -QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) - :QMetaDataControl(parent), m_session(session) -{ -} - -QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() -{ -} - -bool QT7PlayerMetaDataControl::isMetaDataAvailable() const -{ - return !m_tags.isEmpty(); -} - -bool QT7PlayerMetaDataControl::isWritable() const -{ - return false; -} - -QVariant QT7PlayerMetaDataControl::metaData(QtMedia::MetaData key) const -{ - return m_tags.value(key); -} - -void QT7PlayerMetaDataControl::setMetaData(QtMedia::MetaData key, QVariant const &value) -{ - Q_UNUSED(key); - Q_UNUSED(value); -} - -QList QT7PlayerMetaDataControl::availableMetaData() const -{ - return m_tags.keys(); -} - -QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const -{ - Q_UNUSED(key); - return QVariant(); -} - -void QT7PlayerMetaDataControl::setExtendedMetaData(const QString &key, QVariant const &value) -{ - Q_UNUSED(key); - Q_UNUSED(value); -} - -QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const -{ - return QStringList(); -} - -#ifdef QUICKTIME_C_API_AVAILABLE - -static QString stripCopyRightSymbol(const QString &key) -{ - return key.right(key.length()-1); -} - -static QString convertQuickTimeKeyToUserKey(const QString &key) -{ - if (key == QLatin1String("com.apple.quicktime.displayname")) - return QLatin1String("nam"); - else if (key == QLatin1String("com.apple.quicktime.album")) - return QLatin1String("alb"); - else if (key == QLatin1String("com.apple.quicktime.artist")) - return QLatin1String("ART"); - else - return QLatin1String("???"); -} - -static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, - QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) -{ - QTPropertyValueType type; - ByteCount propSize; - UInt32 propFlags; - OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); - - - *value = malloc(propSize); - - err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); - - if (type == 'code' || type == 'itsk' || type == 'itlk') { - // convert from native endian to big endian - OSTypePtr pType = (OSTypePtr)*value; - *pType = EndianU32_NtoB(*pType); - } - - return err; -} - -static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) -{ - QTPropertyValuePtr value = 0; - ByteCount ignore = 0; - OSStatus err = readMetaValue( - metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); - - UInt32 type = *((UInt32 *) value); - if (value) - free(value); - return type; -} - -static QString cFStringToQString(CFStringRef str) -{ - if(!str) - return QString(); - CFIndex length = CFStringGetLength(str); - const UniChar *chars = CFStringGetCharactersPtr(str); - if (chars) - return QString(reinterpret_cast(chars), length); - - QVarLengthArray buffer(length); - CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); - return QString(reinterpret_cast(buffer.constData()), length); -} - - -static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) -{ - QTPropertyValuePtr value = 0; - ByteCount size = 0; - OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); - - QString string; - UInt32 dataType = getMetaType(metaDataRef, item); - switch (dataType){ - case kQTMetaDataTypeUTF8: - case kQTMetaDataTypeMacEncodedText: - string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); - break; - case kQTMetaDataTypeUTF16BE: - string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); - break; - default: - break; - } - - if (value) - free(value); - return string; -} - - -static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap &result) -{ - QTMetaDataItem item = kQTMetaDataItemUninitialized; - OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); - while (err == noErr){ - QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); - if (format == kQTMetaDataStorageFormatQuickTime) - key = convertQuickTimeKeyToUserKey(key); - else - key = stripCopyRightSymbol(key); - - if (!result.contains(key)){ - QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); - result.insert(key, val); - } - err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); - } -} -#endif - - -void QT7PlayerMetaDataControl::updateTags() -{ - bool wasEmpty = m_tags.isEmpty(); - m_tags.clear(); - - QTMovie *movie = (QTMovie*)m_session->movie(); - - if (movie) { - QMultiMap metaMap; - -#ifdef QUICKTIME_C_API_AVAILABLE - QTMetaDataRef metaDataRef; - OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); - - readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); - readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); - readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); -#else - NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; - metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); -#endif // QUICKTIME_C_API_AVAILABLE - - m_tags.insert(QtMedia::AlbumArtist, metaMap.value(QLatin1String("ART"))); - m_tags.insert(QtMedia::AlbumTitle, metaMap.value(QLatin1String("alb"))); - m_tags.insert(QtMedia::Title, metaMap.value(QLatin1String("nam"))); - m_tags.insert(QtMedia::Date, metaMap.value(QLatin1String("day"))); - m_tags.insert(QtMedia::Genre, metaMap.value(QLatin1String("gnre"))); - m_tags.insert(QtMedia::TrackNumber, metaMap.value(QLatin1String("trk"))); - m_tags.insert(QtMedia::Description, metaMap.value(QLatin1String("des"))); - } - - if (!wasEmpty || !m_tags.isEmpty()) - emit metaDataChanged(); -} - -QT_END_NAMESPACE - -#include "moc_qt7playermetadata.cpp" diff --git a/src/plugins/mediaservices/qt7/qt7playerservice.h b/src/plugins/mediaservices/qt7/qt7playerservice.h deleted file mode 100644 index d4b30b8..0000000 --- a/src/plugins/mediaservices/qt7/qt7playerservice.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 QT7PLAYERSERVICE_H -#define QT7PLAYERSERVICE_H - -#include -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QMediaMetaData; -class QMediaPlayerControl; -class QMediaPlaylist; -class QMediaPlaylistNavigator; -class QT7PlayerControl; -class QT7PlayerMetaDataControl; -class QT7VideoOutputControl; -class QT7VideoWindowControl; -class QT7VideoWidgetControl; -class QT7VideoRendererControl; -class QT7VideoOutput; -class QT7PlayerSession; - -class QT7PlayerService : public QMediaService -{ -Q_OBJECT -public: - QT7PlayerService(QObject *parent = 0); - ~QT7PlayerService(); - - QMediaControl *control(const char *name) const; - -private slots: - void updateVideoOutput(); - -private: - QT7PlayerSession *m_session; - QT7PlayerControl *m_control; - QT7VideoOutputControl *m_videoOutputControl; - QT7VideoWindowControl *m_videoWidnowControl; - QT7VideoWidgetControl *m_videoWidgetControl; - QT7VideoRendererControl *m_videoRendererControl; - QT7PlayerMetaDataControl *m_playerMetaDataControl; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/mediaservices/qt7/qt7playerservice.mm b/src/plugins/mediaservices/qt7/qt7playerservice.mm deleted file mode 100644 index df15fa8..0000000 --- a/src/plugins/mediaservices/qt7/qt7playerservice.mm +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 -#include -#include - -#include "qt7backend.h" -#include "qt7playerservice.h" -#include "qt7playercontrol.h" -#include "qt7playersession.h" -#include "qt7videooutputcontrol.h" -#include "qt7movieviewoutput.h" -#include "qt7movieviewrenderer.h" -#include "qt7movierenderer.h" -#include "qt7movievideowidget.h" -#include "qt7playermetadata.h" - -#include -#include - -QT_BEGIN_NAMESPACE - -QT7PlayerService::QT7PlayerService(QObject *parent): - QMediaService(parent) -{ - m_session = new QT7PlayerSession; - - m_control = new QT7PlayerControl(this); - m_control->setSession(m_session); - - m_playerMetaDataControl = new QT7PlayerMetaDataControl(m_session, this); - connect(m_control, SIGNAL(mediaChanged(QMediaContent)), m_playerMetaDataControl, SLOT(updateTags())); - - m_videoOutputControl = new QT7VideoOutputControl(this); - - m_videoWidnowControl = 0; - m_videoWidgetControl = 0; - m_videoRendererControl = 0; - -#if defined(QT_MAC_USE_COCOA) - m_videoWidnowControl = new QT7MovieViewOutput(this); - m_videoOutputControl->enableOutput(QVideoOutputControl::WindowOutput); - qDebug() << "Using cocoa"; -#endif - -#ifdef QUICKTIME_C_API_AVAILABLE - m_videoRendererControl = new QT7MovieRenderer(this); - m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); - - m_videoWidgetControl = new QT7MovieVideoWidget(this); - m_videoOutputControl->enableOutput(QVideoOutputControl::WidgetOutput); - qDebug() << "QuickTime C API is available"; -#else - m_videoRendererControl = new QT7MovieViewRenderer(this); - m_videoOutputControl->enableOutput(QVideoOutputControl::RendererOutput); - qDebug() << "QuickTime C API is not available"; -#endif - - - connect(m_videoOutputControl, SIGNAL(videoOutputChanged(QVideoOutputControl::Output)), - this, SLOT(updateVideoOutput())); -} - -QT7PlayerService::~QT7PlayerService() -{ -} - -QMediaControl *QT7PlayerService::control(const char *name) const -{ - if (qstrcmp(name, QMediaPlayerControl_iid) == 0) - return m_control; - - if (qstrcmp(name, QVideoOutputControl_iid) == 0) - return m_videoOutputControl; - - if (qstrcmp(name, QVideoWindowControl_iid) == 0) - return m_videoWidnowControl; - - if (qstrcmp(name, QVideoRendererControl_iid) == 0) - return m_videoRendererControl; - - if (qstrcmp(name, QVideoWidgetControl_iid) == 0) - return m_videoWidgetControl; - - if (qstrcmp(name, QMetaDataControl_iid) == 0) - return m_playerMetaDataControl; - - return 0; -} - -void QT7PlayerService::updateVideoOutput() -{ - qDebug() << "QT7PlayerService::updateVideoOutput" << m_videoOutputControl->output(); - - switch (m_videoOutputControl->output()) { - case QVideoOutputControl::WindowOutput: - m_session->setVideoOutput(m_videoWidnowControl); - break; - case QVideoOutputControl::RendererOutput: - m_session->setVideoOutput(m_videoRendererControl); - break; - case QVideoOutputControl::WidgetOutput: - m_session->setVideoOutput(m_videoWidgetControl); - break; - default: - m_session->setVideoOutput(0); - } -} - -QT_END_NAMESPACE - -#include "moc_qt7playerservice.cpp" diff --git a/src/plugins/mediaservices/qt7/qt7playersession.h b/src/plugins/mediaservices/qt7/qt7playersession.h deleted file mode 100644 index 55505ee..0000000 --- a/src/plugins/mediaservices/qt7/qt7playersession.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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 QT7PLAYERSESSION_H -#define QT7PLAYERSESSION_H - -#include -#include - -#include -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QT7PlayerControl; -class QMediaPlaylist; -class QMediaPlaylistNavigator; -class QT7VideoOutput; -class QT7PlayerSession; -class QT7PlayerService; - -class QT7PlayerSession : public QObject -{ -Q_OBJECT -public: - QT7PlayerSession(QObject *parent = 0); - ~QT7PlayerSession(); - - void *movie() const; - - void setControl(QT7PlayerControl *control); - void setVideoOutput(QT7VideoOutput *output); - - QMediaPlayer::State state() const; - QMediaPlayer::MediaStatus mediaStatus() const; - - QMediaContent media() const; - const QIODevice *mediaStream() const; - void setMedia(const QMediaContent &content, QIODevice *stream); - - qint64 position() const; - qint64 duration() const; - - int bufferStatus() const; - - int volume() const; - bool isMuted() const; - - bool isVideoAvailable() const; - - bool isSeekable() const; - - qreal playbackRate() const; - void setPlaybackRate(qreal rate); - - void setPosition(qint64 pos); - - void play(); - void pause(); - void stop(); - - void setVolume(int volume); - void setMuted(bool muted); - - void processEOS(); - -signals: - void positionChanged(qint64 position); - void durationChanged(qint64 duration); - void stateChanged(QMediaPlayer::State newState); - void mediaStatusChanged(QMediaPlayer::MediaStatus status); - void volumeChanged(int volume); - void mutedChanged(bool muted); - void videoAvailableChanged(bool videoAvailable); - void error(int error, const QString &errorString); - -private: - void *m_QTMovie; - void *m_movieObserver; - - QMediaPlayer::State m_state; - QMediaPlayer::MediaStatus m_mediaStatus; - QIODevice *m_mediaStream; - QMediaContent m_resources; - - QT7VideoOutput *m_videoOutput; - - mutable qint64 m_currentTime; - - bool m_muted; - int m_volume; - qreal m_rate; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/plugins/mediaservices/qt7/qt7playersession.mm b/src/plugins/mediaservices/qt7/qt7playersession.mm deleted file mode 100644 index 3131a90..0000000 --- a/src/plugins/mediaservices/qt7/qt7playersession.mm +++ /dev/null @@ -1,402 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins 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$ -** -****************************************************************************/ - -#import -#import - -#include "qt7backend.h" - -#include "qt7playersession.h" -#include "qt7playercontrol.h" -#include "qt7videooutputcontrol.h" - -#include - -#include - -#include -#include - - -QT_BEGIN_NAMESPACE - -@interface QTMovieObserver : NSObject -{ -@private - QT7PlayerSession *m_session; - QTMovie *m_movie; -} - -- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; -- (void) setMovie:(QTMovie *)movie; -- (void) processEOS:(NSNotification *)notification; -@end - -@implementation QTMovieObserver - -- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session -{ - if (!(self = [super init])) - return nil; - - self->m_session = session; - return self; -} - -- (void) setMovie:(QTMovie *)movie -{ - if (m_movie == movie) - return; - - if (m_movie) { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [m_movie release]; - } - - m_movie = movie; - - if (movie) { - [[NSNotificationCenter defaultCenter] addObserver: self selector: - @selector(processEOS:) name: QTMovieDidEndNotification object: m_movie]; - - [movie retain]; - } -} - -- (void) processEOS:(NSNotification *)notification -{ - Q_UNUSED(notification); - m_session->processEOS(); -} - -@end - -static CFStringRef qString2CFStringRef(const QString &string) -{ - return CFStringCreateWithCharacters(0, reinterpret_cast(string.unicode()), - string.length()); -} - -QT7PlayerSession::QT7PlayerSession(QObject *parent) - : QObject(parent) - , m_QTMovie(0) - , m_state(QMediaPlayer::StoppedState) - , m_mediaStatus(QMediaPlayer::NoMedia) - , m_mediaStream(0) - , m_videoOutput(0) - , m_muted(false) - , m_volume(100) - , m_rate(1.0) -{ - m_movieObserver = [[QTMovieObserver alloc] initWithPlayerSession:this]; -} - -QT7PlayerSession::~QT7PlayerSession() -{ - [(QTMovieObserver*)m_movieObserver setMovie:nil]; - [(QTMovieObserver*)m_movieObserver release]; -} - -void *QT7PlayerSession::movie() const -{ - return m_QTMovie; -} - -void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) -{ - if (m_videoOutput == output) - return; - - qDebug() << "set output" << output; - - if (m_videoOutput) { - m_videoOutput->setEnabled(false); - m_videoOutput->setMovie(0); - } - - m_videoOutput = output; - - if (m_videoOutput) { - m_videoOutput->setEnabled(m_QTMovie != 0); - m_videoOutput->setMovie(m_QTMovie); - } -} - - -qint64 QT7PlayerSession::position() const -{ - if (!m_QTMovie || m_state == QMediaPlayer::PausedState) - return m_currentTime; - - AutoReleasePool pool; - - QTTime qtTime = [(QTMovie*)m_QTMovie currentTime]; - quint64 t = static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); - m_currentTime = t; - - return m_currentTime; -} - -qint64 QT7PlayerSession::duration() const -{ - if (!m_QTMovie) - return 0; - - AutoReleasePool pool; - - QTTime qtTime = [(QTMovie*)m_QTMovie duration]; - - return static_cast(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); -} - -QMediaPlayer::State QT7PlayerSession::state() const -{ - return m_state; -} - -QMediaPlayer::MediaStatus QT7PlayerSession::mediaStatus() const -{ - return m_mediaStatus; -} - -int QT7PlayerSession::bufferStatus() const -{ - return 100; -} - -int QT7PlayerSession::volume() const -{ - return m_volume; -} - -bool QT7PlayerSession::isMuted() const -{ - return m_muted; -} - -bool QT7PlayerSession::isSeekable() const -{ - return true; -} - -qreal QT7PlayerSession::playbackRate() const -{ - return m_rate; -} - -void QT7PlayerSession::setPlaybackRate(qreal rate) -{ - if (qFuzzyCompare(m_rate, rate)) - return; - - m_rate = rate; - - if (m_QTMovie && m_state == QMediaPlayer::PlayingState) { - float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; - [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; - } -} - -void QT7PlayerSession::setPosition(qint64 pos) -{ - if ( !isSeekable() || pos == position()) - return; - - AutoReleasePool pool; - - pos = qMin(pos, duration()); - - QTTime newQTTime = [(QTMovie*)m_QTMovie currentTime]; - newQTTime.timeValue = (pos / 1000.0f) * newQTTime.timeScale; - [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; -} - -void QT7PlayerSession::play() -{ - m_state = QMediaPlayer::PlayingState; - - float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; - [(QTMovie*)m_QTMovie setRate:preferredRate*m_rate]; - - emit stateChanged(m_state); -} - -void QT7PlayerSession::pause() -{ - m_state = QMediaPlayer::PausedState; - - [(QTMovie*)m_QTMovie setRate:0]; - - emit stateChanged(m_state); -} - -void QT7PlayerSession::stop() -{ - m_state = QMediaPlayer::StoppedState; - - [(QTMovie*)m_QTMovie setRate:0]; - setPosition(0); - - if (m_state == QMediaPlayer::StoppedState) - emit stateChanged(m_state); -} - -void QT7PlayerSession::setVolume(int volume) -{ - if (m_QTMovie) { - m_volume = volume; - [(QTMovie*)m_QTMovie setVolume:(volume/100.0f)]; - } -} - -void QT7PlayerSession::setMuted(bool muted) -{ - if (m_muted != muted) { - m_muted = muted; - - if (m_QTMovie) - [(QTMovie*)m_QTMovie setMuted:m_muted]; - - emit mutedChanged(muted); - } -} - -QMediaContent QT7PlayerSession::media() const -{ - return m_resources; -} - -const QIODevice *QT7PlayerSession::mediaStream() const -{ - return m_mediaStream; -} - -void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) -{ - AutoReleasePool pool; - - if (m_QTMovie) { - [(QTMovieObserver*)m_movieObserver setMovie:nil]; - - if (m_videoOutput) { - m_videoOutput->setEnabled(false); - m_videoOutput->setMovie(0); - } - - [(QTMovie*)m_QTMovie release]; - m_QTMovie = 0; - } - - m_resources = content; - m_mediaStream = stream; - - QUrl url; - - if (!content.isNull()) - url = content.canonicalUrl(); - else - return; - - NSError *err = 0; - QTDataReference *dataRef = 0; - - if ( url.scheme() == "file" ) { - NSString *nsFileName = (NSString *)qString2CFStringRef( url.toLocalFile() ); - dataRef = [QTDataReference dataReferenceWithReferenceToFile:nsFileName]; - } else { - NSString *urlString = (NSString *)qString2CFStringRef( url.toString() ); - NSURL *url = [NSURL URLWithString: urlString]; - dataRef = [QTDataReference dataReferenceWithReferenceToURL:url]; - } - - NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys: - dataRef, QTMovieDataReferenceAttribute, - [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, - [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, - [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, - [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, - nil]; - - m_QTMovie = [[QTMovie movieWithAttributes:attr error:&err] retain]; - - if (err) { - [(QTMovie*)m_QTMovie release]; - m_QTMovie = 0; - QString description = QString::fromUtf8([[err localizedDescription] UTF8String]); - - qDebug() << "QT7PlayerSession::setMedia error" << description; - emit error(QMediaPlayer::FormatError, description ); - } else { - [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; - - if (m_videoOutput) { - m_videoOutput->setEnabled(true); - m_videoOutput->setMovie(m_QTMovie); - } - - emit durationChanged(duration()); - emit videoAvailableChanged(isVideoAvailable()); - - [(QTMovie*)m_QTMovie setMuted:m_muted]; - setVolume(m_volume); - } -} - -bool QT7PlayerSession::isVideoAvailable() const -{ - if (!m_QTMovie) - return false; - - AutoReleasePool pool; - return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES; -} - -void QT7PlayerSession::processEOS() -{ - m_mediaStatus = QMediaPlayer::EndOfMedia; - emit stateChanged(m_state = QMediaPlayer::StoppedState); - emit mediaStatusChanged(m_mediaStatus); -} - -#include "moc_qt7playersession.cpp" - -QT_END_NAMESPACE - diff --git a/src/plugins/mediaservices/qt7/qt7serviceplugin.mm b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm index 49ae8e0..3e2a2a6 100644 --- a/src/plugins/mediaservices/qt7/qt7serviceplugin.mm +++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm @@ -51,16 +51,20 @@ QT_BEGIN_NAMESPACE QStringList QT7ServicePlugin::keys() const { - return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); + return QStringList() +#ifdef Q_MEDIASERVICE_MEDIAPLAYER_AVAILABLE + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); +#endif } QMediaService* QT7ServicePlugin::create(QString const& key) { - qDebug() << "QT7ServicePlugin::create" << key; +#ifdef Q_MEDIASERVICE_MEDIAPLAYER_AVAILABLE if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) return new QT7PlayerService; +#endif - qDebug() << "unsupported key:" << key; + qWarning() << "Attempt to create unknown service with key" << key; return 0; } -- cgit v0.12 From 7574328b1bdfb5d7d34aa2428cb5dc623f19f4aa Mon Sep 17 00:00:00 2001 From: Nicholas Young Date: Tue, 19 Jan 2010 15:47:26 +1000 Subject: Added QtMultimedia audio/video to Webkit. Affects HTML5 Audio/Video --- src/3rdparty/webkit/WebCore/WebCore.pro | 28 +- .../WebCore/platform/graphics/MediaPlayer.cpp | 2 +- .../platform/graphics/qt/MediaPlayerPrivateQt.cpp | 583 +++++++++++++++++++++ .../platform/graphics/qt/MediaPlayerPrivateQt.h | 110 ++++ 4 files changed, 705 insertions(+), 18 deletions(-) create mode 100644 src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp create mode 100644 src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index 3eba696..614a32a 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -155,8 +155,8 @@ contains(DEFINES, ENABLE_SINGLE_THREADED=1) { # HTML5 media support !contains(DEFINES, ENABLE_VIDEO=.) { - contains(QT_CONFIG, phonon):DEFINES += ENABLE_VIDEO=1 - else:DEFINES += ENABLE_VIDEO=0 + contains(QT_CONFIG, multimedia): DEFINES += ENABLE_VIDEO=1 + else: DEFINES += ENABLE_VIDEO=0 } # HTML5 datalist support @@ -2721,23 +2721,17 @@ contains(DEFINES, ENABLE_VIDEO=1) { rendering/RenderMedia.cpp \ bindings/js/JSAudioConstructor.cpp - HEADERS += \ - platform/graphics/qt/MediaPlayerPrivatePhonon.h + INCLUDEPATH += \ + $$PWD/../../../multimedia/base - SOURCES += \ - platform/graphics/qt/MediaPlayerPrivatePhonon.cpp - - # Add phonon manually to prevent it from coming first in - # the include paths, as Phonon's path.h conflicts with - # WebCore's Path.h on case-insensitive filesystems. - qtAddLibrary(phonon) - INCLUDEPATH -= $$QMAKE_INCDIR_QT/phonon - INCLUDEPATH += $$QMAKE_INCDIR_QT/phonon - mac { - INCLUDEPATH -= $$QMAKE_LIBDIR_QT/phonon.framework/Headers - INCLUDEPATH += $$QMAKE_LIBDIR_QT/phonon.framework/Headers - } + HEADERS += \ + platform/graphics/qt/MediaPlayerPrivateQt.h + + SOURCES += \ + platform/graphics/qt/MediaPlayerPrivateQt.cpp + QT += multimedia + contains(QT_CONFIG, opengl): QT += opengl } contains(DEFINES, ENABLE_XPATH=1) { diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp index 3b32b65..07232fd 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp @@ -46,7 +46,7 @@ #elif PLATFORM(GTK) #include "MediaPlayerPrivateGStreamer.h" #elif PLATFORM(QT) -#include "MediaPlayerPrivatePhonon.h" +#include "MediaPlayerPrivateQt.h" #elif PLATFORM(CHROMIUM) #include "MediaPlayerPrivateChromium.h" #endif diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp new file mode 100644 index 0000000..967e125 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -0,0 +1,583 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2009 Apple Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "MediaPlayerPrivateQt.h" + +#include + +// WebCore Includes +#include "CString.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "TimeRanges.h" +#include "Widget.h" + +// WebKit Includes +#include + +// Qt Includes +#include +#include +#include +#include +#include +#include + +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) +#include +#endif + +// Qt Multimedia Includes +#include +#include +#include +#include + + +//#define QT_WEBKIT_MEDIA_INSTRUMENTATION + +using namespace WTF; + +namespace WebCore { + +#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION +class MediaPlayerPrivateInstrumentation +{ +public: + MediaPlayerPrivateInstrumentation() + : update(false) + , frameCount(0) + , paintTimeTotal(0) + , framesPerSecond(0) + , averagePaintTime(0) + , preTime(QTime()) + , lastUpdate(QTime::currentTime()) {} + + void prePaint() { preTime = QTime::currentTime(); } + + void postPaint() + { + QTime time = QTime::currentTime(); + + // Measure seconds different + int paintTime = (time.second() - preTime.second() - 1) * 1000; + paintTime = qMax(0, paintTime); + + // Measure milliseconds different + if(time.msec() < preTime.msec()) + paintTime += time.msec() + (1000 - preTime.msec()); + else + paintTime += time.msec() - preTime.msec(); + + // Add to the total paint time for this second + paintTimeTotal += paintTime; + + // Check for update time + if(time.second() != lastUpdate.second()) { + // Calculate Values + framesPerSecond = frameCount; + averagePaintTime = static_cast(paintTimeTotal) / static_cast(frameCount); + + // Next Update + update = true; + frameCount = 1; + paintTimeTotal = 0; + lastUpdate = time; + } else { + frameCount++; + } + } + + bool updateAvailable() { return update; } + + int fps() { update = false; return framesPerSecond; } + qreal paintTime() { update = false; return averagePaintTime; } + +private: + bool update; + + int frameCount; + qint64 paintTimeTotal; + + int framesPerSecond; + qreal averagePaintTime; + + QTime preTime; + QTime lastUpdate; +}; +#endif // QT_WEBKIT_MEDIA_INSTRUMENTATION + +class MediaPlayerPrivateDefault : public MediaPlayerPrivate { +public: + IntSize naturalSize() const; + void setSize(const IntSize&) {} + void paint(GraphicsContext*, const IntRect&); + bool supportsFullscreen() const { return true; } + +private slots: + void repaint(); + +private: + friend class MediaPlayerPrivate; + MediaPlayerPrivateDefault(MediaPlayer*); + ~MediaPlayerPrivateDefault(); + + QPainterVideoSurface* m_videoSurface; + QVideoOutputControl* m_outputControl; + QVideoRendererControl* m_rendererControl; + + bool m_isActive; + +#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION + MediaPlayerPrivateInstrumentation* m_instruments; +#endif +}; + +MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +{ + return new MediaPlayerPrivateDefault(player); +} + +void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +{ + registrar(create, getSupportedTypes, supportsType); +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet &supported) +{ + QStringList types = QMediaPlayer::supportedMimeTypes(); + + for (int i = 0; i < types.size(); i++) { + supported.add(types.at(i)); + } +} + +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, const String& codec) +{ + if(QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMedia::ProbablySupported) { + return MediaPlayer::IsSupported; + } + + return MediaPlayer::MayBeSupported; +} + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_mediaPlayer(new QMediaPlayer) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::HaveNothing) + , m_isVisible(false) + , m_endTime(std::numeric_limits::max()) +{ + // Signal Handlers + connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SLOT(stateChanged(QMediaPlayer::State))); + connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), + this, SLOT(handleError(QMediaPlayer::Error))); + connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)), + this, SLOT(durationChanged(qint64))); + connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)), + this, SLOT(positionChanged(qint64))); + + // Grab the player control + if (m_mediaPlayer) { + QMediaService *service = m_mediaPlayer->service(); + if (service) { + m_mediaPlayerControl = qobject_cast( + service->control(QMediaPlayerControl_iid)); + } + } +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + delete m_mediaPlayer; + m_mediaPlayer = 0; +} + +bool MediaPlayerPrivate::hasVideo() const +{ + return m_mediaPlayer->isVideoAvailable(); +} + +bool MediaPlayerPrivate::hasAudio() const +{ + return true; +} + +void MediaPlayerPrivate::load(const String& url) +{ + // We are now loading + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + + // And we don't have any data yet + if (m_readyState != MediaPlayer::HaveNothing) { + m_readyState = MediaPlayer::HaveNothing; + m_player->readyStateChanged(); + } + + m_mediaPlayer->setMedia(QUrl(url)); +} + +void MediaPlayerPrivate::cancelLoad() +{ + m_mediaPlayer->setMedia(QMediaContent()); + updateStates(); +} + +void MediaPlayerPrivate::play() +{ + if(m_mediaPlayer->state() != QMediaPlayer::PlayingState) { + m_mediaPlayer->play(); + } +} + +void MediaPlayerPrivate::pause() +{ + if(m_mediaPlayer->state() == QMediaPlayer::PlayingState) { + m_mediaPlayer->pause(); + } +} + +bool MediaPlayerPrivate::paused() const +{ + return m_mediaPlayer->state() != QMediaPlayer::PlayingState; +} + +void MediaPlayerPrivate::seek(float position) +{ + if (!m_mediaPlayer->isSeekable()) + return; + + if (m_mediaPlayerControl != 0 && + !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000)) + return; + + if (position > duration()) + position = duration(); + + m_mediaPlayer->setPosition(position * 1000.0f); +} + +bool MediaPlayerPrivate::seeking() const +{ + return false; +} + +void MediaPlayerPrivate::setEndTime(float time) +{ + // Set the end time in milliseconds + m_endTime = static_cast(time * 1000.0f); + + // Duration may return a smaller value as of now + m_player->durationChanged(); +} + +float MediaPlayerPrivate::duration() const +{ + if (m_readyState < MediaPlayer::HaveMetadata) + return 0.0f; + + float duration = qMin(m_mediaPlayer->duration(), m_endTime) / 1000.0f; + + // We are streaming + if (duration <= 0.0f) + duration = std::numeric_limits::infinity(); + + return duration; +} + +float MediaPlayerPrivate::currentTime() const +{ + float currentTime = m_mediaPlayer->position() / 1000.0f; + return currentTime; +} + +PassRefPtr MediaPlayerPrivate::buffered() const +{ + RefPtr buffered = TimeRanges::create(); + + if(m_mediaPlayerControl == 0) + return buffered; + + QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges(); + + foreach(const QMediaTimeInterval interval, playbackRanges.intervals()) { + float rangeMin = static_cast(interval.start()) / 1000.0f; + float rangeMax = static_cast(interval.end()) / 1000.0f; + buffered->add(rangeMin, rangeMax); + } + + return buffered.release(); +} + +float MediaPlayerPrivate::maxTimeSeekable() const +{ + if(m_mediaPlayerControl == 0) + return 0; + + return static_cast(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f; +} + +unsigned MediaPlayerPrivate::bytesLoaded() const +{ + unsigned percentage = m_mediaPlayer->bufferStatus(); + + if(percentage == 100) { + if(m_networkState != MediaPlayer::Idle) { + m_networkState = MediaPlayer::Idle; + m_player->networkStateChanged(); + } + if(m_readyState != MediaPlayer::HaveEnoughData) { + m_readyState = MediaPlayer::HaveEnoughData; + m_player->readyStateChanged(); + } + } + + QLatin1String blKey("bytes-loaded"); + if(m_mediaPlayer->availableExtendedMetaData().contains(blKey)) + return m_mediaPlayer->extendedMetaData(blKey).toInt(); + + return percentage; +} + +unsigned MediaPlayerPrivate::totalBytes() const +{ + if(m_mediaPlayer->availableMetaData().contains(QtMedia::Size)) + return m_mediaPlayer->metaData(QtMedia::Size).toInt(); + + return 100; +} + +bool MediaPlayerPrivate::totalBytesKnown() const +{ + return m_mediaPlayer->availableMetaData().contains(QtMedia::Size); +} + +void MediaPlayerPrivate::setRate(float rate) +{ + m_mediaPlayer->setPlaybackRate(rate); +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + m_mediaPlayer->setVolume(static_cast(volume * 100.0)); +} + +void MediaPlayerPrivate::setMuted(bool muted) +{ + m_mediaPlayer->setMuted(muted); +} + +int MediaPlayerPrivate::dataRate() const +{ + return 0; +} + +MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +{ + return m_networkState; +} + +MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +{ + return m_readyState; +} + +void MediaPlayerPrivate::setVisible(bool visible) +{ + m_isVisible = visible; +} + +void MediaPlayerPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus) +{ + updateStates(); +} + +void MediaPlayerPrivate::handleError(QMediaPlayer::Error) +{ + updateStates(); +} + +void MediaPlayerPrivate::durationChanged(qint64) +{ + m_player->durationChanged(); +} + +void MediaPlayerPrivate::updateStates() +{ + // Store the old states so that we can detect a change and raise change events + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus(); + QMediaPlayer::Error currentError = m_mediaPlayer->error(); + + if(currentError != QMediaPlayer::NoError) { + m_readyState = MediaPlayer::HaveNothing; + if(currentError == QMediaPlayer::FormatError) { + m_networkState = MediaPlayer::FormatError; + } else { + // ResourceError, NetworkError, AccessDeniedError, ServiceMissingError + m_networkState = MediaPlayer::NetworkError; + } + } else if(currentStatus == QMediaPlayer::UnknownMediaStatus || + currentStatus == QMediaPlayer::NoMedia) { + m_networkState = MediaPlayer::Idle; + m_readyState = MediaPlayer::HaveNothing; + } else if(currentStatus == QMediaPlayer::LoadingMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveNothing; + } else if(currentStatus == QMediaPlayer::LoadedMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveMetadata; + } else if(currentStatus == QMediaPlayer::BufferingMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveFutureData; + } else if(currentStatus == QMediaPlayer::StalledMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveCurrentData; + } else if(currentStatus == QMediaPlayer::BufferedMedia || + currentStatus == QMediaPlayer::EndOfMedia) { + m_networkState = MediaPlayer::Idle; + m_readyState = MediaPlayer::HaveEnoughData; + } else if(currentStatus == QMediaPlayer::InvalidMedia) { + m_networkState = MediaPlayer::FormatError; + m_readyState = MediaPlayer::HaveMetadata; + } + + // Log the state changes and raise the state change events + if (m_networkState != oldNetworkState) { + m_player->networkStateChanged(); + } + + if (m_readyState != oldReadyState) { + m_player->readyStateChanged(); + } +} + +MediaPlayerPrivateDefault::MediaPlayerPrivateDefault(MediaPlayer *player) + : MediaPlayerPrivate(player) + , m_videoSurface(new QPainterVideoSurface(m_mediaPlayer)) +{ +#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION + m_instruments = new MediaPlayerPrivateInstrumentation; +#endif + + if (m_mediaPlayer) { + QMediaService *service = m_mediaPlayer->service(); + if (service) { + m_outputControl = qobject_cast( + service->control(QVideoOutputControl_iid)); + m_rendererControl = qobject_cast( + service->control(QVideoRendererControl_iid)); + + if (m_outputControl != 0 && m_rendererControl != 0) { + connect(m_videoSurface, SIGNAL(frameChanged()), this, SLOT(repaint())); + + m_rendererControl->setSurface(m_videoSurface); + m_outputControl->setOutput(QVideoOutputControl::RendererOutput); + } + } + } +} + +MediaPlayerPrivateDefault::~MediaPlayerPrivateDefault() +{ +#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION + delete m_instruments; + m_instruments = 0; +#endif +} + +IntSize MediaPlayerPrivateDefault::naturalSize() const +{ + if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) + return IntSize(); + + QSize videoSize = m_videoSurface->surfaceFormat().sizeHint(); + return IntSize(videoSize.width(), videoSize.height()); +} + +void MediaPlayerPrivateDefault::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + if (!m_isVisible) + return; + +#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION + m_instruments->prePaint(); +#endif + + // Grab the painter + QPainter* painter = context->platformContext(); + + if(!m_isActive) { + // Attempt GL Setup +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + if ((painter->paintEngine()->type() == QPaintEngine::OpenGL || + painter->paintEngine()->type() == QPaintEngine::OpenGL2)) { + // Set GL Context + m_videoSurface->setGLContext(const_cast(QGLContext::currentContext())); + + // Check Shader Types + if (m_videoSurface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + m_videoSurface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + m_videoSurface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } + } +#endif + + // Setup Completed + m_isActive = true; + } + + // Paint the frame + m_videoSurface->paint(painter, QRect(rect.x(), rect.y(), + rect.width(), rect.height())); + m_videoSurface->setReady(true); + + #ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION + m_instruments->postPaint(); + + if(m_instruments->updateAvailable()) { + qDebug("FPS: %d, Average Paint Time: %f", m_instruments->fps(), m_instruments->paintTime()); + } + #endif +} + +void MediaPlayerPrivateDefault::repaint() +{ + m_player->repaint(); +} + +} // namespace WebCore + +#include "moc_MediaPlayerPrivateQt.cpp" diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h new file mode 100644 index 0000000..f2d4040 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2009 Apple Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MediaPlayerPrivateQt_h +#define MediaPlayerPrivateQt_h + +#include "MediaPlayerPrivate.h" +#include +#include +#include + +namespace WebCore { + + class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface { + + Q_OBJECT + + public: + static MediaPlayerPrivateInterface* create(MediaPlayer* player); + virtual ~MediaPlayerPrivate(); + + static void registerMediaEngine(MediaEngineRegistrar); + static void getSupportedTypes(HashSet&); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable() { return true; } + + bool hasVideo() const; + bool hasAudio() const; + + void load(const String &url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + void setMuted(bool); + + // State Information + MediaPlayer::NetworkState networkState() const; + MediaPlayer::ReadyState readyState() const; + + // Network Information + PassRefPtr buffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + unsigned totalBytes() const; + bool totalBytesKnown() const; + int dataRate() const; + + virtual void setVisible(bool); + + virtual IntSize naturalSize() const = 0; + virtual void setSize(const IntSize&) = 0; + virtual void paint(GraphicsContext*, const IntRect&) = 0; + virtual bool supportsFullscreen() const = 0; + + protected slots: + virtual void mediaStatusChanged(QMediaPlayer::MediaStatus); + virtual void handleError(QMediaPlayer::Error); + virtual void stateChanged(QMediaPlayer::State) {} + virtual void positionChanged(qint64) {} + virtual void durationChanged(qint64); + virtual void repaint() {} + + protected: + MediaPlayerPrivate(MediaPlayer*); + + MediaPlayer* m_player; + QMediaPlayer* m_mediaPlayer; + QMediaPlayerControl* m_mediaPlayerControl; + + mutable MediaPlayer::NetworkState m_networkState; + mutable MediaPlayer::ReadyState m_readyState; + + bool m_isVisible; + qint64 m_endTime; + + private: + void updateStates(); + }; +} + +#endif // MediaPlayerPrivateQt_h -- cgit v0.12 From 665a506fbee9f4c39dfe3b577338815270f090c5 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 19 Jan 2010 11:02:24 +0100 Subject: Optimize speed of QGL2PEXVertexArray This function is the main performance hog when using QStaticText with the OpenGL engine, so I've improved on it a little by removing the conversion from (qreal,qreal) -> QPointF -> QGLPoint. Since the function is called so often, it has an impact on drawStaticText(). --- src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp index 516b847..3f08dbe 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp @@ -63,8 +63,17 @@ QGLRect QGL2PEXVertexArray::boundingRect() const void QGL2PEXVertexArray::addRect(const QRectF &rect) { - vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight() - << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QGLPoint(left, top) + << QGLPoint(right, top) + << QGLPoint(right, bottom) + << QGLPoint(right, bottom) + << QGLPoint(left, bottom) + << QGLPoint(left, top); } void QGL2PEXVertexArray::addClosingLine(int index) -- cgit v0.12 From b28e104cd12f73f5b18244995176f678a9188364 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 19 Jan 2010 14:06:01 +0100 Subject: Inline QGL2PEXVertexArray::addRect() Optimization for drawStaticText() --- src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp | 15 --------------- src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp index 3f08dbe..e454c12 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp @@ -61,21 +61,6 @@ QGLRect QGL2PEXVertexArray::boundingRect() const return QGLRect(minX, minY, maxX, maxY); } -void QGL2PEXVertexArray::addRect(const QRectF &rect) -{ - qreal top = rect.top(); - qreal left = rect.left(); - qreal bottom = rect.bottom(); - qreal right = rect.right(); - - vertexArray << QGLPoint(left, top) - << QGLPoint(right, top) - << QGLPoint(right, bottom) - << QGLPoint(right, bottom) - << QGLPoint(left, bottom) - << QGLPoint(left, top); -} - void QGL2PEXVertexArray::addClosingLine(int index) { if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last())) diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h index e0497b1..ae73040 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h @@ -102,8 +102,22 @@ public: QGL2PEXVertexArray() : maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10), boundingRectDirty(true) {} + + inline void addRect(const QRectF &rect) + { + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QGLPoint(left, top) + << QGLPoint(right, top) + << QGLPoint(right, bottom) + << QGLPoint(right, bottom) + << QGLPoint(left, bottom) + << QGLPoint(left, top); + } - void addRect(const QRectF &rect); void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); void clear(); -- cgit v0.12 From 3c902c0436c68d0c689a813fbef009ac4689b3c4 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 20 Jan 2010 12:41:57 +0100 Subject: Add font object to QStaticText This will be needed by OpenVG paint engine, and is useful elsewhere. --- src/gui/text/qstatictext.cpp | 1 + src/gui/text/qstatictext_p.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 307d2e6..4e8ab9d 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -330,6 +330,7 @@ namespace { 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; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 33d2d39..919589e 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -72,8 +72,9 @@ public: int numGlyphs; // 4 bytes per item int numChars; // 4 bytes per item QFontEngine *fontEngine; // 4 bytes per item + QFont font; // 8 bytes per item // ================ - // 24 bytes per item + // 32 bytes per item }; class QStaticText; -- cgit v0.12 From 20f1d1e7d3178a5fe67e3fd7a8ba80a9fc134a50 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 20 Jan 2010 13:31:38 +0100 Subject: Compile Compile QStaticText and also use font object in QPaintBuffer since it's now available --- src/gui/painting/qpaintbuffer.cpp | 7 ++----- src/gui/text/qstatictext.cpp | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index e0067b0..e41ad57 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -965,9 +965,6 @@ void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) { QString text = QString(staticTextItem->chars, staticTextItem->numChars); - QFontDef fontDef = staticTextItem->fontEngine->fontDef; - QFont font(fontDef.family, fontDef.pointSize, fontDef.weight, fontDef.style == QFont::StyleItalic); - QTransform xform; for (int i=buffer->commands.size()-1; i>=0; --i) { const QPaintBufferCommand &cmd = buffer->commands.at(i); @@ -978,10 +975,10 @@ void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) } QStaticText staticText(text); - staticText.prepare(xform, font); + staticText.prepare(xform, staticTextItem->font); QVariantList variants; - variants << QVariant(font) << QVariant::fromValue(staticText); + variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText); buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants)); } diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 4e8ab9d..db10a03 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -330,7 +330,7 @@ namespace { QStaticTextItem *currentItem = (m_items + (m_itemCount - 1)); currentItem->fontEngine = ti.fontEngine; - currentItem->font = ti.font; + currentItem->font = ti.font(); currentItem->chars = ti.chars; currentItem->numChars = ti.num_chars; currentItem->numGlyphs = ti.glyphs.numGlyphs; -- cgit v0.12 From a16d9ed3f202147b6c315d5e2008c08a3ad909b6 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 26 Jan 2010 13:02:40 +0100 Subject: Attempt at making OpenVG work with QStaticText Done in the blind, so I don't expect this to compile, but it's to make it easier to get it over into a Symbian-ready repository. --- src/openvg/qpaintengine_vg.cpp | 59 ++++++++++++++++++++++++------------------ src/openvg/qpaintengine_vg_p.h | 3 +++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index cc9ba77..9088d66 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -86,10 +87,8 @@ public: QVGFontGlyphCache(); ~QVGFontGlyphCache(); - void cacheGlyphs(QVGPaintEnginePrivate *d, - const QTextItemInt &ti, - const QVarLengthArray &glyphs); - void setScaleFromText(const QTextItemInt &ti); + void cacheGlyphs(QVGPaintEnginePrivate *d, QFontEngine *fontEngine, glyph_t *g, int count); + void setScaleFromText(const QFont &font, QFontEngine *fontEngine); VGFont font; VGfloat scaleX; @@ -3135,22 +3134,20 @@ QVGFontGlyphCache::~QVGFontGlyphCache() vgDestroyFont(font); } -void QVGFontGlyphCache::setScaleFromText(const QTextItemInt &ti) +void QVGFontGlyphCache::setScaleFromText(const QFont &font, QFontEngine *fontEngine) { - QFontInfo fi(ti.font()); + QFontInfo fi(font); qreal pixelSize = fi.pixelSize(); - qreal emSquare = ti.fontEngine->properties().emSquare.toReal(); + qreal emSquare = fontEngine->properties().emSquare.toReal(); scaleX = scaleY = static_cast(pixelSize / emSquare); } void QVGFontGlyphCache::cacheGlyphs - (QVGPaintEnginePrivate *d, const QTextItemInt &ti, - const QVarLengthArray &glyphs) + (QVGPaintEnginePrivate *d, QFontEngine *fontEngine, + glyph_t *g, int count); { VGfloat origin[2]; VGfloat escapement[2]; - const glyph_t *g = glyphs.constData(); - int count = glyphs.size(); glyph_metrics_t metrics; // Some Qt font engines don't set yoff in getUnscaledGlyph(). // Zero the metric structure so that everything has a default value. @@ -3169,9 +3166,9 @@ void QVGFontGlyphCache::cacheGlyphs } #if !defined(QVG_NO_IMAGE_GLYPHS) Q_UNUSED(d); - QImage scaledImage = ti.fontEngine->alphaMapForGlyph(glyph); + QImage scaledImage = fontEngine->alphaMapForGlyph(glyph); VGImage vgImage = VG_INVALID_HANDLE; - metrics = ti.fontEngine->boundingBox(glyph); + metrics = fontEngine->boundingBox(glyph); if (!scaledImage.isNull()) { // Not a space character if (scaledImage.format() == QImage::Format_Indexed8) { vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER); @@ -3195,7 +3192,7 @@ void QVGFontGlyphCache::cacheGlyphs #else // Calculate the path for the glyph and cache it. QPainterPath path; - ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics); + fontEngine->getUnscaledGlyph(glyph, &path, &metrics); VGPath vgPath; if (!path.isEmpty()) { vgPath = d->painterPathToVGPath(path); @@ -3236,8 +3233,25 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) ti.fontEngine->getGlyphPositions (ti.glyphs, matrix, ti.flags, glyphs, positions); + drawCachedGlyphs(glyphs.size(), glyphs.data(), positions.data(), ti.font, ti.fontEngine, p); +#else + // OpenGL 1.0 does not have support for VGFont and glyphs, + // so fall back to the default Qt path stroking algorithm. + QPaintEngineEx::drawTextItem(p, textItem); +#endif +} + +void QVGPaintengine::drawStaticText(QStaticTextItem *textItem) +{ + drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine, + QPointF(0, 0)); +} + + void QVGPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, + QFontEngine *fontEngine, const QPointF &p) + { // Find the glyph cache for this font. - QVGFontCache::ConstIterator it = d->fontCache.constFind(ti.fontEngine); + QVGFontCache::ConstIterator it = d->fontCache.constFind(fontEngine); QVGFontGlyphCache *glyphCache; if (it != d->fontCache.constEnd()) { glyphCache = it.value(); @@ -3249,11 +3263,11 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) QPaintEngineEx::drawTextItem(p, textItem); return; } - glyphCache->setScaleFromText(ti); - d->fontCache.insert(ti.fontEngine, glyphCache); + glyphCache->setScaleFromText(font, fontEngine); + d->fontCache.insert(fontEngine, glyphCache); if (!d->fontEngineCleaner) d->fontEngineCleaner = new QVGFontEngineCleaner(d); - QObject::connect(ti.fontEngine, SIGNAL(destroyed()), + QObject::connect(fontEngine, SIGNAL(destroyed()), d->fontEngineCleaner, SLOT(fontEngineDestroyed())); } @@ -3266,7 +3280,7 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform); // Add the glyphs from the text item into the glyph cache. - glyphCache->cacheGlyphs(d, ti, glyphs); + glyphCache->cacheGlyphs(d, fontEngine, glyphs.constData(), glyphs.size()); // Set the glyph drawing origin. VGfloat origin[2]; @@ -3285,13 +3299,8 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) // Draw the glyphs. We need to fill with the brush associated with // the Qt pen, not the Qt brush. d->ensureBrush(state()->pen.brush()); - vgDrawGlyphs(glyphCache->font, glyphs.size(), (VGuint*)glyphs.data(), + vgDrawGlyphs(glyphCache->font, numGlyphs, (VGuint*)glyphs.data(), NULL, NULL, VG_FILL_PATH, VG_TRUE); -#else - // OpenGL 1.0 does not have support for VGFont and glyphs, - // so fall back to the default Qt path stroking algorithm. - QPaintEngineEx::drawTextItem(p, textItem); -#endif } void QVGPaintEngine::setState(QPainterState *s) diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h index 3f87a72..c70e1c1 100644 --- a/src/openvg/qpaintengine_vg_p.h +++ b/src/openvg/qpaintengine_vg_p.h @@ -139,6 +139,9 @@ public: void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QFlags hints); void drawTextItem(const QPointF &p, const QTextItem &textItem); + void drawStaticTextItem(QStaticTextItem *staticTextItem); + void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, + QFontEngine *fontEngine, const QPointF &p); void setState(QPainterState *s); QVGPainterState *state() { return static_cast(QPaintEngineEx::state()); } -- cgit v0.12 From a5bf01a04d8f18182e9d453ba36facddffc3ba99 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 26 Jan 2010 15:25:09 +0100 Subject: Compile for S60 Make the OpenVG code for QStaticText compile. --- src/openvg/qpaintengine_vg.cpp | 30 +++++++++++++++++------------- src/openvg/qpaintengine_vg_p.h | 3 ++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 9088d66..0ef93b3 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -50,7 +50,6 @@ #endif #include #include -#include #include #include #include @@ -87,7 +86,8 @@ public: QVGFontGlyphCache(); ~QVGFontGlyphCache(); - void cacheGlyphs(QVGPaintEnginePrivate *d, QFontEngine *fontEngine, glyph_t *g, int count); + void cacheGlyphs(QVGPaintEnginePrivate *d, QFontEngine *fontEngine, const glyph_t *g, int count); + void setScaleFromText(const QFont &font, QFontEngine *fontEngine); VGFont font; @@ -3142,9 +3142,9 @@ void QVGFontGlyphCache::setScaleFromText(const QFont &font, QFontEngine *fontEng scaleX = scaleY = static_cast(pixelSize / emSquare); } -void QVGFontGlyphCache::cacheGlyphs - (QVGPaintEnginePrivate *d, QFontEngine *fontEngine, - glyph_t *g, int count); +void QVGFontGlyphCache::cacheGlyphs(QVGPaintEnginePrivate *d, + QFontEngine *fontEngine, + const glyph_t *g, int count) { VGfloat origin[2]; VGfloat escapement[2]; @@ -3233,7 +3233,8 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) ti.fontEngine->getGlyphPositions (ti.glyphs, matrix, ti.flags, glyphs, positions); - drawCachedGlyphs(glyphs.size(), glyphs.data(), positions.data(), ti.font, ti.fontEngine, p); + if (!drawCachedGlyphs(glyphs.size(), glyphs.data(), ti.font(), ti.fontEngine, p)) + QPaintEngineEx::drawTextItem(p, textItem); #else // OpenGL 1.0 does not have support for VGFont and glyphs, // so fall back to the default Qt path stroking algorithm. @@ -3241,15 +3242,17 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) #endif } -void QVGPaintengine::drawStaticText(QStaticTextItem *textItem) +void QVGPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine, QPointF(0, 0)); } - void QVGPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, + bool QVGPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, QFontEngine *fontEngine, const QPointF &p) { + Q_D(QVGPaintEngine); + // Find the glyph cache for this font. QVGFontCache::ConstIterator it = d->fontCache.constFind(fontEngine); QVGFontGlyphCache *glyphCache; @@ -3259,9 +3262,8 @@ void QVGPaintengine::drawStaticText(QStaticTextItem *textItem) glyphCache = new QVGFontGlyphCache(); if (glyphCache->font == VG_INVALID_HANDLE) { qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine"); - delete glyphCache; - QPaintEngineEx::drawTextItem(p, textItem); - return; + delete glyphCache; + return false; } glyphCache->setScaleFromText(font, fontEngine); d->fontCache.insert(fontEngine, glyphCache); @@ -3280,7 +3282,7 @@ void QVGPaintengine::drawStaticText(QStaticTextItem *textItem) d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform); // Add the glyphs from the text item into the glyph cache. - glyphCache->cacheGlyphs(d, fontEngine, glyphs.constData(), glyphs.size()); + glyphCache->cacheGlyphs(d, fontEngine, glyphs, numGlyphs); // Set the glyph drawing origin. VGfloat origin[2]; @@ -3299,8 +3301,10 @@ void QVGPaintengine::drawStaticText(QStaticTextItem *textItem) // Draw the glyphs. We need to fill with the brush associated with // the Qt pen, not the Qt brush. d->ensureBrush(state()->pen.brush()); - vgDrawGlyphs(glyphCache->font, numGlyphs, (VGuint*)glyphs.data(), + vgDrawGlyphs(glyphCache->font, numGlyphs, (VGuint*)glyphs, NULL, NULL, VG_FILL_PATH, VG_TRUE); + + return true; } void QVGPaintEngine::setState(QPainterState *s) diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h index c70e1c1..3f73fed 100644 --- a/src/openvg/qpaintengine_vg_p.h +++ b/src/openvg/qpaintengine_vg_p.h @@ -54,6 +54,7 @@ // #include +#include QT_BEGIN_NAMESPACE @@ -140,7 +141,7 @@ public: void drawTextItem(const QPointF &p, const QTextItem &textItem); void drawStaticTextItem(QStaticTextItem *staticTextItem); - void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, + bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, QFontEngine *fontEngine, const QPointF &p); void setState(QPainterState *s); -- cgit v0.12 From 872a5d79615f5a36bc76730e4e7eecd1f1f54b31 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 26 Jan 2010 16:42:17 +0100 Subject: Compile for Symbian Missing include --- src/gui/text/qstatictext.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 6c70816..de2fdb3 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -44,6 +44,7 @@ #include #include +#include #include #include -- cgit v0.12 From e3b0ec7288b2ad3c477e6717d0ce605a06c0361e Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 28 Jan 2010 17:20:21 +1000 Subject: Fixup license headers. --- src/multimedia/qml/qmlsound.cpp | 2 +- src/multimedia/qml/qmlsound_p.h | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamermessage.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h | 2 +- .../mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h | 2 +- .../mediaservices/gstreamer/qgstreamervideorendererinterface.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h | 2 +- src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp | 2 +- src/plugins/mediaservices/gstreamer/qgstvideobuffer.h | 2 +- src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp | 2 +- src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h | 2 +- src/plugins/mediaservices/gstreamer/qx11videosurface.cpp | 2 +- src/plugins/mediaservices/gstreamer/qx11videosurface.h | 2 +- 34 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/multimedia/qml/qmlsound.cpp b/src/multimedia/qml/qmlsound.cpp index 6b01418..b0693b7 100644 --- a/src/multimedia/qml/qmlsound.cpp +++ b/src/multimedia/qml/qmlsound.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/multimedia/qml/qmlsound_p.h b/src/multimedia/qml/qmlsound_p.h index 3c17413..0a149c0 100644 --- a/src/multimedia/qml/qmlsound_p.h +++ b/src/multimedia/qml/qmlsound_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp index c22e83c..e38f80f 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h index 7e9af23..cdf82d9 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamermetadataprovider.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp index 730279a..7dd8375 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h index ec0253b..7fb2349 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp index 0c83147..d5d7bd0 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h index b27c2ae..f60c72e 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayerservice.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp index baece67..93d97cf 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h index a0f5f1a..f855727 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp index 0f09c6b..4649c21 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h index 471ca50..8600015 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamerbushelper.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp b/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp index 19cdfb1..13a2454 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamermessage.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamermessage.h b/src/plugins/mediaservices/gstreamer/qgstreamermessage.h index 70f35f3..4680903 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamermessage.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamermessage.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp index e892e45..9e5f425 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h index 33148ac..d6d6899 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamerserviceplugin.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp index 5059409..ac9a1e3 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h index 5cdc05f..6762bab 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideoinputdevicecontrol.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp index 10d446f..decf524 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h index 0d618f2..7685239 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooutputcontrol.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp index 8dbe3db..6c6c802 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h index 518d8ce..9566949 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideooverlay.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp index 7e10fbf..25a53cf 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h index f476730..ba3f806 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorenderer.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp index 57df692..0a1c20d 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h index 2700965..39deee8 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideorendererinterface.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp index 7b2ec14..1d8d43d 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h index 9edd1dd..7b966b7 100644 --- a/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h +++ b/src/plugins/mediaservices/gstreamer/qgstreamervideowidget.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp index 80943b5..384bdff 100644 --- a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h index 487832c..36b7c08 100644 --- a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h +++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp index 7c5805c..41e3f77 100644 --- a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h index 99d7007..f02f9a5 100644 --- a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp index 56c1405..30b7e55 100644 --- a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp +++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.h b/src/plugins/mediaservices/gstreamer/qx11videosurface.h index e69517a..1be963e 100644 --- a/src/plugins/mediaservices/gstreamer/qx11videosurface.h +++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Qt Mobility Components. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage -- cgit v0.12 From 1e7dc2be019a5cb278d5ca72702dfbac846bf3e7 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 28 Jan 2010 17:22:01 +1000 Subject: Normalise #defines for service support. --- src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri | 2 +- src/plugins/mediaservices/qt7/qt7serviceplugin.mm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri index f00d418..577209e 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri +++ b/src/plugins/mediaservices/qt7/mediaplayer/mediaplayer.pri @@ -1,6 +1,6 @@ INCLUDEPATH += $$PWD -DEFINES += Q_MEDIASERVICE_MEDIAPLAYER_AVAILABLE +DEFINES += QMEDIA_QT7_PLAYER HEADERS += \ $$PWD/qt7playercontrol.h \ diff --git a/src/plugins/mediaservices/qt7/qt7serviceplugin.mm b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm index 3e2a2a6..c59a453 100644 --- a/src/plugins/mediaservices/qt7/qt7serviceplugin.mm +++ b/src/plugins/mediaservices/qt7/qt7serviceplugin.mm @@ -52,14 +52,14 @@ QT_BEGIN_NAMESPACE QStringList QT7ServicePlugin::keys() const { return QStringList() -#ifdef Q_MEDIASERVICE_MEDIAPLAYER_AVAILABLE +#ifdef QMEDIA_QT7_PLAYER << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); #endif } QMediaService* QT7ServicePlugin::create(QString const& key) { -#ifdef Q_MEDIASERVICE_MEDIAPLAYER_AVAILABLE +#ifdef QMEDIA_QT7_PLAYER if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) return new QT7PlayerService; #endif -- cgit v0.12 From b220901d125b6c440426577b10d5c7463bf49964 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 28 Jan 2010 17:28:36 +1000 Subject: Add an audioAvailable property to QMediaPlayer. from: Andrew den Exter committed 00373999 to qtmobility/qtm-multimedia --- src/multimedia/playback/qmediaplayer.cpp | 26 ++++++++++++++++++++++ src/multimedia/playback/qmediaplayer.h | 3 +++ src/multimedia/playback/qmediaplayercontrol.cpp | 16 +++++++++++++ src/multimedia/playback/qmediaplayercontrol.h | 2 ++ .../mediaplayer/qgstreamerplayercontrol.cpp | 7 ++++++ .../mediaplayer/qgstreamerplayercontrol.h | 1 + .../mediaplayer/qgstreamerplayersession.cpp | 16 +++++++++++++ .../mediaplayer/qgstreamerplayersession.h | 3 +++ .../qt7/mediaplayer/qt7playercontrol.h | 2 +- .../qt7/mediaplayer/qt7playercontrol.mm | 5 +++++ .../qt7/mediaplayer/qt7playersession.h | 2 ++ .../qt7/mediaplayer/qt7playersession.mm | 10 +++++++++ 12 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index 878af0a..0853597 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -282,6 +282,7 @@ QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags, QMediaSer connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); connect(d->control, SIGNAL(positionChanged(qint64)), SIGNAL(positionChanged(qint64))); + connect(d->control, SIGNAL(audioAvailableChanged(bool)), SIGNAL(audioAvailableChanged(bool))); connect(d->control, SIGNAL(videoAvailableChanged(bool)), SIGNAL(videoAvailableChanged(bool))); connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); connect(d->control, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); @@ -402,6 +403,16 @@ int QMediaPlayer::bufferStatus() const return 0; } +bool QMediaPlayer::isAudioAvailable() const +{ + Q_D(const QMediaPlayer); + + if (d->control != 0) + return d->control->isAudioAvailable(); + + return false; +} + bool QMediaPlayer::isVideoAvailable() const { Q_D(const QMediaPlayer); @@ -841,6 +852,15 @@ QStringList QMediaPlayer::supportedMimeTypes(Flags flags) */ /*! + \property QMediaPlayer::audioAvailable + \brief the audio availabilty status for the current media. + + As the life time of QMediaPlayer can be longer than the playback of one + QMediaContent, this property may change over time, the + audioAvailableChanged signal can be used to monitor it's status. +*/ + +/*! \property QMediaPlayer::videoAvailable \brief the video availability status for the current media. @@ -902,6 +922,12 @@ QStringList QMediaPlayer::supportedMimeTypes(Flags flags) */ /*! + \fn void QMediaPlayer::audioAvailableChanged(bool available) + + Signals the availability of audio content has changed to \a available. +*/ + +/*! \fn void QMediaPlayer::videoAvailableChanged(bool videoAvailable) Signal the availability of visual content has changed to \a videoAvailable. diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h index 4de2b5e..dc9d4f0 100644 --- a/src/multimedia/playback/qmediaplayer.h +++ b/src/multimedia/playback/qmediaplayer.h @@ -66,6 +66,7 @@ class Q_MULTIMEDIA_EXPORT QMediaPlayer : public QMediaObject Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) Q_PROPERTY(int bufferStatus READ bufferStatus NOTIFY bufferStatusChanged) + Q_PROPERTY(bool audioAvailable READ isAudioAvailable NOTIFY audioAvailableChanged) Q_PROPERTY(bool videoAvailable READ isVideoAvailable NOTIFY videoAvailableChanged) Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) @@ -131,6 +132,7 @@ public: int volume() const; bool isMuted() const; + bool isAudioAvailable() const; bool isVideoAvailable() const; int bufferStatus() const; @@ -165,6 +167,7 @@ Q_SIGNALS: void volumeChanged(int volume); void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); void videoAvailableChanged(bool videoAvailable); void bufferStatusChanged(int percentFilled); diff --git a/src/multimedia/playback/qmediaplayercontrol.cpp b/src/multimedia/playback/qmediaplayercontrol.cpp index 90e3a8c..95ffade 100644 --- a/src/multimedia/playback/qmediaplayercontrol.cpp +++ b/src/multimedia/playback/qmediaplayercontrol.cpp @@ -220,6 +220,22 @@ QMediaPlayerControl::QMediaPlayerControl(QObject *parent): */ /*! + \fn QMediaPlayerControl::isAudioAvailable() const + + Identifies if there is audio output available for the current media. + + Returns true if audio output is available and false otherwise. +*/ + +/*! + \fn QMediaPlayerControl::audioAvailableChanged(bool audio) + + Signals that there has been a change in the availability of \a audio output. + + \sa isAudioAvailable() +*/ + +/*! \fn QMediaPlayerControl::isVideoAvailable() const Identifies if there is video output available for the current media. diff --git a/src/multimedia/playback/qmediaplayercontrol.h b/src/multimedia/playback/qmediaplayercontrol.h index ac3fc45..a7e418b 100644 --- a/src/multimedia/playback/qmediaplayercontrol.h +++ b/src/multimedia/playback/qmediaplayercontrol.h @@ -82,6 +82,7 @@ public: virtual int bufferStatus() const = 0; + virtual bool isAudioAvailable() const = 0; virtual bool isVideoAvailable() const = 0; virtual bool isSeekable() const = 0; @@ -107,6 +108,7 @@ Q_SIGNALS: void mediaStatusChanged(QMediaPlayer::MediaStatus status); void volumeChanged(int volume); void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); void videoAvailableChanged(bool videoAvailable); void bufferStatusChanged(int percentFilled); void seekableChanged(bool); diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp index 7dd8375..f008e81 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp @@ -80,6 +80,8 @@ QGstreamerPlayerControl::QGstreamerPlayerControl(QGstreamerPlayerSession *sessio this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); connect(m_session,SIGNAL(bufferingProgressChanged(int)), this, SIGNAL(bufferStatusChanged(int))); + connect(m_session, SIGNAL(audioAvailableChanged(bool)), + this, SIGNAL(audioAvailableChanged(bool))); connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); connect(m_session, SIGNAL(seekableChanged(bool)), @@ -236,6 +238,11 @@ void QGstreamerPlayerControl::setVideoOutput(QObject *output) m_session->setVideoRenderer(output); } +bool QGstreamerPlayerControl::isAudioAvailable() const +{ + return m_session->isAudioAvailable(); +} + bool QGstreamerPlayerControl::isVideoAvailable() const { return m_session->isVideoAvailable(); diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h index 7fb2349..ae0f8b6 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.h @@ -79,6 +79,7 @@ public: int volume() const; bool isMuted() const; + bool isAudioAvailable() const; bool isVideoAvailable() const; void setVideoOutput(QObject *output); diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp index 93d97cf..93151e1 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -63,6 +63,7 @@ QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent) m_volume(100), m_playbackRate(1.0), m_muted(false), + m_audioAvailable(false), m_videoAvailable(false), m_seekable(false), m_lastPosition(0), @@ -231,6 +232,11 @@ bool QGstreamerPlayerSession::isMuted() const return m_muted; } +bool QGstreamerPlayerSession::isAudioAvailable() const +{ + return m_audioAvailable; +} + void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) { m_renderer = qobject_cast(videoOutput); @@ -565,6 +571,7 @@ void QGstreamerPlayerSession::getStreamsInfo() } //check if video is available: + bool haveAudio = false; bool haveVideo = false; // m_streamProperties.clear(); // m_streamTypes.clear(); @@ -578,6 +585,9 @@ void QGstreamerPlayerSession::getStreamsInfo() g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, NULL); g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, NULL); + haveAudio = audioStreamsCount > 0; + haveVideo = videoStreamsCount > 0; + m_playbin2StreamOffset[QMediaStreamsControl::AudioStream] = 0; m_playbin2StreamOffset[QMediaStreamsControl::VideoStream] = audioStreamsCount; m_playbin2StreamOffset[QMediaStreamsControl::SubPictureStream] = audioStreamsCount+videoStreamsCount; @@ -648,6 +658,8 @@ void QGstreamerPlayerSession::getStreamsInfo() if (type == GST_STREAM_TYPE_VIDEO) haveVideo = true; + else if (type == GST_STREAM_TYPE_AUDIO) + hasAudio = true; // QMediaStreamsControl::StreamType streamType = QMediaStreamsControl::UnknownStream; // @@ -674,6 +686,10 @@ void QGstreamerPlayerSession::getStreamsInfo() } #endif + if (haveAudio != m_audioAvailable) { + m_audioAvailable = haveAudio; + emit audioAvailableChanged(m_audioAvailable); + } if (haveVideo != m_videoAvailable) { m_videoAvailable = haveVideo; emit videoAvailableChanged(m_videoAvailable); diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h index f855727..0da5f8f 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h @@ -84,6 +84,7 @@ public: bool isMuted() const; void setVideoRenderer(QObject *renderer); + bool isAudioAvailable() const; bool isVideoAvailable() const; bool isSeekable() const; @@ -120,6 +121,7 @@ signals: void mediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus); void volumeChanged(int volume); void mutedStateChanged(bool muted); + void audioAvailalbeChanged(bool audioAvailable); void videoAvailableChanged(bool videoAvailable); void bufferingChanged(bool buffering); void bufferingProgressChanged(int percentFilled); @@ -154,6 +156,7 @@ private: int m_volume; qreal m_playbackRate; bool m_muted; + bool m_audioAvailable; bool m_videoAvailable; bool m_seekable; diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h index da86949..907d13d 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.h @@ -82,13 +82,13 @@ public: int volume() const; bool isMuted() const; + bool isAudioAvailable() const; bool isVideoAvailable() const; bool isSeekable() const; QMediaTimeRange availablePlaybackRanges() const; - qreal playbackRate() const; void setPlaybackRate(qreal rate); diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm index b74f434..0f4ac41 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playercontrol.mm @@ -71,6 +71,7 @@ void QT7PlayerControl::setSession(QT7PlayerSession *session) this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(audioAvailableChanged(bool)), this, SIGNAL(audioAvailableChanged(bool))); connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); } @@ -177,6 +178,10 @@ void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) emit mediaChanged(content); } +bool QT7PlayerControl::isAudioAvailable() const +{ + return m_session->isAudioAvailable(); +} bool QT7PlayerControl::isVideoAvailable() const { diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h index 55505ee..2a6bab7 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.h @@ -87,6 +87,7 @@ public: int volume() const; bool isMuted() const; + bool isAudioAvailable() const; bool isVideoAvailable() const; bool isSeekable() const; @@ -112,6 +113,7 @@ signals: void mediaStatusChanged(QMediaPlayer::MediaStatus status); void volumeChanged(int volume); void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); void videoAvailableChanged(bool videoAvailable); void error(int error, const QString &errorString); diff --git a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm index 3131a90..d9bb646 100644 --- a/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm +++ b/src/plugins/mediaservices/qt7/mediaplayer/qt7playersession.mm @@ -373,6 +373,7 @@ void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) } emit durationChanged(duration()); + emit audioAvailableChanged(isAudioAvailable()); emit videoAvailableChanged(isVideoAvailable()); [(QTMovie*)m_QTMovie setMuted:m_muted]; @@ -380,6 +381,15 @@ void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) } } +bool QT7PlayerSession::isAudioAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasAudioAttribute"] boolValue] == YES; +} + bool QT7PlayerSession::isVideoAvailable() const { if (!m_QTMovie) -- cgit v0.12 From b4402915aab8a13ec6a085dd2e3a1e13a59ade98 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 28 Jan 2010 17:31:52 +1000 Subject: Add size, offset and fillMode properties to QGraphicsVideoItem. From: Andrew den Exter committed 9fb251df to qtmobility/qtm-multimedia --- src/multimedia/base/qgraphicsvideoitem.cpp | 169 +++++++++++++++++++++++---- src/multimedia/base/qgraphicsvideoitem.h | 32 ++++- src/multimedia/base/qpaintervideosurface.cpp | 16 +-- src/multimedia/base/qpaintervideosurface_p.h | 2 +- 4 files changed, 185 insertions(+), 34 deletions(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp index 7fa2e7d..1a5ccd7 100644 --- a/src/multimedia/base/qgraphicsvideoitem.cpp +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -43,15 +43,15 @@ #include #include -#include "qpaintervideosurface_p.h" +#include #include #include - #include QT_BEGIN_NAMESPACE + class QGraphicsVideoItemPrivate { public: @@ -62,6 +62,8 @@ public: , service(0) , outputControl(0) , rendererControl(0) + , aspectRatioMode(Qt::KeepAspectRatio) + , updatePaintDevice(true) { } @@ -72,9 +74,14 @@ public: QMediaService *service; QVideoOutputControl *outputControl; QVideoRendererControl *rendererControl; - QRect boundingRect; + Qt::AspectRatioMode aspectRatioMode; + bool updatePaintDevice; + QRectF rect; + QRectF boundingRect; + QSizeF nativeSize; void clearService(); + void updateBoundingRect(); void _q_present(); void _q_formatChanged(const QVideoSurfaceFormat &format); @@ -99,17 +106,40 @@ void QGraphicsVideoItemPrivate::clearService() } } +void QGraphicsVideoItemPrivate::updateBoundingRect() +{ + q_ptr->prepareGeometryChange(); + + if (nativeSize.isEmpty()) { + boundingRect = QRectF(); + } else { + if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + } else { + QSizeF size = nativeSize; + size.scale(rect.size(), aspectRatioMode); + + boundingRect = QRectF(QPointF(), size); + boundingRect.moveCenter(rect.center()); + } + } +} + void QGraphicsVideoItemPrivate::_q_present() { - q_ptr->update(boundingRect); + if (q_ptr->isObscured()) { + q_ptr->update(boundingRect); + surface->setReady(true); + } else { + q_ptr->update(boundingRect); + } } void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &format) { - q_ptr->prepareGeometryChange(); + nativeSize = format.sizeHint(); - boundingRect = QRect(QPoint(0, 0), format.sizeHint()); - boundingRect.moveCenter(QPoint(0, 0)); + updateBoundingRect(); } void QGraphicsVideoItemPrivate::_q_serviceDestroyed() @@ -152,22 +182,39 @@ void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() player->play(); \endcode - \bold {Note}: Only a single display output can be attached to a media object at one time. + \bold {Note}: Only a single display output can be attached to a media + object at one time. \sa QMediaObject, QMediaPlayer, QVideoWidget */ /*! + \enum QGraphicsVideoItem::FillMode + + Enumerates the methods of scaling a video to fit a graphics item. + + \value Stretch The video is stretched to fit the item's size. + \value PreserveAspectFit The video is uniformly scaled to fix the item's + size without cropping. + \value PreserveAspectCrop The video is uniformly scaled to fill the item's + size, cropping if necessary. +*/ + +/*! Constructs a graphics item that displays video. The \a parent is passed to QGraphicsItem. */ QGraphicsVideoItem::QGraphicsVideoItem(QGraphicsItem *parent) - : QGraphicsItem(parent) + : QGraphicsObject(parent) , d_ptr(new QGraphicsVideoItemPrivate) { d_ptr->q_ptr = this; d_ptr->surface = new QPainterVideoSurface; + + connect(d_ptr->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); + connect(d_ptr->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), + this, SLOT(_q_formatChanged(QVideoSurfaceFormat))); } /*! @@ -187,7 +234,8 @@ QGraphicsVideoItem::~QGraphicsVideoItem() /*! \property QGraphicsVideoItem::mediaObject - \brief the media object which provides the video displayed by a graphics item. + \brief the media object which provides the video displayed by a graphics + item. */ QMediaObject *QGraphicsVideoItem::mediaObject() const @@ -227,15 +275,6 @@ void QGraphicsVideoItem::setMediaObject(QMediaObject *object) d->service->control(QVideoRendererControl_iid)); if (d->outputControl != 0 && d->rendererControl != 0) { - if (!d->surface) { - d->surface = new QPainterVideoSurface; - - connect(d->surface, SIGNAL(frameChanged()), this, SLOT(_q_present())); - connect(d->surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), - this, SLOT(_q_formatChanged(QVideoSurfaceFormat))); - connect(d->service, SIGNAL(destroyed()), this, SLOT(_q_serviceDestroyed())); - } - d->rendererControl->setSurface(d->surface); if (isVisible()) @@ -246,6 +285,82 @@ void QGraphicsVideoItem::setMediaObject(QMediaObject *object) } /*! + \property QGraphicsVideoItem::aspectRatioMode + \brief how a video is scaled to fit the graphics item's size. +*/ + +Qt::AspectRatioMode QGraphicsVideoItem::aspectRatioMode() const +{ + return d_func()->aspectRatioMode; +} + +void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) +{ + Q_D(QGraphicsVideoItem); + + d->aspectRatioMode = mode; + d->updateBoundingRect(); +} + +/*! + \property QGraphicsVideoItem::offset + \brief the video item's offset. + + QGraphicsVideoItem will draw video using the offset for its top left + corner. +*/ + +QPointF QGraphicsVideoItem::offset() const +{ + return d_func()->rect.topLeft(); +} + +void QGraphicsVideoItem::setOffset(const QPointF &offset) +{ + Q_D(QGraphicsVideoItem); + + d->rect.moveTo(offset); + d->updateBoundingRect(); +} + +/*! + \property QGraphicsVideoItem::size + \brief the video item's size. + + QGraphicsVideoItem will draw video scaled to fit size according to its + fillMode. +*/ + +QSizeF QGraphicsVideoItem::size() const +{ + return d_func()->rect.size(); +} + +void QGraphicsVideoItem::setSize(const QSizeF &size) +{ + Q_D(QGraphicsVideoItem); + + d->rect.setSize(size); + d->updateBoundingRect(); +} + +/*! + \property QGraphicsVideoItem::nativeSize + \brief the native size of the video. +*/ + +QSizeF QGraphicsVideoItem::nativeSize() const +{ + return d_func()->nativeSize; +} + +/*! + \fn QGraphicsVideoItem::nativeSizeChanged(const QSizeF &size) + + Signals that the native \a size of the video has changed. +*/ + +/*! \reimp */ QRectF QGraphicsVideoItem::boundingRect() const @@ -264,10 +379,24 @@ void QGraphicsVideoItem::paint( Q_UNUSED(option); Q_UNUSED(widget); - if (d->surface != 0) { + if (d->surface && d->surface->isActive()) { d->surface->paint(painter, d->boundingRect); d->surface->setReady(true); +#ifndef QGRAPHICSVIDEOITEM_SHADERS // Flickers + } +#else + } else if (d->updatePaintDevice && (painter->paintEngine()->type() == QPaintEngine::OpenGL + || painter->paintEngine()->type() == QPaintEngine::OpenGL2)) { + d->updatePaintDevice = false; + + d->surface->setGLContext(const_cast(QGLContext::currentContext())); + if (d->surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { + d->surface->setShaderType(QPainterVideoSurface::GlslShader); + } else { + d->surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); + } } +#endif } /*! diff --git a/src/multimedia/base/qgraphicsvideoitem.h b/src/multimedia/base/qgraphicsvideoitem.h index 0cd5d46..ac215ea 100644 --- a/src/multimedia/base/qgraphicsvideoitem.h +++ b/src/multimedia/base/qgraphicsvideoitem.h @@ -46,32 +46,54 @@ #include + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Multimedia) - class QVideoSurfaceFormat; class QGraphicsVideoItemPrivate; -class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QObject, public QGraphicsItem +class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QGraphicsObject { Q_OBJECT - Q_INTERFACES(QGraphicsItem) Q_PROPERTY(QMediaObject* mediaObject READ mediaObject WRITE setMediaObject) - + Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ aspectRatioMode WRITE setAspectRatioMode) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset) + Q_PROPERTY(QSizeF size READ size WRITE setSize) + Q_PROPERTY(QSizeF nativeSize READ nativeSize NOTIFY nativeSizeChanged) public: + enum FillMode + { + Stretch, + PreserveAspectFit, + PreserveAspectCrop + }; + QGraphicsVideoItem(QGraphicsItem *parent = 0); ~QGraphicsVideoItem(); QMediaObject *mediaObject() const; void setMediaObject(QMediaObject *object); + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode mode); + + QPointF offset() const; + void setOffset(const QPointF &offset); + + QSizeF size() const; + void setSize(const QSizeF &size); + + QSizeF nativeSize() const; + QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); +Q_SIGNALS: + void nativeSizeChanged(const QSizeF &size) const; + protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value); diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index feeb42f..9953ae8 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -73,7 +73,7 @@ public: virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; virtual QAbstractVideoSurface::Error paint( - const QRect &target, QPainter *painter, const QRect &source) = 0; + const QRectF &target, QPainter *painter, const QRect &source) = 0; virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; }; @@ -99,7 +99,7 @@ public: QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); QAbstractVideoSurface::Error paint( - const QRect &target, QPainter *painter, const QRect &source); + const QRectF &target, QPainter *painter, const QRect &source); void updateColors(int brightness, int contrast, int hue, int saturation); @@ -167,7 +167,7 @@ QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::setCurrentFrame(const Q } QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::paint( - const QRect &target, QPainter *painter, const QRect &source) + const QRectF &target, QPainter *painter, const QRect &source) { if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { QImage image( @@ -540,7 +540,7 @@ public: QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); void stop(); - QAbstractVideoSurface::Error paint(const QRect &target, QPainter *painter, const QRect &source); + QAbstractVideoSurface::Error paint(const QRectF &target, QPainter *painter, const QRect &source); private: typedef void (APIENTRY *_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *); @@ -700,7 +700,7 @@ void QVideoSurfaceArbFpPainter::stop() } QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::paint( - const QRect &target, QPainter *painter, const QRect &source) + const QRectF &target, QPainter *painter, const QRect &source) { if (m_frame.isValid()) { painter->beginNativePainting(); @@ -857,7 +857,7 @@ public: QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); void stop(); - QAbstractVideoSurface::Error paint(const QRect &target, QPainter *painter, const QRect &source); + QAbstractVideoSurface::Error paint(const QRectF &target, QPainter *painter, const QRect &source); private: QGLShaderProgram m_program; @@ -975,7 +975,7 @@ void QVideoSurfaceGlslPainter::stop() } QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( - const QRect &target, QPainter *painter, const QRect &source) + const QRectF &target, QPainter *painter, const QRect &source) { if (m_frame.isValid()) { painter->beginNativePainting(); @@ -1289,7 +1289,7 @@ void QPainterVideoSurface::setReady(bool ready) /*! */ -void QPainterVideoSurface::paint(QPainter *painter, const QRect &rect) +void QPainterVideoSurface::paint(QPainter *painter, const QRectF &rect) { if (!isActive()) { painter->fillRect(rect, QBrush(Qt::black)); diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h index a7d3e3a..67b514f 100644 --- a/src/multimedia/base/qpaintervideosurface_p.h +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -102,7 +102,7 @@ public: bool isReady() const; void setReady(bool ready); - void paint(QPainter *painter, const QRect &rect); + void paint(QPainter *painter, const QRectF &rect); #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) const QGLContext *glContext() const; -- cgit v0.12 From 11e4882fdde6efba2b3fef6805801a290ad15fb0 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 28 Jan 2010 17:34:20 +1000 Subject: Add Audio and Video QML elements. --- src/multimedia/qml/qmetadatacontrolmetaobject.cpp | 234 +++++++++++++ src/multimedia/qml/qmetadatacontrolmetaobject_p.h | 85 +++++ src/multimedia/qml/qml.pri | 12 +- src/multimedia/qml/qmlaudio.cpp | 292 +++++++++++++++++ src/multimedia/qml/qmlaudio_p.h | 162 +++++++++ src/multimedia/qml/qmlgraphicsvideo.cpp | 378 +++++++++++++++++++++ src/multimedia/qml/qmlgraphicsvideo_p.h | 197 +++++++++++ src/multimedia/qml/qmlmediabase.cpp | 379 ++++++++++++++++++++++ 8 files changed, 1737 insertions(+), 2 deletions(-) create mode 100644 src/multimedia/qml/qmetadatacontrolmetaobject.cpp create mode 100644 src/multimedia/qml/qmetadatacontrolmetaobject_p.h create mode 100644 src/multimedia/qml/qmlaudio.cpp create mode 100644 src/multimedia/qml/qmlaudio_p.h create mode 100644 src/multimedia/qml/qmlgraphicsvideo.cpp create mode 100644 src/multimedia/qml/qmlgraphicsvideo_p.h create mode 100644 src/multimedia/qml/qmlmediabase.cpp diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp new file mode 100644 index 0000000..c2b5e78 --- /dev/null +++ b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 + +#include /qmetadatacontrol.h> + + +QT_BEGIN_NAMESPACE + +namespace +{ + struct MetaDataKey + { + QtMedia::MetaData key; + const char *name; + }; + + const MetaDataKey qt_metaDataKeys[] = + { + { QtMedia::Title, "title" }, + { QtMedia::SubTitle, "subTitle" }, + { QtMedia::Author, "author" }, + { QtMedia::Comment, "comment" }, + { QtMedia::Description, "description" }, + { QtMedia::Category, "category" }, + { QtMedia::Genre, "genre" }, + { QtMedia::Year, "year" }, + { QtMedia::Date, "date" }, + { QtMedia::UserRating, "userRating" }, + { QtMedia::Keywords, "keywords" }, + { QtMedia::Language, "language" }, + { QtMedia::Publisher, "publisher" }, + { QtMedia::Copyright, "copyright" }, + { QtMedia::ParentalRating, "parentalRating" }, + { QtMedia::RatingOrganisation, "ratingOrganisation" }, + + // Media + { QtMedia::Size, "size" }, + { QtMedia::MediaType, "mediaType" }, + { QtMedia::Duration, "duration" }, + + // Audio + { QtMedia::AudioBitRate, "audioBitRate" }, + { QtMedia::AudioCodec, "audioCodec" }, + { QtMedia::AverageLevel, "averageLevel" }, + { QtMedia::ChannelCount, "channelCount" }, + { QtMedia::PeakValue, "peakValue" }, + { QtMedia::SampleRate, "frequency" }, + + // Music + { QtMedia::AlbumTitle, "albumTitle" }, + { QtMedia::AlbumArtist, "albumArtist" }, + { QtMedia::ContributingArtist, "contributingArtist" }, + { QtMedia::Composer, "composer" }, + { QtMedia::Conductor, "conductor" }, + { QtMedia::Lyrics, "lyrics" }, + { QtMedia::Mood, "mood" }, + { QtMedia::TrackNumber, "trackNumber" }, + { QtMedia::TrackCount, "trackCount" }, + + { QtMedia::CoverArtUrlSmall, "coverArtUrlSmall" }, + { QtMedia::CoverArtUrlLarge, "coverArtUrlLarge" }, + + // Image/Video + { QtMedia::Resolution, "resolution" }, + { QtMedia::PixelAspectRatio, "pixelAspectRatio" }, + + // Video + { QtMedia::VideoFrameRate, "videoFrameRate" }, + { QtMedia::VideoBitRate, "videoBitRate" }, + { QtMedia::VideoCodec, "videoCodec" }, + + { QtMedia::PosterUrl, "posterUrl" }, + + // Movie + { QtMedia::ChapterNumber, "chapterNumber" }, + { QtMedia::Director, "director" }, + { QtMedia::LeadPerformer, "leadPerformer" }, + { QtMedia::Writer, "writer" }, + + // Photos + { QtMedia::CameraManufacturer, "cameraManufacturer" }, + { QtMedia::CameraModel, "cameraModel" }, + { QtMedia::Event, "event" }, + { QtMedia::Subject, "subject" }, + { QtMedia::Orientation, "orientation" }, + { QtMedia::ExposureTime, "exposureTime" }, + { QtMedia::FNumber, "fNumber" }, + { QtMedia::ExposureProgram, "exposureProgram" }, + { QtMedia::ISOSpeedRatings, "isoSpeedRatings" }, + { QtMedia::ExposureBiasValue, "exposureBiasValue" }, + { QtMedia::DateTimeOriginal, "dateTimeOriginal" }, + { QtMedia::DateTimeDigitized, "dateTimeDigitized" }, + { QtMedia::SubjectDistance, "subjectDistance" }, + { QtMedia::MeteringMode, "meteringMode" }, + { QtMedia::LightSource, "lightSource" }, + { QtMedia::Flash, "flash" }, + { QtMedia::FocalLength, "focalLength" }, + { QtMedia::ExposureMode, "exposureMode" }, + { QtMedia::WhiteBalance, "whiteBalance" }, + { QtMedia::DigitalZoomRatio, "digitalZoomRatio" }, + { QtMedia::FocalLengthIn35mmFilm, "focalLengthIn35mmFilm" }, + { QtMedia::SceneCaptureType, "sceneCaptureType" }, + { QtMedia::GainControl, "gainControl" }, + { QtMedia::Contrast, "contrast" }, + { QtMedia::Saturation, "saturation" }, + { QtMedia::Sharpness, "sharpness" }, + { QtMedia::DeviceSettingDescription, "deviceSettingDescription" } + }; +} + +QMetaDataControlMetaObject::QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object) + : m_control(control) + , m_object(object) + , m_mem(0) + , m_propertyOffset(0) + , m_signalOffset(0) +{ + m_builder.setSuperClass(m_object->metaObject()); + m_builder.setClassName(m_object->metaObject()->className()); + m_builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + + QObjectPrivate *op = QObjectPrivate::get(m_object); + if (op->metaObject) + m_builder.setSuperClass(op->metaObject); + + m_mem = m_builder.toMetaObject(); + *static_cast(this) = *m_mem; + + op->metaObject = this; + m_propertyOffset = propertyOffset(); + m_signalOffset = methodOffset(); +} + +QMetaDataControlMetaObject::~QMetaDataControlMetaObject() +{ + qFree(m_mem); + + QObjectPrivate *op = QObjectPrivate::get(m_object); + op->metaObject = 0; +} + +int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +{ + if (c == QMetaObject::ReadProperty && id >= m_propertyOffset) { + int propId = id - m_propertyOffset; + + *reinterpret_cast(a[0]) = m_control->metaData(m_keys.at(propId)); + + return -1; + } else if (c == QMetaObject::WriteProperty && id >= m_propertyOffset) { + int propId = id - m_propertyOffset; + + m_control->setMetaData(m_keys.at(propId), *reinterpret_cast(a[0])); + + activate(m_object, m_signalOffset + propId, 0); + + return -1; + } else { + return m_object->qt_metacall(c, id, a); + } +} + +int QMetaDataControlMetaObject::createProperty(const char *name, const char *) +{ + const int count = sizeof(qt_metaDataKeys) / sizeof(MetaDataKey); + + for (int i = 0; i < count; ++i) { + if (qstrcmp(name, qt_metaDataKeys[i].name) == 0) { + int id = m_keys.count(); + m_keys.append(qt_metaDataKeys[i].key); + + m_builder.addSignal("__" + QByteArray::number(id) + "()"); + + QMetaPropertyBuilder build = m_builder.addProperty(name, "QVariant", id); + build.setDynamic(true); + + qFree(m_mem); + m_mem = m_builder.toMetaObject(); + *static_cast(this) = *m_mem; + + return m_propertyOffset + id; + } + } + + return -1; +} + +void QMetaDataControlMetaObject::metaDataChanged() +{ + for (int i = 0; i < m_keys.count(); ++i) + activate(m_object, m_signalOffset + i, 0); +} + +QT_END_NAMESPACE diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject_p.h b/src/multimedia/qml/qmetadatacontrolmetaobject_p.h new file mode 100644 index 0000000..b7f88fe --- /dev/null +++ b/src/multimedia/qml/qmetadatacontrolmetaobject_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMETADATACONTROLMETAOBJECT_P_H +#define QMETADATACONTROLMETAOJBECT_P_H + +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMetaDataControl; + +class QMetaDataControlMetaObject : public QAbstractDynamicMetaObject +{ +public: + QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object); + ~QMetaDataControlMetaObject(); + + int metaCall(QMetaObject::Call call, int _id, void **arguments); + int createProperty(const char *, const char *); + + void metaDataChanged(); + +private: + QMetaDataControl *m_control; + QObject *m_object; + QMetaObject *m_mem; + + int m_propertyOffset; + int m_signalOffset; + + QVector m_keys; + QMetaObjectBuilder m_builder; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/multimedia/qml/qml.pri b/src/multimedia/qml/qml.pri index adfcc23..6b44e0c 100644 --- a/src/multimedia/qml/qml.pri +++ b/src/multimedia/qml/qml.pri @@ -3,9 +3,17 @@ contains(QT_CONFIG, declarative) { QT += declarative HEADERS += \ - $$PWD/qmlsound_p.h + $$PWD/qmlsound_p.h \ + $$PWD/qmetadatacontrolmetaobject_p.h \ + $$PWD/qmlaudio_p.h \ + $$PWD/qmlgraphicsvideo_p.h \ + $$PWD/qmlmediabase_p.h SOURCES += \ - $$PWD/qmlsound.cpp + $$PWD/qmlsound.cpp \ + $$PWD/qmetadatacontrolmetaobject.cpp \ + $$PWD/qmlaudio.cpp \ + $$PWD/qmlgraphicsvideo.cpp \ + $$PWD/qmlmediabase.cpp } diff --git a/src/multimedia/qml/qmlaudio.cpp b/src/multimedia/qml/qmlaudio.cpp new file mode 100644 index 0000000..713e36a --- /dev/null +++ b/src/multimedia/qml/qmlaudio.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qmlaudio_p.h" + +#include + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt,4,6,Audio,QmlAudio); + +/*! + \qmlclass Audio QmlAudio + \brief The Audio element allows you to add audio to a scene. +*/ + +/*! + \internal + \class QmlAudio + \brief The QmlAudio class provides a audio item that you can add to a QmlView. +*/ + +void QmlAudio::_q_error(QMediaPlayer::Error errorCode, const QString &errorString) +{ + m_error = errorCode; + m_errorString = errorString; + + emit error(Error(errorCode), errorString); + emit errorChanged(); +} + + +QmlAudio::QmlAudio(QObject *parent) + : QObject(parent) +{ + setObject(this); +} + +QmlAudio::~QmlAudio() +{ + shutdown(); +} + +/*! + \qmlmethod Audio::play() + + Starts playback of the audio. +*/ + +void QmlAudio::play() +{ + m_playerControl->play(); +} + +/*! + \qmlmethod Audio::pause() + + Pauses playback of the audio. +*/ + +void QmlAudio::pause() +{ + m_playerControl->pause(); +} + +/*! + \qmlmethod Audio::stop() + + Stops playback of the audio. +*/ + +void QmlAudio::stop() +{ + m_playerControl->stop(); +} + +/*! + \qmlproperty url Audio::source + + This property holds the source URL of the audio. +*/ + +/*! + \qmlproperty bool Audio::playing + + This property holds whether the audio is playing. +*/ + +/*! + \qmlproperty bool Audio::paused + + This property holds whether the audio is paused. +*/ + +/*! + \qmlsignal Audio::onStarted() + + This handler is called when playback is started. +*/ + +/*! + \qmlsignal Audio::onResumed() + + This handler is called when playback is resumed from the paused state. +*/ + +/*! + \qmlsignal Audio::onPaused() + + This handler is called when playback is paused. +*/ + +/*! + \qmlsignal Audio::onStopped() + + This handler is called when playback is stopped. +*/ + +/*! + \qmlproperty enum Audio::status + + This property holds the status of audio loading. It can be one of: + + \list + \o NoMedia - no audio has been set. + \o Loading - the audio is currently being loaded. + \o Loaded - the audio has been loaded. + \o Buffering - the audio is buffering data. + \o Stalled - playback has been interrupted while the audio is buffering data. + \o Buffered - the audio has buffered data. + \o EndOfMedia - the audio has played to the end. + \o InvalidMedia - the audio cannot be played. + \o UnknownStatus - the status of the audio is unknown. + \endlist +*/ + +QmlAudio::Status QmlAudio::status() const +{ + return Status(m_status); +} + +/*! + \qmlsignal Audio::onLoaded() + + This handler is called when the video source has been loaded. +*/ + +/*! + \qmlsignal Audio::onBuffering() + + This handler is called when the video stream starts buffering. +*/ + +/*! + \qmlsignal Audio::onStalled() + + This handler is called when playback has stalled while the video stream buffers. +*/ + +/*! + \qmlsignal Audio::onBuffered() + + This handler is called when the video stream has finished buffering. +*/ + +/*! + \qmlsignal Audio::onEndOfMedia + + This handler is called when playback stops because end of the video has been reached. +*/ +/*! + \qmlproperty int Audio::duration + + This property holds the duration of the audio in milliseconds. + + If the audio doesn't have a fixed duration (a live stream for example) this will be 0. +*/ + +/*! + \qmlproperty int Audio::position + + This property holds the current playback position in milliseconds. +*/ + +/*! + \qmlproperty qreal Audio::volume + + This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). +*/ + +/*! + \qmlproperty bool Audio::muted + + This property holds whether the audio output is muted. +*/ + +/*! + \qmlproperty qreal Audio::bufferProgress + + This property holds how much of the data buffer is currently filled, from 0.0 (empty) to 1.0 + (full). +*/ + +/*! + \qmlproperty bool Audio::seekable + + This property holds whether position of the audio can be changed. +*/ + +/*! + \qmlproperty qreal playbackRate + + This property holds the rate at which audio is played at as a multiple of the normal rate. +*/ + +/*! + \qmlproperty enum Audio::error + + This property holds the error state of the audio. It can be one of: + + \list + \o NoError - there is no current error. + \o ResourceError - the audio cannot be played due to a problem allocating resources. + \o FormatError - the audio format is not supported. + \o NetworkError - the audio cannot be played due to network issues. + \o AccessDenied - the audio cannot be played due to insufficient permissions. + \o ServiceMissing - the audio cannot be played because the media service could not be + instantiated. + \endlist +*/ + +QmlAudio::Error QmlAudio::error() const +{ + return Error(m_error); +} + +/*! + \qmlproperty string Audio::errorString + + This property holds a string describing the current error condition in more detail. +*/ + +/*! + \qmlproperty Audio::onError(error, errorString) + + This property is called when an \l {Error}{error} has occurred. The errorString parameter + may contain more detailed information about the error. +*/ + +QT_END_NAMESPACE + +#include "moc_qmlaudio_p.cpp" + + diff --git a/src/multimedia/qml/qmlaudio_p.h b/src/multimedia/qml/qmlaudio_p.h new file mode 100644 index 0000000..c6ab53d --- /dev/null +++ b/src/multimedia/qml/qmlaudio_p.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMLAUDIO_P_H +#define QMLAUDIO_P_H + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimerEvent; + +class QmlAudio : public QObject, public QmlMediaBase, public QmlParserStatus +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged) + Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int bufferProgress READ bufferProgress NOTIFY bufferProgressChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(Error error READ error NOTIFY errorChanged) + Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) + Q_ENUMS(Status) + Q_ENUMS(Error) + Q_INTERFACES(QmlParserStatus) +public: + enum Status + { + UnknownStatus = QMediaPlayer::UnknownMediaStatus, + NoMedia = QMediaPlayer::NoMedia, + Loading = QMediaPlayer::LoadingMedia, + Loaded = QMediaPlayer::LoadedMedia, + Stalled = QMediaPlayer::StalledMedia, + Buffering = QMediaPlayer::BufferingMedia, + Buffered = QMediaPlayer::BufferedMedia, + EndOfMedia = QMediaPlayer::EndOfMedia, + InvalidMedia = QMediaPlayer::InvalidMedia + }; + + enum Error + { + NoError = QMediaPlayer::NoError, + ResourceError = QMediaPlayer::ResourceError, + FormatError = QMediaPlayer::FormatError, + NetworkError = QMediaPlayer::NetworkError, + AccessDenied = QMediaPlayer::AccessDeniedError, + ServiceMissing = QMediaPlayer::ServiceMissingError + }; + + QmlAudio(QObject *parent = 0); + ~QmlAudio(); + + Status status() const; + Error error() const; + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + +Q_SIGNALS: + void sourceChanged(); + + void playingChanged(); + void pausedChanged(); + + void started(); + void resumed(); + void paused(); + void stopped(); + + void statusChanged(); + + void loaded(); + void buffering(); + void stalled(); + void buffered(); + void endOfMedia(); + + void durationChanged(); + void positionChanged(); + + void volumeChanged(); + void mutedChanged(); + + void bufferProgressChanged(); + + void seekableChanged(); + void playbackRateChanged(); + + void errorChanged(); + void error(QmlAudio::Error error, const QString &errorString); + +private Q_SLOTS: + void _q_error(QMediaPlayer::Error, const QString &); + +private: + Q_DISABLE_COPY(QmlAudio) + Q_PRIVATE_SLOT(mediaBase(), void _q_stateChanged(QMediaPlayer::State)) + Q_PRIVATE_SLOT(mediaBase(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) + Q_PRIVATE_SLOT(mediaBase(), void _q_metaDataChanged()) + + inline QmlMediaBase *mediaBase() { return this; } +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QmlAudio)) + +QT_END_HEADER + +#endif diff --git a/src/multimedia/qml/qmlgraphicsvideo.cpp b/src/multimedia/qml/qmlgraphicsvideo.cpp new file mode 100644 index 0000000..c96f7e9 --- /dev/null +++ b/src/multimedia/qml/qmlgraphicsvideo.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qmlgraphicsvideo_p.h" + +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt,4,6,Video,QmlGraphicsVideo); + + +void QmlGraphicsVideo::_q_nativeSizeChanged(const QSizeF &size) +{ + setImplicitWidth(size.width()); + setImplicitHeight(size.height()); +} + +void QmlGraphicsVideo::_q_error(QMediaPlayer::Error errorCode, const QString &errorString) +{ + m_error = errorCode; + m_errorString = errorString; + + emit error(Error(errorCode), errorString); + emit errorChanged(); +} + + +/*! + \qmlclass Video QmlGraphicsVideo + \brief The Video element allows you to add videos to a scene. + \inherits Item +*/ + +/*! + \internal + \class QmlGraphicsVideo + \brief The QmlGraphicsVideo class provides a video item that you can add to a QmlView. +*/ + +QmlGraphicsVideo::QmlGraphicsVideo(QmlGraphicsItem *parent) + : QmlGraphicsItem(parent) + , m_graphicsItem(0) + , m_fillMode(QmlGraphicsVideo::PreserveAspectFit) + +{ + m_graphicsItem = new QGraphicsVideoItem(this); + connect(m_graphicsItem, SIGNAL(nativeSizeChanged(QSizeF)), + this, SLOT(_q_nativeSizeChanged(QSizeF))); + + setObject(this); + + if (m_mediaService) { + connect(m_playerControl, SIGNAL(audioAvailableChanged(bool)), + this, SIGNAL(hasAudioChanged())); + connect(m_playerControl, SIGNAL(videoAvailableChanged(bool)), + this, SIGNAL(hasVideoChanged())); + + m_graphicsItem->setMediaObject(m_mediaObject); + } +} + +QmlGraphicsVideo::~QmlGraphicsVideo() +{ + shutdown(); + + delete m_graphicsItem; +} + +/*! + \qmlproperty url Video::source + + This property holds the source URL of the video. +*/ + +/*! + \qmlproperty bool Video::playing + + This property holds whether the video is playing. +*/ + +/*! + \qmlproperty bool Video::paused + + This property holds whether the video is paused. +*/ + +/*! + \qmlsignal Video::onStarted() + + This handler is called when playback is started. +*/ + +/*! + \qmlsignal Video::onResumed() + + This handler is called when playback is resumed from the paused state. +*/ + +/*! + \qmlsignal Video::onPaused() + + This handler is called when playback is paused. +*/ + +/*! + \qmlsignal Video::onStopped() + + This handler is called when playback is stopped. +*/ + +/*! + \qmlproperty enum Video::status + + This property holds the status of video loading. It can be one of: + + \list + \o NoMedia - no video has been set. + \o Loading - the video is currently being loaded. + \o Loaded - the video has been loaded. + \o Buffering - the video is buffering data. + \o Stalled - playback has been interrupted while the video is buffering data. + \o Buffered - the video has buffered data. + \o EndOfMedia - the video has played to the end. + \o InvalidMedia - the video cannot be played. + \o UnknownStatus - the status of the video is unknown. + \endlist +*/ + +QmlGraphicsVideo::Status QmlGraphicsVideo::status() const +{ + return Status(m_status); +} + +/*! + \qmlsignal Video::onLoaded() + + This handler is called when the video source has been loaded. +*/ + +/*! + \qmlsignal Video::onBuffering() + + This handler is called when the video stream starts buffering. +*/ + +/*! + \qmlsignal Video::onStalled() + + This handler is called when playback has stalled while the video stream buffers. +*/ + +/*! + \qmlsignal Video::onBuffered() + + This handler is called when the video stream has finished buffering. +*/ + +/*! + \qmlsignal Video::onEndOfMedia + + This handler is called when playback stops because end of the video has been reached. +*/ + +/*! + \qmlproperty int Video::duration + + This property holds the duration of the video in milliseconds. + + If the video doesn't have a fixed duration (a live stream for example) this will be 0. +*/ + +/*! + \qmlproperty int Video::position + + This property holds the current playback position in milliseconds. +*/ + +/*! + \qmlproperty qreal Video::volume + + This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). +*/ + +/*! + \qmlproperty bool Video::muted + + This property holds whether the audio output is muted. +*/ + +/*! + \qmlproperty bool Audio::hasAudio + + This property holds whether the source contains audio. +*/ + +bool QmlGraphicsVideo::hasAudio() const +{ + return m_playerControl->isAudioAvailable(); +} + +/*! + \qmlproperty bool Video::hasVideo + + This property holds whether the source contains video. +*/ + +bool QmlGraphicsVideo::hasVideo() const +{ + return m_playerControl->isVideoAvailable(); +} + +/*! + \qmlproperty qreal Video::bufferProgress + + This property holds how much of the data buffer is currently filled, from 0.0 (empty) to 1.0 + (full). +*/ + +/*! + \qmlproperty bool Video::seekable + + This property holds whether position of the video can be changed. +*/ + +/*! + \qmlproperty qreal playbackRate + + This property holds the rate at which video is played at as a multiple of the normal rate. +*/ + +/*! + \qmlproperty enum Video::error + + This property holds the error state of the video. It can be one of: + + \list + \o NoError - there is no current error. + \o ResourceError - the video cannot be played due to a problem allocating resources. + \o FormatError - the video format is not supported. + \o NetworkError - the video cannot be played due to network issues. + \o AccessDenied - the video cannot be played due to insufficient permissions. + \o ServiceMissing - the video cannot be played because the media service could not be + instantiated. + \endlist +*/ + + +QmlGraphicsVideo::Error QmlGraphicsVideo::error() const +{ + return Error(m_error); +} + +/*! + \qmlproperty string Video::errorString + + This property holds a string describing the current error condition in more detail. +*/ + +/*! + \qmlproperty Video::onError(error, errorString) + + This property is called when an \l {Error}{error} has occurred. The errorString parameter + may contain more detailed information about the error. +*/ + +/*! + \qmlproperty enum Video::FillMode + + Set this property to define how the video is scaled to fit the target area. + + \list + \o Stretch - the video is scaled to fit. + \o PreserveAspectFit - the video is scaled uniformly to fit without cropping + \o PreserveAspectCrop - the video is scaled uniformly to fill, cropping if necessary + \endlist +*/ + +QmlGraphicsVideo::FillMode QmlGraphicsVideo::fillMode() const +{ + return FillMode(m_graphicsItem->aspectRatioMode()); +} + +void QmlGraphicsVideo::setFillMode(FillMode mode) +{ + m_graphicsItem->setAspectRatioMode(Qt::AspectRatioMode(mode)); +} + +/*! + \qmlmethod Video::play() + + Starts playback of the video. +*/ + +void QmlGraphicsVideo::play() +{ + m_playerControl->play(); +} + +/*! + \qmlmethod Video::pause() + + Pauses playback of the video. +*/ + +void QmlGraphicsVideo::pause() +{ + m_playerControl->pause(); +} + +/*! + \qmlmethod Video::stop() + + Stops playback of the video. +*/ + +void QmlGraphicsVideo::stop() +{ + m_playerControl->stop(); +} + +void QmlGraphicsVideo::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) +{ +} + +void QmlGraphicsVideo::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + m_graphicsItem->setSize(newGeometry.size()); + + QmlGraphicsItem::geometryChanged(newGeometry, oldGeometry); +} + +QT_END_NAMESPACE + +#include "moc_qmlgraphicsvideo_p.cpp" diff --git a/src/multimedia/qml/qmlgraphicsvideo_p.h b/src/multimedia/qml/qmlgraphicsvideo_p.h new file mode 100644 index 0000000..d89de8c --- /dev/null +++ b/src/multimedia/qml/qmlgraphicsvideo_p.h @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMLGRAPHICSVIDEO_H +#define QMLGRAPHICSVIDEO_H + +#include + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QTimerEvent; +class QVideoSurfaceFormat; + + +class QmlGraphicsVideo : public QmlGraphicsItem, public QmlMediaBase +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged) + Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(bool hasAudio READ hasAudio NOTIFY hasAudioChanged) + Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) + Q_PROPERTY(int bufferProgress READ bufferProgress NOTIFY bufferProgressChanged) + Q_PROPERTY(bool seekable READ isSeekable NOTIFY seekableChanged) + Q_PROPERTY(qreal playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) + Q_PROPERTY(Error error READ error NOTIFY errorChanged) + Q_PROPERTY(QString errorString READ errorString NOTIFY errorChanged) + Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode) + Q_ENUMS(FillMode) + Q_ENUMS(Status) + Q_ENUMS(Error) +public: + enum FillMode + { + Stretch = Qt::IgnoreAspectRatio, + PreserveAspectFit = Qt::KeepAspectRatio, + PreserveAspectCrop = Qt::KeepAspectRatioByExpanding + }; + + enum Status + { + UnknownStatus = QMediaPlayer::UnknownMediaStatus, + NoMedia = QMediaPlayer::NoMedia, + Loading = QMediaPlayer::LoadingMedia, + Loaded = QMediaPlayer::LoadedMedia, + Stalled = QMediaPlayer::StalledMedia, + Buffering = QMediaPlayer::BufferingMedia, + Buffered = QMediaPlayer::BufferedMedia, + EndOfMedia = QMediaPlayer::EndOfMedia, + InvalidMedia = QMediaPlayer::InvalidMedia + }; + + enum Error + { + NoError = QMediaPlayer::NoError, + ResourceError = QMediaPlayer::ResourceError, + FormatError = QMediaPlayer::FormatError, + NetworkError = QMediaPlayer::NetworkError, + AccessDenied = QMediaPlayer::AccessDeniedError, + ServiceMissing = QMediaPlayer::ServiceMissingError + }; + + QmlGraphicsVideo(QmlGraphicsItem *parent = 0); + ~QmlGraphicsVideo(); + + bool hasAudio() const; + bool hasVideo() const; + + FillMode fillMode() const; + void setFillMode(FillMode mode); + + Status status() const; + Error error() const; + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + +public Q_SLOTS: + void play(); + void pause(); + void stop(); + +Q_SIGNALS: + void sourceChanged(); + + void playingChanged(); + void pausedChanged(); + + void started(); + void resumed(); + void paused(); + void stopped(); + + void statusChanged(); + + void loaded(); + void buffering(); + void stalled(); + void buffered(); + void endOfMedia(); + + void durationChanged(); + void positionChanged(); + + void volumeChanged(); + void mutedChanged(); + void hasAudioChanged(); + void hasVideoChanged(); + + void bufferProgressChanged(); + + void seekableChanged(); + void playbackRateChanged(); + + void errorChanged(); + void error(QmlGraphicsVideo::Error error, const QString &errorString); + +protected: + void geometryChanged(const QRectF &geometry, const QRectF &); + +private Q_SLOTS: + void _q_nativeSizeChanged(const QSizeF &size); + void _q_error(QMediaPlayer::Error, const QString &); + +private: + Q_DISABLE_COPY(QmlGraphicsVideo) + + QGraphicsVideoItem *m_graphicsItem; + + FillMode m_fillMode; + QRectF m_scaledRect; + bool m_updatePaintDevice; + + Q_PRIVATE_SLOT(mediaBase(), void _q_stateChanged(QMediaPlayer::State)) + Q_PRIVATE_SLOT(mediaBase(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) + Q_PRIVATE_SLOT(mediaBase(), void _q_metaDataChanged()) + + inline QmlMediaBase *mediaBase() { return this; } +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QmlGraphicsVideo)) + +QT_END_HEADER + +#endif diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp new file mode 100644 index 0000000..0f0f1e4 --- /dev/null +++ b/src/multimedia/qml/qmlmediabase.cpp @@ -0,0 +1,379 @@ +/**************************************************************************** +** +** 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 QtMultimedia module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "QtMultimedia/private/qmlmediabase_p.h" + +#include +#include + +#include +#include +#include +#include +#include + + + +QT_BEGIN_NAMESPACE + + +class QmlMediaBaseObject : public QMediaObject +{ +public: + QmlMediaBaseObject(QMediaService *service) + : QMediaObject(0, service) + { + } +}; + +class QmlMediaBasePlayerControl : public QMediaPlayerControl +{ +public: + QmlMediaBasePlayerControl(QObject *parent) + : QMediaPlayerControl(parent) + { + } + + QMediaPlayer::State state() const { return QMediaPlayer::StoppedState; } + QMediaPlayer::MediaStatus mediaStatus() const { return QMediaPlayer::NoMedia; } + + qint64 duration() const { return 0; } + qint64 position() const { return 0; } + void setPosition(qint64) {} + int volume() const { return 100; } + void setVolume(int) {} + bool isMuted() const { return false; } + void setMuted(bool) {} + int bufferStatus() const { return 0; } + bool isAudioAvailable() const { return false; } + bool isVideoAvailable() const { return false; } + bool isSeekable() const { return false; } + QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); } + qreal playbackRate() const { return 1; } + void setPlaybackRate(qreal) {} + QMediaContent media() const { return QMediaContent(); } + const QIODevice *mediaStream() const { return 0; } + void setMedia(const QMediaContent &, QIODevice *) {} + + void play() {} + void pause() {} + void stop() {} +}; + +class QmlMediaBaseAnimation : public QObject +{ +public: + QmlMediaBaseAnimation(QmlMediaBase *media) + : m_media(media) + { + } + + void start() { if (!m_timer.isActive()) m_timer.start(500, this); } + void stop() { m_timer.stop(); } + +protected: + void timerEvent(QTimerEvent *event) + { + if (event->timerId() == m_timer.timerId()) { + event->accept(); + + if (m_media->m_state == QMediaPlayer::PlayingState) + emit m_media->positionChanged(); + if (m_media->m_status == QMediaPlayer::BufferingMedia || QMediaPlayer::StalledMedia) + emit m_media->bufferProgressChanged(); + } else { + QObject::timerEvent(event); + } + } + +private: + QmlMediaBase *m_media; + QBasicTimer m_timer; +}; + +void QmlMediaBase::_q_stateChanged(QMediaPlayer::State state) +{ + if (state != m_state) { + QMediaPlayer::State oldState = state; + + m_state = state; + + switch (state) { + case QMediaPlayer::PlayingState: + if (oldState == QMediaPlayer::StoppedState) + emit started(); + else if (oldState == QMediaPlayer::PausedState) + emit resumed(); + break; + case QMediaPlayer::PausedState: + emit paused(); + case QMediaPlayer::StoppedState: + emit stopped(); + break; + default: + break; + } + + emit playingChanged(); + emit pausedChanged(); + + if (m_state == QMediaPlayer::PlayingState + || m_status == QMediaPlayer::BufferingMedia + || m_status == QMediaPlayer::StalledMedia) { + m_animation->start(); + } else { + m_animation->stop(); + } + } +} + +void QmlMediaBase::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status) +{ + if (status != m_status) { + m_status = status; + + switch (status) { + case QMediaPlayer::LoadedMedia: + emit loaded(); + break; + case QMediaPlayer::BufferingMedia: + emit buffering(); + break; + case QMediaPlayer::BufferedMedia: + emit buffered(); + break; + case QMediaPlayer::StalledMedia: + emit stalled(); + break; + case QMediaPlayer::EndOfMedia: + emit endOfMedia(); + break; + default: + break; + } + + emit statusChanged(); + + if (m_state == QMediaPlayer::PlayingState + || m_status == QMediaPlayer::BufferingMedia + || m_status == QMediaPlayer::StalledMedia) { + m_animation->start(); + } else { + m_animation->stop(); + } + } +} + +void QmlMediaBase::_q_metaDataChanged() +{ + m_metaObject->metaDataChanged(); +} + +QmlMediaBase::QmlMediaBase() + : m_mediaService(0) + , m_playerControl(0) + , m_mediaObject(0) + , m_mediaProvider(0) + , m_metaDataControl(0) + , m_metaObject(0) + , m_animation(0) + , m_state(QMediaPlayer::StoppedState) + , m_status(QMediaPlayer::NoMedia) + , m_error(QMediaPlayer::NoError) +{ +} + +QmlMediaBase::~QmlMediaBase() +{ +} + +void QmlMediaBase::shutdown() +{ + delete m_metaObject; + delete m_mediaObject; + + if (m_mediaProvider) + m_mediaProvider->releaseService(m_mediaService); + + delete m_animation; + +} + +void QmlMediaBase::setObject(QObject *object) +{ + if ((m_mediaProvider = QMediaServiceProvider::defaultServiceProvider())) { + if ((m_mediaService = m_mediaProvider->requestService(Q_MEDIASERVICE_MEDIAPLAYER))) { + m_playerControl = qobject_cast( + m_mediaService->control(QMediaPlayerControl_iid)); + m_metaDataControl = qobject_cast( + m_mediaService->control(QMetaDataControl_iid)); + m_mediaObject = new QmlMediaBaseObject(m_mediaService); + } + } + + if (m_playerControl) { + QObject::connect(m_playerControl, SIGNAL(stateChanged(QMediaPlayer::State)), + object, SLOT(_q_stateChanged(QMediaPlayer::State))); + QObject::connect(m_playerControl, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + object, SLOT(_q_mediaStatusChanged(QMediaPlayer::MediaStatus))); + QObject::connect(m_playerControl, SIGNAL(mediaChanged(QMediaContent)), + object, SIGNAL(sourceChanged())); + QObject::connect(m_playerControl, SIGNAL(durationChanged(qint64)), + object, SIGNAL(durationChanged())); + QObject::connect(m_playerControl, SIGNAL(positionChanged(qint64)), + object, SIGNAL(positionChanged())); + QObject::connect(m_playerControl, SIGNAL(volumeChanged(int)), + object, SIGNAL(volumeChanged())); + QObject::connect(m_playerControl, SIGNAL(mutedChanged(bool)), + object, SIGNAL(mutedChanged())); + + m_animation = new QmlMediaBaseAnimation(this); + } else { + m_playerControl = new QmlMediaBasePlayerControl(object); + } + + if (m_metaDataControl) { + m_metaObject = new QMetaDataControlMetaObject(m_metaDataControl, object); + + QObject::connect(m_metaDataControl, SIGNAL(metaDataChanged()), + object, SLOT(_q_metaDataChanged())); + } +} + +QUrl QmlMediaBase::source() const +{ + return m_playerControl->media().canonicalUrl(); +} + +void QmlMediaBase::setSource(const QUrl &url) +{ + m_playerControl->setMedia(QMediaContent(url), 0); +} + +bool QmlMediaBase::isPlaying() const +{ + return m_state != QMediaPlayer::StoppedState; +} + +void QmlMediaBase::setPlaying(bool playing) +{ + if (playing && m_state == QMediaPlayer::StoppedState) + m_playerControl->play(); + else if (!playing) + m_playerControl->stop(); +} + +bool QmlMediaBase::isPaused() const +{ + return m_state == QMediaPlayer::PausedState; +} + +void QmlMediaBase::setPaused(bool paused) +{ + if (paused && m_state == QMediaPlayer::PlayingState) + m_playerControl->pause(); + if (!paused && m_state == QMediaPlayer::PausedState) + m_playerControl->play(); +} + +int QmlMediaBase::duration() const +{ + return m_playerControl->duration(); +} + +int QmlMediaBase::position() const +{ + return m_playerControl->position(); + +} + +void QmlMediaBase::setPosition(int position) +{ + m_playerControl->setPosition(position); +} + +qreal QmlMediaBase::volume() const +{ + return qreal(m_playerControl->volume()) / 100; +} + +void QmlMediaBase::setVolume(qreal volume) +{ + m_playerControl->setVolume(volume * 100); +} + +bool QmlMediaBase::isMuted() const +{ + return m_playerControl->isMuted(); +} + +void QmlMediaBase::setMuted(bool muted) +{ + m_playerControl->setMuted(muted); +} + +qreal QmlMediaBase::bufferProgress() const +{ + return qreal(m_playerControl->bufferStatus()) / 100; +} + +bool QmlMediaBase::isSeekable() const +{ + return m_playerControl->isSeekable(); +} + +qreal QmlMediaBase::playbackRate() const +{ + return m_playerControl->playbackRate(); +} + +void QmlMediaBase::setPlaybackRate(qreal rate) +{ + m_playerControl->setPlaybackRate(rate); +} + +QString QmlMediaBase::errorString() const +{ + return m_errorString; +} + +QT_END_NAMESPACE + -- cgit v0.12 From 7123ef04484f283ffa30ece8cb73f541bd81e830 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Thu, 28 Jan 2010 17:35:17 +1000 Subject: Multimedia; Add directshow backend --- .../mediaservices/directshow/directshow.pro | 14 + .../mediaservices/directshow/dsserviceplugin.cpp | 189 +++ .../mediaservices/directshow/dsserviceplugin.h | 77 ++ .../mediaplayer/directshowaudioendpointcontrol.cpp | 147 +++ .../mediaplayer/directshowaudioendpointcontrol.h | 90 ++ .../directshow/mediaplayer/directshoweventloop.cpp | 160 +++ .../directshow/mediaplayer/directshoweventloop.h | 83 ++ .../directshow/mediaplayer/directshowglobal.h | 78 ++ .../directshow/mediaplayer/directshowioreader.cpp | 501 ++++++++ .../directshow/mediaplayer/directshowioreader.h | 126 ++ .../directshow/mediaplayer/directshowiosource.cpp | 603 ++++++++++ .../directshow/mediaplayer/directshowiosource.h | 145 +++ .../directshow/mediaplayer/directshowmediatype.cpp | 158 +++ .../directshow/mediaplayer/directshowmediatype.h | 85 ++ .../mediaplayer/directshowmediatypelist.cpp | 229 ++++ .../mediaplayer/directshowmediatypelist.h | 78 ++ .../mediaplayer/directshowmetadatacontrol.cpp | 351 ++++++ .../mediaplayer/directshowmetadatacontrol.h | 98 ++ .../directshow/mediaplayer/directshowpinenum.cpp | 140 +++ .../directshow/mediaplayer/directshowpinenum.h | 81 ++ .../mediaplayer/directshowplayercontrol.cpp | 369 ++++++ .../mediaplayer/directshowplayercontrol.h | 147 +++ .../mediaplayer/directshowplayerservice.cpp | 1235 ++++++++++++++++++++ .../mediaplayer/directshowplayerservice.h | 208 ++++ .../mediaplayer/directshowsamplescheduler.cpp | 394 +++++++ .../mediaplayer/directshowsamplescheduler.h | 126 ++ .../mediaplayer/directshowvideooutputcontrol.cpp | 87 ++ .../mediaplayer/directshowvideooutputcontrol.h | 75 ++ .../mediaplayer/directshowvideorenderercontrol.cpp | 93 ++ .../mediaplayer/directshowvideorenderercontrol.h | 82 ++ .../directshow/mediaplayer/mediaplayer.pri | 43 + .../mediaplayer/mediasamplevideobuffer.cpp | 91 ++ .../mediaplayer/mediasamplevideobuffer.h | 77 ++ .../directshow/mediaplayer/videosurfacefilter.cpp | 600 ++++++++++ .../directshow/mediaplayer/videosurfacefilter.h | 182 +++ .../mediaplayer/vmr9videowindowcontrol.cpp | 308 +++++ .../mediaplayer/vmr9videowindowcontrol.h | 112 ++ src/plugins/mediaservices/mediaservices.pro | 2 + 38 files changed, 7664 insertions(+) create mode 100644 src/plugins/mediaservices/directshow/directshow.pro create mode 100644 src/plugins/mediaservices/directshow/dsserviceplugin.cpp create mode 100644 src/plugins/mediaservices/directshow/dsserviceplugin.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp create mode 100644 src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h diff --git a/src/plugins/mediaservices/directshow/directshow.pro b/src/plugins/mediaservices/directshow/directshow.pro new file mode 100644 index 0000000..a3080d3 --- /dev/null +++ b/src/plugins/mediaservices/directshow/directshow.pro @@ -0,0 +1,14 @@ +TARGET = dsengine +include(../../qpluginbase.pri) + +QT += multimedia + +HEADERS += dsserviceplugin.h +SOURCES += dsserviceplugin.cpp + +include(mediaplayer/mediaplayer.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices +target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices +INSTALLS += target + diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.cpp b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp new file mode 100644 index 0000000..fc5d11f --- /dev/null +++ b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 +#include +#include + +#include "dsserviceplugin.h" + +#ifdef QMEDIA_DIRECTSHOW_CAMERA +#include "dscameraservice.h" +#endif + +#ifdef QMEDIA_DIRECTSHOW_PLAYER +#include "directshowplayerservice.h" +#endif + +#include + + +#ifdef QMEDIA_DIRECTSHOW_CAMERA +#ifdef QMEDIA_DIRECTSHOW_CAMERA +#ifndef _STRSAFE_H_INCLUDED_ +#include +#endif +#include +#include +#include +#pragma comment(lib, "strmiids.lib") +#pragma comment(lib, "ole32.lib") +#include +#endif + + +QT_BEGIN_NAMESPACE + +QStringList DSServicePlugin::keys() const +{ + return QStringList() +#ifdef QMEDIA_DIRECTSHOW_CAMERA + << QLatin1String(Q_MEDIASERVICE_CAMERA) +#endif +#ifdef QMEDIA_DIRECTSHOW_PLAYER + << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER) +#endif + ; +} + +QMediaService* DSServicePlugin::create(QString const& key) +{ +#ifdef QMEDIA_DIRECTSHOW_CAMERA + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new DSCameraService; +#endif +#ifdef QMEDIA_DIRECTSHOW_PLAYER + if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)) + return new DirectShowPlayerService; +#endif + + qDebug() << "unsupported key:" << key; + return 0; +} + +void DSServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList DSServicePlugin::devices(const QByteArray &service) const +{ +#ifdef QMEDIA_DIRECTSHOW_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } +#endif + + return QList(); +} + +QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) +{ +#ifdef QMEDIA_DIRECTSHOW_CAMERA + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + for (int i=0; i(&pDevEnum)); + if(SUCCEEDED(hr)) { + // Create the enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, &pEnum, 0); + pEnum->Reset(); + // go through and find all video capture devices + IMoniker* pMoniker = NULL; + while(pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag, + (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if(SUCCEEDED(hr)) { + StringCchCopyW(str,sizeof(str)/sizeof(str[0]),varName.bstrVal); + QString temp(QString::fromUtf16((unsigned short*)str)); + m_cameraDevices.append(QString("ds:%1").arg(temp).toLocal8Bit().constData()); + hr = pPropBag->Read(L"Description", &varName, 0); + StringCchCopyW(str,sizeof(str)/sizeof(str[0]),varName.bstrVal); + QString temp2(QString::fromUtf16((unsigned short*)str)); + m_cameraDescriptions.append(temp2); + } + pPropBag->Release(); + pMoniker->Release(); + } + } + CoUninitialize(); +} +#endif + +QT_END_NAMESPACE + +Q_EXPORT_PLUGIN2(dsengine, DSServicePlugin); + diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.h b/src/plugins/mediaservices/directshow/dsserviceplugin.h new file mode 100644 index 0000000..3c6f1b8 --- /dev/null +++ b/src/plugins/mediaservices/directshow/dsserviceplugin.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DSSERVICEPLUGIN_H +#define DSSERVICEPLUGIN_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class DSServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) +public: + QStringList keys() const; + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: +#ifdef QMEDIA_DIRECTSHOW_CAMERA + void updateDevices() const; + + mutable QList m_cameraDevices; + mutable QStringList m_cameraDescriptions; +#endif +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSSERVICEPLUGIN_H diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp new file mode 100644 index 0000000..2826ba5 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowaudioendpointcontrol.h" + +#include "directshowglobal.h" +#include "directshowplayerservice.h" + + +QT_BEGIN_NAMESPACE + +DirectShowAudioEndpointControl::DirectShowAudioEndpointControl( + DirectShowPlayerService *service, QObject *parent) + : QAudioEndpointSelector(parent) + , m_service(service) + , m_bindContext(0) + , m_deviceEnumerator(0) +{ + if (CreateBindCtx(0, &m_bindContext) == S_OK) { + m_deviceEnumerator = com_new(CLSID_SystemDeviceEnum); + + updateEndpoints(); + + setActiveEndpoint(m_defaultEndpoint); + } +} + +DirectShowAudioEndpointControl::~DirectShowAudioEndpointControl() +{ + foreach (IMoniker *moniker, m_devices) + moniker->Release(); + + if (m_bindContext) + m_bindContext->Release(); + + if (m_deviceEnumerator) + m_deviceEnumerator->Release(); +} + +QList DirectShowAudioEndpointControl::availableEndpoints() const +{ + return m_devices.keys(); +} + +QString DirectShowAudioEndpointControl::endpointDescription(const QString &name) const +{ + return name.section(QLatin1Char('\\'), -1); +} + +QString DirectShowAudioEndpointControl::defaultEndpoint() const +{ + return m_defaultEndpoint; +} + +QString DirectShowAudioEndpointControl::activeEndpoint() const +{ + return m_activeEndpoint; +} + +void DirectShowAudioEndpointControl::setActiveEndpoint(const QString &name) +{ + if (m_activeEndpoint == name) + return; + + if (IMoniker *moniker = m_devices.value(name, 0)) { + IBaseFilter *filter = 0; + + if (moniker->BindToObject( + m_bindContext, + 0, + __uuidof(IBaseFilter), + reinterpret_cast(&filter)) == S_OK) { + m_service->setAudioOutput(filter); + + filter->Release(); + } + } +} + +void DirectShowAudioEndpointControl::updateEndpoints() +{ + IMalloc *oleMalloc = 0; + if (m_deviceEnumerator && CoGetMalloc(1, &oleMalloc) == S_OK) { + IEnumMoniker *monikers = 0; + + if (m_deviceEnumerator->CreateClassEnumerator( + CLSID_AudioRendererCategory, &monikers, 0) == S_OK) { + for (IMoniker *moniker = 0; monikers->Next(1, &moniker, 0) == S_OK; moniker->Release()) { + OLECHAR *string = 0; + if (moniker->GetDisplayName(m_bindContext, 0, &string) == S_OK) { + QString deviceId = QString::fromWCharArray(string); + oleMalloc->Free(string); + + moniker->AddRef(); + m_devices.insert(QString::fromWCharArray(string), moniker); + + if (m_defaultEndpoint.isEmpty() + || deviceId.endsWith(QLatin1String("Default DirectSound Device"))) { + m_defaultEndpoint = deviceId; + } + } + } + monikers->Release(); + } + oleMalloc->Release(); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h new file mode 100644 index 0000000..9ab188c --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWAUDIOENDPOINTCONTROL_H +#define DIRECTSHOWAUDIOENDPOINTCONTROL_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowPlayerService; + + +class DirectShowAudioEndpointControl : public QAudioEndpointSelector +{ + Q_OBJECT +public: + DirectShowAudioEndpointControl(DirectShowPlayerService *service, QObject *parent = 0); + ~DirectShowAudioEndpointControl(); + + QList availableEndpoints() const; + + QString endpointDescription(const QString &name) const; + + QString defaultEndpoint() const; + QString activeEndpoint() const; + + void setActiveEndpoint(const QString& name); + +private: + void updateEndpoints(); + + DirectShowPlayerService *m_service; + IBindCtx *m_bindContext; + ICreateDevEnum *m_deviceEnumerator; + + QMap m_devices; + QString m_defaultEndpoint; + QString m_activeEndpoint; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp new file mode 100644 index 0000000..4f9a19d --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 + +#include +#include + + +QT_BEGIN_NAMESPACE + + +class DirectShowPostedEvent +{ +public: + DirectShowPostedEvent(QObject *receiver, QEvent *event) + : receiver(receiver) + , event(event) + , next(0) + { + } + + ~DirectShowPostedEvent() + { + delete event; + } + + QObject *receiver; + QEvent *event; + DirectShowPostedEvent *next; +}; + +DirectShowEventLoop::DirectShowEventLoop(QObject *parent) + : QWinEventNotifier(parent) + , m_postsHead(0) + , m_postsTail(0) + , m_eventHandle(::CreateEvent(0, 0, 0, 0)) + , m_waitHandle(::CreateEvent(0, 0, 0, 0)) +{ + setHandle(m_eventHandle); + setEnabled(true); +} + +DirectShowEventLoop::~DirectShowEventLoop() +{ + setEnabled(false); + + ::CloseHandle(m_eventHandle); + ::CloseHandle(m_waitHandle); + + for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) { + m_postsHead = m_postsHead->next; + + delete post; + } +} + +void DirectShowEventLoop::wait(QMutex *mutex) +{ + ::ResetEvent(m_waitHandle); + + mutex->unlock(); + + HANDLE handles[] = { m_eventHandle, m_waitHandle }; + while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0) + processEvents(); + + mutex->lock(); +} + +void DirectShowEventLoop::wake() +{ + ::SetEvent(m_waitHandle); +} + +void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event) +{ + QMutexLocker locker(&m_mutex); + + DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event); + + if (m_postsTail) + m_postsTail->next = post; + else + m_postsHead = post; + + m_postsTail = post; + + ::SetEvent(m_eventHandle); +} + +bool DirectShowEventLoop::event(QEvent *event) +{ + if (event->type() == QEvent::WinEventAct) { + processEvents(); + + return true; + } else { + return QWinEventNotifier::event(event); + } +} + +void DirectShowEventLoop::processEvents() +{ + QMutexLocker locker(&m_mutex); + + while(m_postsHead) { + ::ResetEvent(m_eventHandle); + + DirectShowPostedEvent *post = m_postsHead; + m_postsHead = m_postsHead->next; + + locker.unlock(); + QCoreApplication::sendEvent(post->receiver, post->event); + delete post; + locker.relock(); + } + + m_postsTail = 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h new file mode 100644 index 0000000..eb68af3 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWEVENTLOOP_H +#define DIRECTSHOWEVENTLOOP_H + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowPostedEvent; + +class DirectShowEventLoop : public QWinEventNotifier +{ + Q_OBJECT +public: + DirectShowEventLoop(QObject *parent = 0); + ~DirectShowEventLoop(); + + void wait(QMutex *mutex); + void wake(); + + void postEvent(QObject *object, QEvent *event); + + bool event(QEvent *event); + +private: + void processEvents(); + + DirectShowPostedEvent *m_postsHead; + DirectShowPostedEvent *m_postsTail; + HANDLE m_eventHandle; + HANDLE m_waitHandle; + QMutex m_mutex; +}; + +QT_END_NAMESPAC + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h new file mode 100644 index 0000000..1c9fe54 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWGLOBAL_H +#define DIRECTSHOWGLOBAL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +template T *com_cast(IUnknown *unknown) +{ + T *iface = 0; + return unknown && unknown->QueryInterface( + __uuidof(T), reinterpret_cast(&iface)) == S_OK + ? iface + : 0; +} + +template T *com_new(const IID &clsid) +{ + T *object = 0; + return CoCreateInstance( + clsid, + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(T), + reinterpret_cast(&object)) == S_OK + ? object + : 0; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp new file mode 100644 index 0000000..dcb9a40 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp @@ -0,0 +1,501 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowioreader.h" + +#include "directshoweventloop.h" +#include "directshowglobal.h" +#include "directshowiosource.h" + +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +class DirectShowSampleRequest +{ +public: + DirectShowSampleRequest( + IMediaSample *sample, DWORD_PTR userData, LONGLONG position, LONG length, BYTE *buffer) + : next(0) + , sample(sample) + , userData(userData) + , position(position) + , length(length) + , buffer(buffer) + , result(S_FALSE) + { + } + + DirectShowSampleRequest *remove() { DirectShowSampleRequest *n = next; delete this; return n; } + + DirectShowSampleRequest *next; + IMediaSample *sample; + DWORD_PTR userData; + LONGLONG position; + LONG length; + BYTE *buffer; + HRESULT result; +}; + +DirectShowIOReader::DirectShowIOReader( + QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop) + : m_source(source) + , m_device(device) + , m_loop(loop) + , m_pendingHead(0) + , m_pendingTail(0) + , m_readyHead(0) + , m_readyTail(0) + , m_synchronousPosition(0) + , m_synchronousLength(0) + , m_synchronousBytesRead(0) + , m_synchronousBuffer(0) + , m_synchronousResult(S_OK) + , m_totalLength(0) + , m_availableLength(0) + , m_flushing(false) +{ + moveToThread(device->thread()); + + connect(device, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + +DirectShowIOReader::~DirectShowIOReader() +{ + flushRequests(); +} + +HRESULT DirectShowIOReader::QueryInterface(REFIID riid, void **ppvObject) +{ + return m_source->QueryInterface(riid, ppvObject); +} + +ULONG DirectShowIOReader::AddRef() +{ + return m_source->AddRef(); +} + +ULONG DirectShowIOReader::Release() +{ + return m_source->Release(); +} + +// IAsyncReader +HRESULT DirectShowIOReader::RequestAllocator( + IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual) +{ + if (!ppActual || !pProps) { + return E_POINTER; + } else { + ALLOCATOR_PROPERTIES actualProperties; + + if (pProps->cbAlign == 0) + pProps->cbAlign = 1; + + if (pPreferred && pPreferred->SetProperties(pProps, &actualProperties) == S_OK) { + pPreferred->AddRef(); + + *ppActual = pPreferred; + + m_source->setAllocator(*ppActual); + + return S_OK; + } else { + *ppActual = com_new(CLSID_MemoryAllocator); + + if (*ppActual) { + if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) { + (*ppActual)->Release(); + } else { + m_source->setAllocator(*ppActual); + + return S_OK; + } + } + } + ppActual = 0; + + return E_FAIL; + } +} + +HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser) +{ + QMutexLocker locker(&m_mutex); + + if (!pSample) { + return E_POINTER; + } else if (m_flushing) { + return VFW_E_WRONG_STATE; + } else { + REFERENCE_TIME startTime = 0; + REFERENCE_TIME endTime = 0; + BYTE *buffer; + + if (pSample->GetTime(&startTime, &endTime) != S_OK + || pSample->GetPointer(&buffer) != S_OK) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + LONGLONG position = startTime / 10000000; + LONG length = ((endTime - startTime) / 10000000) + 1; + + DirectShowSampleRequest *request = new DirectShowSampleRequest( + pSample, dwUser, position, length, buffer); + + if (m_pendingTail) { + m_pendingTail->next = request; + } else { + m_pendingHead = request; + + m_loop->postEvent(this, new QEvent(QEvent::User)); + } + m_pendingTail = request; + + return S_OK; + } + } +} + +HRESULT DirectShowIOReader::WaitForNext( + DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser) +{ + if (!ppSample || !pdwUser) + return E_POINTER; + + QMutexLocker locker(&m_mutex); + + do { + if (m_readyHead) { + DirectShowSampleRequest *request = m_readyHead; + + *ppSample = request->sample; + *pdwUser = request->userData; + + HRESULT hr = request->result; + + m_readyHead = request->next; + + if (!m_readyHead) + m_readyTail = 0; + + delete request; + + return hr; + } else if (m_flushing) { + *ppSample = 0; + *pdwUser = 0; + + return VFW_E_WRONG_STATE; + } + } while (m_wait.wait(&m_mutex, dwTimeout)); + + *ppSample = 0; + *pdwUser = 0; + + return VFW_E_TIMEOUT; +} + +HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample) +{ + if (!pSample) { + return E_POINTER; + } else { + REFERENCE_TIME startTime = 0; + REFERENCE_TIME endTime = 0; + BYTE *buffer; + + if (pSample->GetTime(&startTime, &endTime) != S_OK + || pSample->GetPointer(&buffer) != S_OK) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + LONGLONG position = startTime / 10000000; + LONG length = ((endTime - startTime) / 10000000) + 1; + + QMutexLocker locker(&m_mutex); + + if (thread() == QThread::currentThread()) { + qint64 bytesRead = 0; + + HRESULT hr = blockingRead(position, length, buffer, &bytesRead); + + if (SUCCEEDED(hr)) + pSample->SetActualDataLength(bytesRead); + + return hr; + } else { + m_synchronousPosition = position; + m_synchronousLength = length; + m_synchronousBuffer = buffer; + + m_loop->postEvent(this, new QEvent(QEvent::User)); + + m_wait.wait(&m_mutex); + + m_synchronousBuffer = 0; + + if (SUCCEEDED(m_synchronousResult)) + pSample->SetActualDataLength(m_synchronousBytesRead); + + return m_synchronousResult; + } + } + } +} + +HRESULT DirectShowIOReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer) +{ + if (!pBuffer) { + return E_POINTER; + } else { + if (thread() == QThread::currentThread()) { + qint64 bytesRead; + + return blockingRead(llPosition, lLength, pBuffer, &bytesRead); + } else { + QMutexLocker locker(&m_mutex); + + m_synchronousPosition = llPosition; + m_synchronousLength = lLength; + m_synchronousBuffer = pBuffer; + + m_loop->postEvent(this, new QEvent(QEvent::User)); + + m_wait.wait(&m_mutex); + + m_synchronousBuffer = 0; + + return m_synchronousResult; + } + } +} + +HRESULT DirectShowIOReader::Length(LONGLONG *pTotal, LONGLONG *pAvailable) +{ + if (!pTotal || !pAvailable) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + *pTotal = m_totalLength; + *pAvailable = m_availableLength; + + return S_OK; + } +} + + +HRESULT DirectShowIOReader::BeginFlush() +{ + QMutexLocker locker(&m_mutex); + + if (m_flushing) + return S_FALSE; + + m_flushing = true; + + flushRequests(); + + m_wait.wakeAll(); + + return S_OK; +} + +HRESULT DirectShowIOReader::EndFlush() +{ + QMutexLocker locker(&m_mutex); + + if (!m_flushing) + return S_FALSE; + + m_flushing = false; + + return S_OK; +} + +void DirectShowIOReader::customEvent(QEvent *event) +{ + if (event->type() == QEvent::User) { + readyRead(); + } else { + QObject::customEvent(event); + } +} + +void DirectShowIOReader::readyRead() +{ + QMutexLocker locker(&m_mutex); + + m_availableLength = m_device->bytesAvailable() + m_device->pos(); + m_totalLength = m_device->size(); + + if (m_synchronousBuffer) { + if (nonBlockingRead( + m_synchronousPosition, + m_synchronousLength, + m_synchronousBuffer, + &m_synchronousBytesRead, + &m_synchronousResult)) { + m_wait.wakeAll(); + } + } else { + qint64 bytesRead = 0; + + while (m_pendingHead && nonBlockingRead( + m_pendingHead->position, + m_pendingHead->length, + m_pendingHead->buffer, + &bytesRead, + &m_pendingHead->result)) { + m_pendingHead->sample->SetActualDataLength(bytesRead); + + if (m_readyTail) + m_readyTail->next = m_pendingHead; + m_readyTail = m_pendingHead; + + m_pendingHead = m_pendingHead->next; + + m_readyTail->next = 0; + + if (!m_pendingHead) + m_pendingTail = 0; + + if (!m_readyHead) + m_readyHead = m_readyTail; + + m_wait.wakeAll(); + } + } +} + +HRESULT DirectShowIOReader::blockingRead( + LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead) +{ + *bytesRead = 0; + + if (qint64(position) > m_device->size()) + return S_FALSE; + + const qint64 maxSize = qMin(m_device->size(), position + length); + + while (m_device->bytesAvailable() + m_device->pos() < maxSize) { + if (!m_device->waitForReadyRead(-1)) + return S_FALSE; + } + + if (m_device->pos() != position && !m_device->seek(position)) + return S_FALSE; + + const qint64 maxBytes = qMin(length, m_device->bytesAvailable()); + + *bytesRead = m_device->read(reinterpret_cast(buffer), maxBytes); + + if (*bytesRead != length) { + qMemSet(buffer + *bytesRead, 0, length - *bytesRead); + + return S_FALSE; + } else { + return S_OK; + } +} + +bool DirectShowIOReader::nonBlockingRead( + LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result) +{ + const qint64 maxSize = qMin(m_device->size(), position + length); + + if (position > m_device->size()) { + *bytesRead = 0; + *result = S_FALSE; + + return true; + } else if (m_device->bytesAvailable() + m_device->pos() >= maxSize) { + if (m_device->pos() != position && !m_device->seek(position)) { + *bytesRead = 0; + *result = S_FALSE; + + return true; + } else { + const qint64 maxBytes = qMin(length, m_device->bytesAvailable()); + + *bytesRead = m_device->read(reinterpret_cast(buffer), maxBytes); + + if (*bytesRead != length) { + qMemSet(buffer + *bytesRead, 0, length - *bytesRead); + + *result = S_FALSE; + } else { + *result = S_OK; + } + + return true; + } + } else { + return false; + } +} + +void DirectShowIOReader::flushRequests() +{ + while (m_pendingHead) { + m_pendingHead->result = VFW_E_WRONG_STATE; + + if (m_readyTail) + m_readyTail->next = m_pendingHead; + + m_readyTail = m_pendingHead; + + m_pendingHead = m_pendingHead->next; + + m_readyTail->next = 0; + + if (!m_pendingHead) + m_pendingTail = 0; + + if (!m_readyHead) + m_readyHead = m_readyTail; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h new file mode 100644 index 0000000..8cbc2f1 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWIOREADER_H +#define DIRECTSHOWIOREADER_H + +#include +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QIODevice; + +class DirectShowEventLoop; +class DirectShowIOSource; +class DirectShowSampleRequest; + +class DirectShowIOReader : public QObject, public IAsyncReader +{ + Q_OBJECT +public: + DirectShowIOReader(QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop); + ~DirectShowIOReader(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IAsyncReader + HRESULT STDMETHODCALLTYPE RequestAllocator( + IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual); + + HRESULT STDMETHODCALLTYPE Request(IMediaSample *pSample, DWORD_PTR dwUser); + + HRESULT STDMETHODCALLTYPE WaitForNext( + DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser); + + HRESULT STDMETHODCALLTYPE SyncReadAligned(IMediaSample *pSample); + + HRESULT STDMETHODCALLTYPE SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer); + + HRESULT STDMETHODCALLTYPE Length(LONGLONG *pTotal, LONGLONG *pAvailable); + + HRESULT STDMETHODCALLTYPE BeginFlush(); + HRESULT STDMETHODCALLTYPE EndFlush(); + +protected: + void customEvent(QEvent *event); + +private Q_SLOTS: + void readyRead(); + +private: + HRESULT blockingRead(LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead); + bool nonBlockingRead( + LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result); + void flushRequests(); + + DirectShowIOSource *m_source; + QIODevice *m_device; + DirectShowEventLoop *m_loop; + DirectShowSampleRequest *m_pendingHead; + DirectShowSampleRequest *m_pendingTail; + DirectShowSampleRequest *m_readyHead; + DirectShowSampleRequest *m_readyTail; + LONGLONG m_synchronousPosition; + LONG m_synchronousLength; + qint64 m_synchronousBytesRead; + BYTE *m_synchronousBuffer; + HRESULT m_synchronousResult; + LONGLONG m_totalLength; + LONGLONG m_availableLength; + bool m_flushing; + QMutex m_mutex; + QWaitCondition m_wait; +}; + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp new file mode 100644 index 0000000..bf83dcf --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp @@ -0,0 +1,603 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowiosource.h" + +#include "directshowglobal.h" +#include "directshowmediatype.h" +#include "directshowpinenum.h" + + +QT_BEGIN_NAMESPACE + +static const GUID directshow_subtypes[] = +{ + MEDIASUBTYPE_Avi, + MEDIASUBTYPE_WAVE, + MEDIASUBTYPE_NULL +}; + +DirectShowIOSource::DirectShowIOSource(QIODevice *device, DirectShowEventLoop *loop) + : m_ref(1) + , m_state(State_Stopped) + , m_graph(0) + , m_clock(0) + , m_allocator(0) + , m_peerPin(0) + , m_pinId(QLatin1String("Data")) + , m_reader(device, this, loop) +{ + QVector mediaTypes; + + AM_MEDIA_TYPE type = + { + MEDIATYPE_Stream, // majortype + MEDIASUBTYPE_NULL, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 1, // lSampleSize + GUID_NULL, // formattype + 0, // pUnk + 0, // cbFormat + 0, // pbFormat + }; + + static const int count = sizeof(directshow_subtypes) / sizeof(GUID); + + for (int i = 0; i < count; ++i) { + type.subtype = directshow_subtypes[i]; + mediaTypes.append(type); + } + + setMediaTypes(mediaTypes); +} + +DirectShowIOSource::~DirectShowIOSource() +{ + Q_ASSERT(m_ref == 0); +} + +void DirectShowIOSource::setAllocator(IMemAllocator *allocator) +{ + if (m_allocator) + m_allocator->Release(); + + m_allocator = allocator; + + if (m_allocator) + m_allocator->AddRef(); +} + +// IUnknown +HRESULT DirectShowIOSource::QueryInterface(REFIID riid, void **ppvObject) +{ + if (!ppvObject) { + return E_POINTER; + } else if (riid == IID_IUnknown + || riid == IID_IPersist + || riid == IID_IMediaFilter + || riid == IID_IBaseFilter) { + *ppvObject = static_cast(this); + } else if (riid == IID_IAMFilterMiscFlags) { + *ppvObject = static_cast(this); + } else if (riid == IID_IPin) { + *ppvObject = static_cast(this); + } else if (riid == IID_IAsyncReader) { + *ppvObject = static_cast(&m_reader); + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG DirectShowIOSource::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG DirectShowIOSource::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + if (ref == 0) { + delete this; + } + + return ref; +} + +// IPersist +HRESULT DirectShowIOSource::GetClassID(CLSID *pClassID) +{ + *pClassID = CLSID_NULL; + + return S_OK; +} + +// IMediaFilter +HRESULT DirectShowIOSource::Run(REFERENCE_TIME tStart) +{ + QMutexLocker locker(&m_mutex); + + m_state = State_Running; + + return S_OK; +} + +HRESULT DirectShowIOSource::Pause() +{ + QMutexLocker locker(&m_mutex); + + m_state = State_Paused; + + return S_OK; +} + +HRESULT DirectShowIOSource::Stop() +{ + QMutexLocker locker(&m_mutex); + + m_state = State_Stopped; + + return S_OK; +} + +HRESULT DirectShowIOSource::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + Q_UNUSED(dwMilliSecsTimeout); + + if (!pState) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + *pState = m_state; + + return S_OK; + } +} + +HRESULT DirectShowIOSource::SetSyncSource(IReferenceClock *pClock) +{ + QMutexLocker locker(&m_mutex); + + if (m_clock) + m_clock->Release(); + + m_clock = pClock; + + if (m_clock) + m_clock->AddRef(); + + return S_OK; +} + +HRESULT DirectShowIOSource::GetSyncSource(IReferenceClock **ppClock) +{ + if (!ppClock) { + return E_POINTER; + } else { + if (!m_clock) { + *ppClock = 0; + + return S_FALSE; + } else { + m_clock->AddRef(); + + *ppClock = m_clock; + + return S_OK; + } + } +} + +// IBaseFilter +HRESULT DirectShowIOSource::EnumPins(IEnumPins **ppEnum) +{ + if (!ppEnum) { + return E_POINTER; + } else { + *ppEnum = new DirectShowPinEnum(QList() << this); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::FindPin(LPCWSTR Id, IPin **ppPin) +{ + if (!ppPin || !Id) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + if (QString::fromWCharArray(Id) == m_pinId) { + AddRef(); + + *ppPin = this; + + return S_OK; + } else { + *ppPin = 0; + + return VFW_E_NOT_FOUND; + } + } +} + +HRESULT DirectShowIOSource::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName) +{ + QMutexLocker locker(&m_mutex); + + m_graph = pGraph; + m_filterName = QString::fromWCharArray(pName); + + return S_OK; +} + +HRESULT DirectShowIOSource::QueryFilterInfo(FILTER_INFO *pInfo) +{ + if (!pInfo) { + return E_POINTER; + } else { + QString name = m_filterName; + + if (name.length() >= MAX_FILTER_NAME) + name.truncate(MAX_FILTER_NAME - 1); + + int length = name.toWCharArray(pInfo->achName); + pInfo->achName[length] = '\0'; + + if (m_graph) + m_graph->AddRef(); + + pInfo->pGraph = m_graph; + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryVendorInfo(LPWSTR *pVendorInfo) +{ + Q_UNUSED(pVendorInfo); + + return E_NOTIMPL; +} + +// IAMFilterMiscFlags +ULONG DirectShowIOSource::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_SOURCE; +} + +// IPin +HRESULT DirectShowIOSource::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) +{ + QMutexLocker locker(&m_mutex); + if (!pReceivePin) { + return E_POINTER; + } else if (m_state != State_Stopped) { + return VFW_E_NOT_STOPPED; + } else if (m_peerPin) { + return VFW_E_ALREADY_CONNECTED; + } else { + HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED; + + m_peerPin = pReceivePin; + m_peerPin->AddRef(); + + if (!pmt) { + IEnumMediaTypes *mediaTypes = 0; + if (pReceivePin->EnumMediaTypes(&mediaTypes) == S_OK) { + for (AM_MEDIA_TYPE *type = 0; + mediaTypes->Next(1, &type, 0) == S_OK; + DirectShowMediaType::deleteType(type)) { + switch (tryConnect(pReceivePin, type)) { + case S_OK: + DirectShowMediaType::freeData(type); + mediaTypes->Release(); + return S_OK; + case VFW_E_NO_TRANSPORT: + hr = VFW_E_NO_TRANSPORT; + break; + default: + break; + } + } + mediaTypes->Release(); + } + AM_MEDIA_TYPE type = + { + MEDIATYPE_Stream, // majortype + MEDIASUBTYPE_NULL, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 1, // lSampleSize + GUID_NULL, // formattype + 0, // pUnk + 0, // cbFormat + 0, // pbFormat + }; + + static const int count = sizeof(directshow_subtypes) / sizeof(GUID); + + for (int i = 0; i < count; ++i) { + type.subtype = directshow_subtypes[i]; + + switch (tryConnect(pReceivePin, &type)) { + case S_OK: + return S_OK; + case VFW_E_NO_TRANSPORT: + hr = VFW_E_NO_TRANSPORT; + break; + default: + break; + } + } + } else if (pmt->majortype == MEDIATYPE_Stream && (hr = tryConnect(pReceivePin, pmt))) { + return S_OK; + } + + m_peerPin->Release(); + m_peerPin = 0; + + m_mediaType.clear(); + + return hr; + } +} + +HRESULT DirectShowIOSource::tryConnect(IPin *pin, const AM_MEDIA_TYPE *type) +{ + m_mediaType = *type; + + HRESULT hr = pin->ReceiveConnection(this, type); + + if (!SUCCEEDED(hr)) { + if (m_allocator) { + m_allocator->Release(); + m_allocator = 0; + } + } else if (!m_allocator) { + hr = VFW_E_NO_TRANSPORT; + + if (IMemInputPin *memPin = com_cast(pin)) { + if ((m_allocator = com_new(CLSID_MemoryAllocator))) { + ALLOCATOR_PROPERTIES properties; + if (memPin->GetAllocatorRequirements(&properties) == S_OK + || m_allocator->GetProperties(&properties) == S_OK) { + if (properties.cbAlign == 0) + properties.cbAlign = 1; + + ALLOCATOR_PROPERTIES actualProperties; + if (SUCCEEDED(hr = m_allocator->SetProperties(&properties, &actualProperties))) + hr = memPin->NotifyAllocator(m_allocator, TRUE); + } + if (!SUCCEEDED(hr)) { + m_allocator->Release(); + m_allocator = 0; + } + } + memPin->Release(); + } + if (!SUCCEEDED(hr)) + pin->Disconnect(); + } + return hr; +} + +HRESULT DirectShowIOSource::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) +{ + Q_UNUSED(pConnector); + Q_UNUSED(pmt); + // Output pin. + return E_NOTIMPL; +} + +HRESULT DirectShowIOSource::Disconnect() +{ + if (!m_peerPin) { + return S_FALSE; + } else if (m_state != State_Stopped) { + return VFW_E_NOT_STOPPED; + } else { + HRESULT hr = m_peerPin->Disconnect(); + + if (!SUCCEEDED(hr)) + return hr; + + if (m_allocator) { + m_allocator->Release(); + m_allocator = 0; + } + + m_peerPin->Release(); + m_peerPin = 0; + + m_mediaType.clear(); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::ConnectedTo(IPin **ppPin) +{ + if (!ppPin) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + *ppPin = 0; + + return VFW_E_NOT_CONNECTED; + } else { + m_peerPin->AddRef(); + + *ppPin = m_peerPin; + + return S_OK; + } + } +} + +HRESULT DirectShowIOSource::ConnectionMediaType(AM_MEDIA_TYPE *pmt) +{ + if (!pmt) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + pmt = 0; + + return VFW_E_NOT_CONNECTED; + } else { + DirectShowMediaType::copy(pmt, m_mediaType); + + return S_OK; + } + } +} + +HRESULT DirectShowIOSource::QueryPinInfo(PIN_INFO *pInfo) +{ + if (!pInfo) { + return E_POINTER; + } else { + AddRef(); + + pInfo->pFilter = this; + pInfo->dir = PINDIR_OUTPUT; + + const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2); + + qMemCopy(pInfo->achName, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryId(LPWSTR *Id) +{ + if (!Id) { + return E_POINTER; + } else { + const int bytes = (m_pinId.length() + 1) * 2; + + *Id = static_cast(::CoTaskMemAlloc(bytes)); + + qMemCopy(*Id, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryAccept(const AM_MEDIA_TYPE *pmt) +{ + if (!pmt) { + return E_POINTER; + } else if (pmt->majortype == MEDIATYPE_Stream) { + return S_OK; + } else { + return S_FALSE; + } +} + +HRESULT DirectShowIOSource::EnumMediaTypes(IEnumMediaTypes **ppEnum) +{ + if (!ppEnum) { + return E_POINTER; + } else { + *ppEnum = createMediaTypeEnum(); + + return S_OK; + } +} + +HRESULT DirectShowIOSource::QueryInternalConnections(IPin **apPin, ULONG *nPin) +{ + Q_UNUSED(apPin); + Q_UNUSED(nPin); + + return E_NOTIMPL; +} + +HRESULT DirectShowIOSource::EndOfStream() +{ + return S_OK; +} + +HRESULT DirectShowIOSource::BeginFlush() +{ + return m_reader.BeginFlush(); +} + +HRESULT DirectShowIOSource::EndFlush() +{ + return m_reader.EndFlush(); +} + +HRESULT DirectShowIOSource::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + Q_UNUSED(tStart); + Q_UNUSED(tStop); + Q_UNUSED(dRate); + + return S_OK; +} + +HRESULT DirectShowIOSource::QueryDirection(PIN_DIRECTION *pPinDir) +{ + if (!pPinDir) { + return E_POINTER; + } else { + *pPinDir = PINDIR_OUTPUT; + + return S_OK; + } +} + +QT_END_NAMESPACE + diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h new file mode 100644 index 0000000..a8ed56a --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWIOSOURCE_H +#define DIRECTSHOWIOSOURCE_H + +#include "directshowioreader.h" +#include "directshowmediatype.h" +#include "directshowmediatypelist.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QIODevice; + +class DirectShowIOSource + : public DirectShowMediaTypeList + , public IBaseFilter + , public IAMFilterMiscFlags + , public IPin +{ +public: + DirectShowIOSource(QIODevice *device, DirectShowEventLoop *loop); + ~DirectShowIOSource(); + + void setAllocator(IMemAllocator *allocator); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IPersist + HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + + // IMediaFilter + HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); + HRESULT STDMETHODCALLTYPE Pause(); + HRESULT STDMETHODCALLTYPE Stop(); + + HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState); + + HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock); + HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock); + + // IBaseFilter + HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum); + HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin); + + HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName); + + HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo); + + // IAMFilterMiscFlags + ULONG STDMETHODCALLTYPE GetMiscFlags(); + + // IPin + HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE Disconnect(); + HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin); + + HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id); + + HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum); + + HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin); + + HRESULT STDMETHODCALLTYPE EndOfStream(); + + HRESULT STDMETHODCALLTYPE BeginFlush(); + HRESULT STDMETHODCALLTYPE EndFlush(); + + HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir); + +private: + HRESULT tryConnect(IPin *pin, const AM_MEDIA_TYPE *type); + + volatile LONG m_ref; + FILTER_STATE m_state; + IFilterGraph *m_graph; + IReferenceClock *m_clock; + IMemAllocator *m_allocator; + IPin *m_peerPin; + DirectShowMediaType m_mediaType; + QString m_filterName; + const QString m_pinId; + QMutex m_mutex; + DirectShowIOReader m_reader; + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp new file mode 100644 index 0000000..8edf93e --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowmediatype.h" + + +QT_BEGIN_NAMESPACE + +namespace +{ + struct TypeLookup + { + QVideoFrame::PixelFormat pixelFormat; + GUID mediaType; + }; + + static const TypeLookup qt_typeLookup[] = + { + { QVideoFrame::Format_RGB24, MEDIASUBTYPE_RGB24 }, + { QVideoFrame::Format_RGB32, MEDIASUBTYPE_RGB32 }, + { QVideoFrame::Format_YV12, MEDIASUBTYPE_YV12 } + }; +} + +void DirectShowMediaType::copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source) +{ + *target = source; + + if (source.cbFormat > 0) { + target->pbFormat = reinterpret_cast(CoTaskMemAlloc(source.cbFormat)); + memcpy(target->pbFormat, source.pbFormat, source.cbFormat); + } + if (target->pUnk) + target->pUnk->AddRef(); +} + +void DirectShowMediaType::deleteType(AM_MEDIA_TYPE *type) +{ + freeData(type); + + CoTaskMemFree(type); +} + +void DirectShowMediaType::freeData(AM_MEDIA_TYPE *type) +{ + if (type->cbFormat > 0) + CoTaskMemFree(type->pbFormat); + + if (type->pUnk) + type->pUnk->Release(); +} + + +GUID DirectShowMediaType::convertPixelFormat(QVideoFrame::PixelFormat format) +{ + const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup); + + for (int i = 0; i < count; ++i) + if (qt_typeLookup[i].pixelFormat == format) + return qt_typeLookup[i].mediaType; + return MEDIASUBTYPE_None; +} + +QVideoSurfaceFormat DirectShowMediaType::formatFromType(const AM_MEDIA_TYPE &type) +{ + const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup); + + for (int i = 0; i < count; ++i) { + if (IsEqualGUID(qt_typeLookup[i].mediaType, type.subtype) && type.cbFormat > 0) { + if (IsEqualGUID(type.formattype, FORMAT_VideoInfo)) { + VIDEOINFOHEADER *header = reinterpret_cast(type.pbFormat); + + QVideoSurfaceFormat format( + QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)), + qt_typeLookup[i].pixelFormat); + + if (header->AvgTimePerFrame > 0) + format.setFrameRate(10000 /header->AvgTimePerFrame); + + format.setScanLineDirection(header->bmiHeader.biHeight < 0 + ? QVideoSurfaceFormat::TopToBottom + : QVideoSurfaceFormat::BottomToTop); + + return format; + } else if (IsEqualGUID(type.formattype, FORMAT_VideoInfo2)) { + VIDEOINFOHEADER2 *header = reinterpret_cast(type.pbFormat); + + QVideoSurfaceFormat format( + QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)), + qt_typeLookup[i].pixelFormat); + + if (header->AvgTimePerFrame > 0) + format.setFrameRate(10000 / header->AvgTimePerFrame); + + format.setScanLineDirection(header->bmiHeader.biHeight < 0 + ? QVideoSurfaceFormat::TopToBottom + : QVideoSurfaceFormat::BottomToTop); + + return format; + } + } + } + return QVideoSurfaceFormat(); +} + +int DirectShowMediaType::bytesPerLine(const QVideoSurfaceFormat &format) +{ + switch (format.pixelFormat()) { + case QVideoFrame::Format_RGB24: + return format.frameWidth() * 4 + 3 - format.frameWidth() % 4; + case QVideoFrame::Format_RGB32: + return format.frameWidth() * 4; + case QVideoFrame::Format_YV12: + return format.frameWidth() + 3 - format.frameWidth() % 4; + default: + return 0; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h new file mode 100644 index 0000000..3ba907e --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWMEDIATYPE_H +#define DIRECTSHOWMEDIATYPE_H + +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class DirectShowMediaType : public AM_MEDIA_TYPE +{ +public: + DirectShowMediaType() { memset(this, 0, sizeof(DirectShowMediaType)); } + DirectShowMediaType(const AM_MEDIA_TYPE &type) { copy(this, type); } + DirectShowMediaType(const DirectShowMediaType &other) { copy(this, other); } + DirectShowMediaType &operator =(const AM_MEDIA_TYPE &type) { + free(this); copy(this, type); return *this; } + DirectShowMediaType &operator =(const DirectShowMediaType &other) { + free(this); copy(this, other); return *this; } + ~DirectShowMediaType() { freeData(this); } + + void clear() { freeData(this); memset(this, 0, sizeof(DirectShowMediaType)); } + + static void copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source); + static void freeData(AM_MEDIA_TYPE *type); + static void deleteType(AM_MEDIA_TYPE *type); + + static GUID convertPixelFormat(QVideoFrame::PixelFormat format); + static QVideoSurfaceFormat formatFromType(const AM_MEDIA_TYPE &type); + + static int bytesPerLine(const QVideoSurfaceFormat &format); +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp new file mode 100644 index 0000000..f67794a --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowmediatypelist.h" + +#include "directshowmediatype.h" +#include "videosurfacefilter.h" + + +QT_BEGIN_NAMESPACE + +class DirectShowMediaTypeEnum : public IEnumMediaTypes +{ +public: + DirectShowMediaTypeEnum(DirectShowMediaTypeList *list, int token, int index = 0); + ~DirectShowMediaTypeEnum(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IEnumMediaTypes + HRESULT STDMETHODCALLTYPE Next( + ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched); + HRESULT STDMETHODCALLTYPE Skip(ULONG cMediaTypes); + HRESULT STDMETHODCALLTYPE Reset(); + + HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **ppEnum); + +private: + LONG m_ref; + DirectShowMediaTypeList *m_list; + int m_mediaTypeToken; + int m_index; +}; + + +DirectShowMediaTypeEnum::DirectShowMediaTypeEnum( + DirectShowMediaTypeList *list, int token, int index) + : m_ref(1) + , m_list(list) + , m_mediaTypeToken(token) + , m_index(index) +{ + m_list->AddRef(); +} + +DirectShowMediaTypeEnum::~DirectShowMediaTypeEnum() +{ + m_list->Release(); +} + +HRESULT DirectShowMediaTypeEnum::QueryInterface(REFIID riid, void **ppvObject) +{ + if (!ppvObject) { + return E_POINTER; + } else if (riid == IID_IUnknown + || riid == IID_IEnumMediaTypes) { + *ppvObject = static_cast(this); + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG DirectShowMediaTypeEnum::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG DirectShowMediaTypeEnum::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + if (ref == 0) { + delete this; + } + + return ref; +} + +HRESULT DirectShowMediaTypeEnum::Next( + ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched) +{ + return m_list->nextMediaType(m_mediaTypeToken, &m_index, cMediaTypes, ppMediaTypes, pcFetched); +} + +HRESULT DirectShowMediaTypeEnum::Skip(ULONG cMediaTypes) +{ + return m_list->skipMediaType(m_mediaTypeToken, &m_index, cMediaTypes); +} + +HRESULT DirectShowMediaTypeEnum::Reset() +{ + m_mediaTypeToken = m_list->currentMediaTypeToken(); + m_index = 0; + + return S_OK; +} + +HRESULT DirectShowMediaTypeEnum::Clone(IEnumMediaTypes **ppEnum) +{ + return m_list->cloneMediaType(m_mediaTypeToken, m_index, ppEnum); +} + + +DirectShowMediaTypeList::DirectShowMediaTypeList() + : m_mediaTypeToken(0) +{ +} + +IEnumMediaTypes *DirectShowMediaTypeList::createMediaTypeEnum() +{ + return new DirectShowMediaTypeEnum(this, m_mediaTypeToken, 0); +} + + +void DirectShowMediaTypeList::setMediaTypes(const QVector &types) +{ + ++m_mediaTypeToken; + + m_mediaTypes = types; +} + + +int DirectShowMediaTypeList::currentMediaTypeToken() +{ + return m_mediaTypeToken; +} + +HRESULT DirectShowMediaTypeList::nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount) +{ + if (!types || (count != 1 && !fetchedCount)) { + return E_POINTER; + } else if (m_mediaTypeToken != token) { + return VFW_E_ENUM_OUT_OF_SYNC; + } else { + int boundedCount = qBound(0, count, m_mediaTypes.count() - *index); + + for (int i = 0; i < boundedCount; ++i, ++(*index)) { + types[i] = reinterpret_cast(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))); + + if (types[i]) { + DirectShowMediaType::copy(types[i], m_mediaTypes.at(*index)); + } else { + for (--i; i >= 0; --i) + CoTaskMemFree(types[i]); + + if (fetchedCount) + *fetchedCount = 0; + + return E_OUTOFMEMORY; + } + } + if (fetchedCount) + *fetchedCount = boundedCount; + + return boundedCount == count ? S_OK : S_FALSE; + } +} + +HRESULT DirectShowMediaTypeList::skipMediaType(int token, int *index, ULONG count) +{ + if (m_mediaTypeToken != token) { + return VFW_E_ENUM_OUT_OF_SYNC; + } else { + *index = qMin(*index + count, m_mediaTypes.size()); + + return *index < m_mediaTypes.size() ? S_OK : S_FALSE; + } +} + +HRESULT DirectShowMediaTypeList::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration) +{ + if (m_mediaTypeToken != token) { + return VFW_E_ENUM_OUT_OF_SYNC; + } else { + *enumeration = new DirectShowMediaTypeEnum(this, token, index); + + return S_OK; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h new file mode 100644 index 0000000..b49f24c --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWMEDIATYPELIST_H +#define DIRECTSHOWMEDIATYPELIST_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowMediaTypeList : public IUnknown +{ +public: + DirectShowMediaTypeList(); + + IEnumMediaTypes *createMediaTypeEnum(); + + void setMediaTypes(const QVector &types); + + virtual int currentMediaTypeToken(); + virtual HRESULT nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount); + virtual HRESULT skipMediaType(int token, int *index, ULONG count); + virtual HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); + +private: + int m_mediaTypeToken; + QVector m_mediaTypes; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp new file mode 100644 index 0000000..7335e3d --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 +#include +#include + +#include "directshowmetadatacontrol.h" + +#include "directshowplayerservice.h" + +#include + + +QT_BEGIN_NAMESPACE + +namespace +{ + struct QWMMetaDataKeyLookup + { + QtMedia::MetaData key; + const wchar_t *token; + }; +} + +static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] = +{ + { QtMedia::Title, L"Title" }, + { QtMedia::SubTitle, L"WM/SubTitle" }, + { QtMedia::Author, L"Author" }, + { QtMedia::Comment, L"Comment" }, + { QtMedia::Description, L"Description" }, + { QtMedia::Category, L"WM/Category" }, + { QtMedia::Genre, L"WM/Genre" }, + //{ QtMedia::Date, 0 }, + { QtMedia::Year, L"WM/Year" }, + { QtMedia::UserRating, L"UserRating" }, + //{ QtMedia::MetaDatawords, 0 }, + { QtMedia::Language, L"Language" }, + { QtMedia::Publisher, L"WM/Publisher" }, + { QtMedia::Copyright, L"Copyright" }, + { QtMedia::ParentalRating, L"ParentalRating" }, + { QtMedia::RatingOrganisation, L"RatingOrganisation" }, + + // Media + { QtMedia::Size, L"FileSize" }, + { QtMedia::MediaType, L"MediaType" }, + { QtMedia::Duration, L"Duration" }, + + // Audio + { QtMedia::AudioBitRate, L"AudioBitRate" }, + { QtMedia::AudioCodec, L"AudioCodec" }, + { QtMedia::ChannelCount, L"ChannelCount" }, + { QtMedia::SampleRate, L"Frequency" }, + + // Music + { QtMedia::AlbumTitle, L"WM/AlbumTitle" }, + { QtMedia::AlbumArtist, L"WM/AlbumArtist" }, + { QtMedia::ContributingArtist, L"Author" }, + { QtMedia::Composer, L"WM/Composer" }, + { QtMedia::Conductor, L"WM/Conductor" }, + { QtMedia::Lyrics, L"WM/Lyrics" }, + { QtMedia::Mood, L"WM/Mood" }, + { QtMedia::TrackNumber, L"WM/TrackNumber" }, + //{ QtMedia::TrackCount, 0 }, + //{ QtMedia::CoverArtUriSmall, 0 }, + //{ QtMedia::CoverArtUriLarge, 0 }, + + // Image/Video + //{ QtMedia::Resolution, 0 }, + //{ QtMedia::PixelAspectRatio, 0 }, + + // Video + //{ QtMedia::FrameRate, 0 }, + { QtMedia::VideoBitRate, L"VideoBitRate" }, + { QtMedia::VideoCodec, L"VideoCodec" }, + + //{ QtMedia::PosterUri, 0 }, + + // Movie + { QtMedia::ChapterNumber, L"ChapterNumber" }, + { QtMedia::Director, L"WM/Director" }, + { QtMedia::LeadPerformer, L"LeadPerformer" }, + { QtMedia::Writer, L"WM/Writer" }, + + // Photos + { QtMedia::CameraManufacturer, L"CameraManufacturer" }, + { QtMedia::CameraModel, L"CameraModel" }, + { QtMedia::Event, L"Event" }, + { QtMedia::Subject, L"Subject" } +}; + +static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key) +{ + WORD streamNumber = 0; + WMT_ATTR_DATATYPE type = WMT_TYPE_DWORD; + WORD size = 0; + + if (header->GetAttributeByName(&streamNumber, key, &type, 0, &size) == S_OK) { + switch (type) { + case WMT_TYPE_DWORD: + if (size == sizeof(DWORD)) { + DWORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return int(word); + } + } + break; + case WMT_TYPE_STRING: + { + QString string; + string.resize(size / 2 - 1); + + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(const_cast(string.utf16())), + &size) == S_OK) { + return string; + } + } + break; + case WMT_TYPE_BINARY: + { + QByteArray bytes; + bytes.resize(size); + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(bytes.data()), + &size) == S_OK) { + return bytes; + } + } + break; + case WMT_TYPE_BOOL: + if (size == sizeof(DWORD)) { + DWORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return bool(word); + } + } + break; + case WMT_TYPE_QWORD: + if (size == sizeof(QWORD)) { + QWORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return qint64(word); + } + } + break; + case WMT_TYPE_WORD: + if (size == sizeof(WORD)){ + WORD word; + if (header->GetAttributeByName( + &streamNumber, + key, + &type, + reinterpret_cast(&word), + &size) == S_OK) { + return short(word); + } + } + break; + case WMT_TYPE_GUID: + if (size == 16) { + } + break; + default: + break; + } + } + return QVariant(); +} + +DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent) + : QMetaDataControl(parent) + , m_content(0) + , m_headerInfo(0) +{ +} + +DirectShowMetaDataControl::~DirectShowMetaDataControl() +{ +} + +bool DirectShowMetaDataControl::isWritable() const +{ + return false; +} + +bool DirectShowMetaDataControl::isMetaDataAvailable() const +{ + return m_content || m_headerInfo; +} + +QVariant DirectShowMetaDataControl::metaData(QtMedia::MetaData key) const +{ + QVariant value; + + if (m_headerInfo) { + static const int count = sizeof(qt_wmMetaDataKeys) / sizeof(QWMMetaDataKeyLookup); + for (int i = 0; i < count; ++i) { + if (qt_wmMetaDataKeys[i].key == key) { + value = getValue(m_headerInfo, qt_wmMetaDataKeys[i].token); + break; + } + } + } else if (m_content) { + BSTR string = 0; + + switch (key) { + case QtMedia::Author: + m_content->get_AuthorName(&string); + break; + case QtMedia::Title: + m_content->get_Title(&string); + break; + case QtMedia::ParentalRating: + m_content->get_Rating(&string); + break; + case QtMedia::Description: + m_content->get_Description(&string); + break; + case QtMedia::Copyright: + m_content->get_Copyright(&string); + break; + default: + break; + } + + if (string) { + value = QString::fromUtf16(string, ::SysStringLen(string)); + + ::SysFreeString(string); + } + } + return value; +} + +void DirectShowMetaDataControl::setMetaData(QtMedia::MetaData, const QVariant &) +{ +} + +QList DirectShowMetaDataControl::availableMetaData() const +{ + return QList(); +} + +QVariant DirectShowMetaDataControl::extendedMetaData(const QString &) const +{ + return QVariant(); +} + +void DirectShowMetaDataControl::setExtendedMetaData(const QString &, const QVariant &) +{ +} + +QStringList DirectShowMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source) +{ + if (m_content) + m_content->Release(); + + if (m_headerInfo) + m_headerInfo->Release(); + + if (!graph || graph->QueryInterface( + IID_IAMMediaContent, reinterpret_cast(&m_content)) != S_OK) { + m_content = 0; + } + + m_headerInfo = com_cast(source); + + // DirectShowMediaPlayerService holds a lock at this point so defer emitting signals to a later + // time. + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(MetaDataChanged))); +} + +void DirectShowMetaDataControl::customEvent(QEvent *event) +{ + if (event->type() == QEvent::Type(MetaDataChanged)) { + event->accept(); + + emit metaDataChanged(); + emit metaDataAvailableChanged(m_content || m_headerInfo); + } else { + QMetaDataControl::customEvent(event); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h new file mode 100644 index 0000000..9bb5fcc --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWMETADATACONTROL_H +#define DIRECTSHOWMETADATACONTROL_H + +#include + +#include +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowPlayerService; + + +class DirectShowMetaDataControl : public QMetaDataControl +{ + Q_OBJECT +public: + DirectShowMetaDataControl(QObject *parent = 0); + ~DirectShowMetaDataControl(); + + bool isWritable() const; + bool isMetaDataAvailable() const; + + QVariant metaData(QtMedia::MetaData key) const; + void setMetaData(QtMedia::MetaData key, const QVariant &value); + QList availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const; + void setExtendedMetaData(const QString &key, const QVariant &value); + QStringList availableExtendedMetaData() const; + + void updateGraph(IFilterGraph2 *graph, IBaseFilter *source); + +protected: + void customEvent(QEvent *event); + +private: + enum Event + { + MetaDataChanged = QEvent::User + }; + + IAMMediaContent *m_content; + IWMHeaderInfo *m_headerInfo; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp new file mode 100644 index 0000000..19f65da --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowpinenum.h" + +#include + + +QT_BEGIN_NAMESPACE + +DirectShowPinEnum::DirectShowPinEnum(const QList &pins) + : m_ref(1) + , m_pins(pins) + , m_index(0) +{ + foreach (IPin *pin, m_pins) + pin->AddRef(); +} + +DirectShowPinEnum::~DirectShowPinEnum() +{ + foreach (IPin *pin, m_pins) + pin->Release(); +} + +HRESULT DirectShowPinEnum::QueryInterface(REFIID riid, void **ppvObject) +{ + if (riid == IID_IUnknown + || riid == IID_IEnumPins) { + AddRef(); + + *ppvObject = static_cast(this); + + return S_OK; + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } +} + +ULONG DirectShowPinEnum::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG DirectShowPinEnum::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + if (ref == 0) { + delete this; + } + + return ref; +} + +HRESULT DirectShowPinEnum::Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched) +{ + if (ppPins && (pcFetched || cPins == 1)) { + ULONG count = qBound(0, cPins, m_pins.count() - m_index); + + for (ULONG i = 0; i < count; ++i, ++m_index) { + ppPins[i] = m_pins.at(m_index); + ppPins[i]->AddRef(); + } + + if (pcFetched) + *pcFetched = count; + + return count == cPins ? S_OK : S_FALSE; + } else { + return E_POINTER; + } +} + +HRESULT DirectShowPinEnum::Skip(ULONG cPins) +{ + m_index = qMin(int(m_index + cPins), m_pins.count()); + + return m_index < m_pins.count() ? S_OK : S_FALSE; +} + +HRESULT DirectShowPinEnum::Reset() +{ + m_index = 0; + + return S_OK; +} + +HRESULT DirectShowPinEnum::Clone(IEnumPins **ppEnum) +{ + if (ppEnum) { + *ppEnum = new DirectShowPinEnum(m_pins); + + return S_OK; + } else { + return E_POINTER; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h new file mode 100644 index 0000000..40d99ea --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWPINENUM_H +#define DIRECTSHOWPINENUM_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowPinEnum : public IEnumPins +{ +public: + DirectShowPinEnum(const QList &pins); + ~DirectShowPinEnum(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IEnumPins + HRESULT STDMETHODCALLTYPE Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched); + HRESULT STDMETHODCALLTYPE Skip(ULONG cPins); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE Clone(IEnumPins **ppEnum); + +private: + LONG m_ref; + QList m_pins; + int m_index; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp new file mode 100644 index 0000000..a4308d7 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowplayercontrol.h" + +#include "directshowplayerservice.h" + +#include +#include + + +QT_BEGIN_NAMESPACE + +static int volumeToDecibels(int volume) +{ + if (volume == 0) { + return -10000; + } else if (volume == 100) { + return 0; +#ifdef QT_USE_MATH_H_FLOATS + } else if (sizeof(qreal) == sizeof(float)) { + return qRound(::log10f(float(volume) / 100) * 5000); +#endif + } else { + return qRound(::log10(qreal(volume) / 100) * 5000); + } +} + +static int decibelsToVolume(int dB) +{ + if (dB == -10000) { + return 0; + } else if (dB == 0) { + return 100; + } else { + return qRound(100 * qPow(10, qreal(dB) / 5000)); + } +} + +DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent) + : QMediaPlayerControl(parent) + , m_service(service) + , m_audio(0) + , m_updateProperties(0) + , m_state(QMediaPlayer::StoppedState) + , m_status(QMediaPlayer::UnknownMediaStatus) + , m_streamTypes(0) + , m_muteVolume(-1) + , m_duration(0) + , m_playbackRate(0) + , m_seekable(false) +{ +} + +DirectShowPlayerControl::~DirectShowPlayerControl() +{ + if (m_audio) + m_audio->Release(); +} + +QMediaPlayer::State DirectShowPlayerControl::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus DirectShowPlayerControl::mediaStatus() const +{ + return m_status; +} + +qint64 DirectShowPlayerControl::duration() const +{ + return m_duration; +} + +qint64 DirectShowPlayerControl::position() const +{ + return m_service->position(); +} + +void DirectShowPlayerControl::setPosition(qint64 position) +{ + m_service->seek(position); +} + +int DirectShowPlayerControl::volume() const +{ + if (m_muteVolume >= 0) { + return m_muteVolume; + } else if (m_audio) { + long dB = 0; + + m_audio->get_Volume(&dB); + + return decibelsToVolume(dB); + } else { + return 0; + } +} + +void DirectShowPlayerControl::setVolume(int volume) +{ + int boundedVolume = qBound(0, volume, 100); + + if (m_muteVolume >= 0) { + m_muteVolume = boundedVolume; + + emit volumeChanged(m_muteVolume); + } else if (m_audio) { + m_audio->put_Volume(volumeToDecibels(volume)); + + emit volumeChanged(boundedVolume); + } +} + +bool DirectShowPlayerControl::isMuted() const +{ + return m_muteVolume >= 0; +} + +void DirectShowPlayerControl::setMuted(bool muted) +{ + if (muted && m_muteVolume < 0) { + if (m_audio) { + long dB = 0; + + m_audio->get_Volume(&dB); + + m_muteVolume = decibelsToVolume(dB); + + m_audio->put_Volume(-10000); + } else { + m_muteVolume = 0; + } + + emit mutedChanged(muted); + } else if (!muted && m_muteVolume >= 0) { + if (m_audio) { + m_audio->put_Volume(volumeToDecibels(m_muteVolume)); + } + m_muteVolume = -1; + + emit mutedChanged(muted); + } +} + +int DirectShowPlayerControl::bufferStatus() const +{ + return m_service->bufferStatus(); +} + +bool DirectShowPlayerControl::isAudioAvailable() const +{ + return m_streamTypes & DirectShowPlayerService::AudioStream; +} + +bool DirectShowPlayerControl::isVideoAvailable() const +{ + return m_streamTypes & DirectShowPlayerService::VideoStream; +} + +bool DirectShowPlayerControl::isSeekable() const +{ + return m_seekable; +} + +QMediaTimeRange DirectShowPlayerControl::availablePlaybackRanges() const +{ + return m_service->availablePlaybackRanges(); +} + +qreal DirectShowPlayerControl::playbackRate() const +{ + return m_playbackRate; +} + +void DirectShowPlayerControl::setPlaybackRate(qreal rate) +{ + if (m_playbackRate != rate) { + m_service->setRate(rate); + + emit playbackRateChanged(m_playbackRate = rate); + } +} + +QMediaContent DirectShowPlayerControl::media() const +{ + return m_media; +} + +const QIODevice *DirectShowPlayerControl::mediaStream() const +{ + return m_stream; +} + +void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) +{ + m_media = media; + m_stream = stream; + + m_updateProperties &= PlaybackRateProperty; + + m_service->load(media, stream); + + emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream); + emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); + emit durationChanged(m_duration); + emit seekableChanged(m_seekable); + emit mediaStatusChanged(m_status); + emit stateChanged(m_state); +} + +void DirectShowPlayerControl::play() +{ + m_service->play(); + emit stateChanged(m_state = QMediaPlayer::PlayingState); +} + +void DirectShowPlayerControl::pause() +{ + m_service->pause(); + emit stateChanged(m_state = QMediaPlayer::PausedState); +} + +void DirectShowPlayerControl::stop() +{ + m_service->stop(); + emit stateChanged(m_state = QMediaPlayer::StoppedState); +} + +void DirectShowPlayerControl::customEvent(QEvent *event) +{ + if (event->type() == QEvent::Type(PropertiesChanged)) { + int properties = m_updateProperties; + m_updateProperties = 0; + + if (properties & PlaybackRateProperty) + emit playbackRateChanged(m_playbackRate); + + if (properties & StreamTypesProperty) { + emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream); + emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); + } + + if (properties & DurationProperty) + emit durationChanged(m_duration); + + if (properties & SeekableProperty) + emit seekableChanged(m_seekable); + + if (properties & StatusProperty) + emit mediaStatusChanged(m_status); + + if (properties & StateProperty) + emit stateChanged(m_state); + + event->accept(); + } else { + QMediaPlayerControl::customEvent(event); + } +} + +void DirectShowPlayerControl::scheduleUpdate(int properties) +{ + if (m_updateProperties == 0) + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PropertiesChanged))); + + m_updateProperties |= properties; +} + +void DirectShowPlayerControl::updateState(QMediaPlayer::State state) +{ + if (m_state != state) { + m_state = state; + + scheduleUpdate(StateProperty); + } +} + +void DirectShowPlayerControl::updateStatus(QMediaPlayer::MediaStatus status) +{ + if (m_status != status) { + m_status = status; + + scheduleUpdate(StatusProperty); + } +} + +void DirectShowPlayerControl::updateMediaInfo(qint64 duration, int streamTypes, bool seekable) +{ + int properties = 0; + + if (m_duration != duration) { + m_duration = duration; + + properties |= DurationProperty; + } + if (m_streamTypes != streamTypes) { + m_streamTypes = streamTypes; + + properties |= StreamTypesProperty; + } + + if (m_seekable != seekable) { + m_seekable = seekable; + + properties |= SeekableProperty; + } + + if (properties != 0) + scheduleUpdate(properties); +} + +void DirectShowPlayerControl::updatePlaybackRate(qreal rate) +{ + if (m_playbackRate != rate) { + m_playbackRate = rate; + + scheduleUpdate(PlaybackRateProperty); + } +} + +void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter) +{ + if (m_audio) + m_audio->Release(); + + m_audio = com_cast(filter); +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h new file mode 100644 index 0000000..af2cd3f --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWPLAYERCONTROL_H +#define DIRECTSHOWPLAYERCONTROL_H + +#include +#include + +#include + +#include "directshowplayerservice.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent = 0); + ~DirectShowPlayerControl(); + + QMediaPlayer::State state() const; + + QMediaPlayer::MediaStatus mediaStatus() const; + + qint64 duration() const; + + qint64 position() const; + void setPosition(qint64 position); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int bufferStatus() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &media, QIODevice *stream); + + void play(); + void pause(); + void stop(); + + void updateState(QMediaPlayer::State state); + void updateStatus(QMediaPlayer::MediaStatus status); + void updateMediaInfo(qint64 duration, int streamTypes, bool seekable); + void updatePlaybackRate(qreal rate); + void updateAudioOutput(IBaseFilter *filter); + + using QMediaPlayerControl::error; + +protected: + void customEvent(QEvent *event); + +private: + enum Properties + { + StateProperty = 0x01, + StatusProperty = 0x02, + StreamTypesProperty = 0x04, + DurationProperty = 0x08, + PlaybackRateProperty = 0x10, + SeekableProperty = 0x20 + }; + + enum Event + { + PropertiesChanged = QEvent::User + }; + + void scheduleUpdate(int properties); + + DirectShowPlayerService *m_service; + IBasicAudio *m_audio; + QIODevice *m_stream; + int m_updateProperties; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_status; + int m_streamTypes; + int m_muteVolume; + qint64 m_duration; + qreal m_playbackRate; + bool m_seekable; + QMediaContent m_media; + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp new file mode 100644 index 0000000..ea4b73c --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -0,0 +1,1235 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowplayerservice.h" + +#include "directshowaudioendpointcontrol.h" +#include "directshowiosource.h" +#include "directshowmetadatacontrol.h" +#include "directshowplayercontrol.h" +#include "directshowvideooutputcontrol.h" +#include "directshowvideorenderercontrol.h" +#include "vmr9videowindowcontrol.h" + +#include + +#include +#include +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +class DirectShowPlayerServiceThread : public QThread +{ +public: + DirectShowPlayerServiceThread(DirectShowPlayerService *service) + : m_service(service) + { + } + +protected: + void run() { m_service->run(); } + +private: + DirectShowPlayerService *m_service; +}; + +DirectShowPlayerService::DirectShowPlayerService(QObject *parent) + : QMediaService(parent) + , m_playerControl(0) + , m_audioEndpointControl(0) + , m_metaDataControl(0) + , m_videoOutputControl(0) + , m_videoRendererControl(0) + , m_videoWindowControl(0) + , m_taskThread(0) + , m_pendingTasks(0) + , m_executingTask(0) + , m_executedTasks(0) + , m_graphStatus(NoMedia) + , m_stream(0) + , m_graph(0) + , m_source(0) + , m_audioOutput(0) + , m_videoOutput(0) + , m_rate(1.0) + , m_position(0) + , m_duration(0) + , m_buffering(false) + , m_seekable(false) +{ + m_playerControl = new DirectShowPlayerControl(this); + m_metaDataControl = new DirectShowMetaDataControl(this); + m_videoOutputControl = new DirectShowVideoOutputControl; + m_audioEndpointControl = new DirectShowAudioEndpointControl(this); + m_videoRendererControl = new DirectShowVideoRendererControl(&m_loop); + m_videoWindowControl = new Vmr9VideoWindowControl; + + m_taskThread = new DirectShowPlayerServiceThread(this); + m_taskThread->start(); + + connect(m_videoOutputControl, SIGNAL(outputChanged()), this, SLOT(videoOutputChanged())); + connect(m_videoRendererControl, SIGNAL(filterChanged()), this, SLOT(videoOutputChanged())); + + connect(&m_graphEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(graphEvent(HANDLE))); +} + +DirectShowPlayerService::~DirectShowPlayerService() +{ + { + QMutexLocker locker(&m_mutex); + + m_pendingTasks = Shutdown; + + if (m_graph) { + m_graphEventNotifier.setEnabled(false); + + if (IAMOpenProgress *progress = com_cast(m_graph)) { + progress->AbortOperation(); + progress->Release(); + } + + m_graph->Abort(); + + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + OAFilterState state; + control->GetState(INFINITE, &state); + control->Release(); + } + } + m_wait.wakeAll(); + + m_loop.wait(&m_mutex); + } + + m_taskThread->wait(); + delete m_taskThread; + + if (m_graph) { + m_graph->Release(); + m_graph = 0; + } + + if (m_source) { + m_source->Release(); + m_source = 0; + } + + if (m_audioOutput) { + m_audioOutput->Release(); + m_audioOutput = 0; + } + + if (m_videoOutput) { + m_videoOutput->Release(); + m_videoOutput = 0; + } + + delete m_playerControl; + delete m_audioEndpointControl; + delete m_metaDataControl; + delete m_videoOutputControl; + delete m_videoRendererControl; + delete m_videoWindowControl; +} + +QMediaControl *DirectShowPlayerService::control(const char *name) const +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_playerControl; + else if (qstrcmp(name, QAudioEndpointSelector_iid) == 0) + return m_audioEndpointControl; + else if (qstrcmp(name, QMetaDataControl_iid) == 0) + return m_metaDataControl; + else if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return m_videoOutputControl; + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return m_videoRendererControl; + else if (qstrcmp(name, QVideoWindowControl_iid) == 0) + return m_videoWindowControl; + else + return 0; +} + +void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream) +{ + QMutexLocker locker(&m_mutex); + + if (m_graph) { + m_graphEventNotifier.setEnabled(false); + + if (m_executingTask != 0) { + if (IAMOpenProgress *progress = com_cast(m_graph)) { + progress->AbortOperation(); + progress->Release(); + } else { + m_graph->Abort(); + } + + m_pendingTasks = Stop; + + m_loop.wait(&m_mutex); + } + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); + } + + if (m_source) { + m_source->Release(); + m_source = 0; + } + + m_graph->Release(); + m_graph = 0; + } + + m_resources = media.resources(); + m_stream = stream; + m_duration = 0; + m_streamTypes = 0; + m_executedTasks = 0; + m_buffering = false; + m_seekable = false; + m_metaDataControl->updateGraph(0, 0); + + if (m_resources.isEmpty() && !stream) { + m_pendingTasks = 0; + m_graphStatus = NoMedia; + + m_url.clear(); + } else { + m_graphStatus = Loading; + + m_graph = com_new(CLSID_FilterGraph); + + if (IMediaEventEx *event = com_cast(m_graph)) { + HANDLE handle; + if (event->GetEventHandle(reinterpret_cast(&handle)) == S_OK) { + m_graphEventNotifier.setHandle(handle); + m_graphEventNotifier.setEnabled(true); + } + event->Release(); + } + + if (stream) + m_pendingTasks = SetStreamSource; + else + m_pendingTasks = SetUrlSource; + + m_wait.wakeAll(); + } + + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_playerControl->updateState(QMediaPlayer::StoppedState); + updateStatus(); +} + +void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) +{ + IBaseFilter *source = 0; + + QMediaResource resource = m_resources.takeFirst(); + QUrl url = resource.url(); + + HRESULT hr = E_FAIL; + + if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) { + if (IFileSourceFilter *fileSource = com_new(CLSID_WMAsfReader)) { + locker->unlock(); + hr = fileSource->Load(url.toString().utf16(), 0); + locker->relock(); + + if (SUCCEEDED(hr)) { + source = com_cast(fileSource); + + if (!SUCCEEDED(hr = m_graph->AddFilter(source, L"Source")) && source) { + source->Release(); + source = 0; + } + } + + fileSource->Release(); + } + } + + if (!SUCCEEDED(hr)) { + locker->unlock(); + hr = m_graph->AddSourceFilter(url.toString().utf16(), L"Source", &source); + locker->relock(); + } + + if (SUCCEEDED(hr)) { + m_executedTasks = SetSource; + m_pendingTasks |= Render; + + if (m_audioOutput) + m_pendingTasks |= SetAudioOutput; + if (m_videoOutput) + m_pendingTasks |= SetVideoOutput; + + if (m_rate != 1.0) + m_pendingTasks |= SetRate; + + m_source = source; + } else if (!m_resources.isEmpty()) { + m_pendingTasks |= SetUrlSource; + } else { + m_pendingTasks = 0; + m_graphStatus = InvalidMedia; + + switch (hr) { + case VFW_E_UNKNOWN_FILE_TYPE: + m_error = QMediaPlayer::FormatError; + break; + case E_OUTOFMEMORY: + case VFW_E_CANNOT_LOAD_SOURCE_FILTER: + case VFW_E_NOT_FOUND: + m_error = QMediaPlayer::ResourceError; + default: + m_error = QMediaPlayer::ResourceError; + qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", hr); + break; + } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } +} + +void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker) +{ + IBaseFilter *source = new DirectShowIOSource(m_stream, &m_loop); + + if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) { + m_executedTasks = SetSource; + m_pendingTasks |= Render; + + if (m_audioOutput) + m_pendingTasks |= SetAudioOutput; + if (m_videoOutput) + m_pendingTasks |= SetVideoOutput; + + if (m_rate != 1.0) + m_pendingTasks |= SetRate; + + m_source = source; + } else { + source->Release(); + + m_pendingTasks = 0; + m_graphStatus = InvalidMedia; + + m_error = QMediaPlayer::ResourceError; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } +} + +void DirectShowPlayerService::doRender(QMutexLocker *locker) +{ + if (m_pendingTasks & SetAudioOutput) { + m_graph->AddFilter(m_audioOutput, L"AudioOutput"); + + m_pendingTasks ^= SetAudioOutput; + m_executedTasks |= SetAudioOutput; + } + if (m_pendingTasks & SetVideoOutput) { + m_graph->AddFilter(m_videoOutput, L"VideoOutput"); + + m_pendingTasks ^= SetVideoOutput; + m_executedTasks |= SetVideoOutput; + } + + IFilterGraph2 *graph = m_graph; + graph->AddRef(); + + QVarLengthArray filters; + m_source->AddRef(); + filters.append(m_source); + + bool rendered = false; + + HRESULT renderHr = S_OK; + + while (!filters.isEmpty()) { + IEnumPins *pins = 0; + IBaseFilter *filter = filters[filters.size() - 1]; + filters.removeLast(); + + if (m_executingTask == Render && SUCCEEDED(filter->EnumPins(&pins))) { + int outputs = 0; + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION direction; + if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) { + ++outputs; + + IPin *peer = 0; + if (pin->ConnectedTo(&peer) == S_OK) { + PIN_INFO peerInfo; + if (peer->QueryPinInfo(&peerInfo) == S_OK) + filters.append(peerInfo.pFilter); + peer->Release(); + } else { + locker->unlock(); + HRESULT hr; + if (SUCCEEDED(hr = graph->RenderEx( + pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, 0))) { + rendered = true; + } else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){ + renderHr = hr; + } + locker->relock(); + } + } + } + if (outputs == 0) + rendered = true; + } + filter->Release(); + } + + + if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) { + graph->RemoveFilter(m_audioOutput); + + m_executedTasks &= ~SetAudioOutput; + } + + if (m_videoOutput && !isConnected(m_videoOutput, PINDIR_INPUT)) { + graph->RemoveFilter(m_videoOutput); + + m_executedTasks &= ~SetVideoOutput; + } + + graph->Release(); + + if (m_executingTask == Render) { + if (rendered) { + if (!(m_executedTasks & FinalizeLoad)) + m_pendingTasks |= FinalizeLoad; + } else { + m_pendingTasks = 0; + + m_graphStatus = InvalidMedia; + + if (!m_audioOutput && !m_videoOutput) { + m_error = QMediaPlayer::ResourceError; + } else { + switch (renderHr) { + case VFW_E_UNSUPPORTED_AUDIO: + case VFW_E_UNSUPPORTED_VIDEO: + case VFW_E_UNSUPPORTED_STREAM: + m_error = QMediaPlayer::FormatError; + default: + m_error = QMediaPlayer::ResourceError; + qWarning("DirectShowPlayerService::doRender: Unresolved error code %x", + renderHr); + } + } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } + + m_executedTasks |= Render; + } + + m_loop.wake(); +} + +void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker) +{ + if (m_graphStatus != Loaded) { + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG duration = 0; + seeking->GetDuration(&duration); + m_duration = duration / 10; + + DWORD capabilities = 0; + seeking->GetCapabilities(&capabilities); + m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute; + + seeking->Release(); + } + } + + if ((m_executedTasks & SetOutputs) == SetOutputs) { + m_streamTypes = AudioStream | VideoStream; + } else { + m_streamTypes = findStreamTypes(m_source); + } + + m_executedTasks |= FinalizeLoad; + + m_graphStatus = Loaded; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(FinalizedLoad))); +} + + +void DirectShowPlayerService::doUpdateDuration(QMutexLocker *) +{ + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG duration = 0; + seeking->GetDuration(&duration); + m_duration = duration / 10; + + DWORD capabilities = 0; + seeking->GetCapabilities(&capabilities); + m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute; + + seeking->Release(); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(DurationChange))); + } +} + +int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const +{ + QVarLengthArray filters; + source->AddRef(); + filters.append(source); + + int streamTypes = 0; + + while (!filters.isEmpty()) { + IEnumPins *pins = 0; + IBaseFilter *filter = filters[filters.size() - 1]; + filters.removeLast(); + + if (SUCCEEDED(filter->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION direction; + if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) { + AM_MEDIA_TYPE connectionType; + if (SUCCEEDED(pin->ConnectionMediaType(&connectionType))) { + IPin *peer = 0; + + if (connectionType.majortype == MEDIATYPE_Audio) { + streamTypes |= AudioStream; + } else if (connectionType.majortype == MEDIATYPE_Video) { + streamTypes |= VideoStream; + } else if (SUCCEEDED(pin->ConnectedTo(&peer))) { + PIN_INFO peerInfo; + if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) + filters.append(peerInfo.pFilter); + peer->Release(); + } + } else { + streamTypes |= findStreamType(pin); + } + } + } + } + filter->Release(); + } + return streamTypes; +} + +int DirectShowPlayerService::findStreamType(IPin *pin) const +{ + IEnumMediaTypes *types; + + if (SUCCEEDED(pin->EnumMediaTypes(&types))) { + bool video = false; + bool audio = false; + bool other = false; + + for (AM_MEDIA_TYPE *type = 0; + types->Next(1, &type, 0) == S_OK; + DirectShowMediaType::deleteType(type)) { + if (type->majortype == MEDIATYPE_Audio) + audio = true; + else if (type->majortype == MEDIATYPE_Video) + video = true; + else + other = true; + } + types->Release(); + + if (other) + return 0; + else if (audio && !video) + return AudioStream; + else if (!audio && video) + return VideoStream; + else + return 0; + } else { + return 0; + } +} + +void DirectShowPlayerService::play() +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks &= ~Pause; + m_pendingTasks |= Play; + + if (m_executedTasks & Render) { + if (m_executedTasks & Stop) { + m_position = 0; + m_pendingTasks |= Seek; + m_executedTasks ^= Stop; + } + + m_wait.wakeAll(); + } +} + +void DirectShowPlayerService::doPlay(QMutexLocker *locker) +{ + if (IMediaControl *control = com_cast(m_graph)) { + locker->unlock(); + HRESULT hr = control->Run(); + locker->relock(); + + control->Release(); + + if (SUCCEEDED(hr)) + m_executedTasks |= Play; + + if (SUCCEEDED(hr)) { + m_executedTasks |= Play; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Started))); + } else { + m_error = QMediaPlayer::ResourceError; + qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", hr); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } + } +} + +void DirectShowPlayerService::pause() +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks &= ~Play; + m_pendingTasks |= Pause; + + if (m_executedTasks & Render) { + if (m_executedTasks & Stop) { + m_position = 0; + m_pendingTasks |= Seek; + m_executedTasks ^= Stop; + } + + m_wait.wakeAll(); + } +} + +void DirectShowPlayerService::doPause(QMutexLocker *locker) +{ + if (IMediaControl *control = com_cast(m_graph)) { + locker->unlock(); + HRESULT hr = control->Pause(); + locker->relock(); + + control->Release(); + + if (SUCCEEDED(hr)) { + m_executedTasks |= Pause; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Paused))); + } else { + m_error = QMediaPlayer::ResourceError; + qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", hr); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); + } + } +} + +void DirectShowPlayerService::stop() +{ + QMutexLocker locker(&m_mutex); + + m_pendingTasks &= ~(Play | Pause | Seek); + + if (m_executedTasks & Render) { + if (m_executingTask & (Play | Pause | Seek)) { + m_pendingTasks |= Stop; + + m_loop.wait(&m_mutex); + } + + if (m_executedTasks & (Play | Pause)) { + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); + } + m_executedTasks &= ~(Play | Pause); + } + } + + m_executedTasks |= Stop; +} + +void DirectShowPlayerService::setRate(qreal rate) +{ + QMutexLocker locker(&m_mutex); + + m_rate = rate; + + m_pendingTasks |= SetRate; + + if (m_executedTasks & FinalizeLoad) + m_wait.wakeAll(); +} + +void DirectShowPlayerService::doSetRate(QMutexLocker *locker) +{ + if (IMediaSeeking *seeking = com_cast(m_graph)) { + // Cache current values as we can't query IMediaSeeking during a seek due to the + // possibility of a deadlock when flushing the VideoSurfaceFilter. + LONGLONG currentPosition = 0; + seeking->GetCurrentPosition(¤tPosition); + m_position = currentPosition / 10; + + LONGLONG minimum = 0; + LONGLONG maximum = 0; + m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum)) + ? QMediaTimeRange(minimum / 10, maximum / 10) + : QMediaTimeRange(); + + locker->unlock(); + HRESULT hr = seeking->SetRate(m_rate); + locker->relock(); + + if (!SUCCEEDED(hr)) { + double rate = 0.0; + m_rate = seeking->GetRate(&rate) + ? rate + : 1.0; + } + + seeking->Release(); + } else if (m_rate != 1.0) { + m_rate = 1.0; + } + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(RateChange))); +} + +qint64 DirectShowPlayerService::position() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + if (m_graphStatus == Loaded) { + if (m_executingTask == Seek || m_executingTask == SetRate) { + return m_position; + } else if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + return position / 10; + } + } + return 0; +} + +QMediaTimeRange DirectShowPlayerService::availablePlaybackRanges() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + if (m_graphStatus == Loaded) { + if (m_executingTask == Seek || m_executingTask == SetRate) { + return m_playbackRange; + } else if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG minimum = 0; + LONGLONG maximum = 0; + + HRESULT hr = seeking->GetAvailable(&minimum, &maximum); + seeking->Release(); + + if (SUCCEEDED(hr)) + return QMediaTimeRange(minimum, maximum); + } + } + return QMediaTimeRange(); +} + +void DirectShowPlayerService::seek(qint64 position) +{ + QMutexLocker locker(&m_mutex); + + m_position = position; + + m_pendingTasks |= Seek; + + if (m_executedTasks & FinalizeLoad) + m_wait.wakeAll(); +} + +void DirectShowPlayerService::doSeek(QMutexLocker *locker) +{ + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG seekPosition = LONGLONG(m_position) * 10; + + // Cache current values as we can't query IMediaSeeking during a seek due to the + // possibility of a deadlock when flushing the VideoSurfaceFilter. + LONGLONG currentPosition = 0; + seeking->GetCurrentPosition(¤tPosition); + m_position = currentPosition / 10; + + LONGLONG minimum = 0; + LONGLONG maximum = 0; + m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum)) + ? QMediaTimeRange(minimum / 10, maximum / 10) + : QMediaTimeRange(); + + locker->unlock(); + seeking->SetPositions( + &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); + locker->relock(); + + seeking->Release(); + } +} + +int DirectShowPlayerService::bufferStatus() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + + if (IWMReaderAdvanced2 *reader = com_cast(m_source)) { + DWORD percentage = 0; + + reader->GetBufferProgress(&percentage, 0); + reader->Release(); + + return percentage; + } else { + return 0; + } +} + +void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) +{ + QMutexLocker locker(&m_mutex); + + if (m_graph) { + if (m_audioOutput) { + if (m_executedTasks & SetAudioOutput) { + removeOutput(m_audioOutput); + + m_executedTasks &= ~SetAudioOutput; + } + m_audioOutput->Release(); + } + + m_audioOutput = filter; + + if (m_audioOutput) { + m_audioOutput->AddRef(); + + m_pendingTasks |= SetAudioOutput; + } else { + m_pendingTasks &= ~ SetAudioOutput; + } + + if (m_executedTasks & SetSource) { + m_pendingTasks |= Render; + + m_wait.wakeAll(); + } + } else { + if (m_audioOutput) + m_audioOutput->Release(); + + m_audioOutput = filter; + + if (m_audioOutput) + m_audioOutput->AddRef(); + } + + m_playerControl->updateAudioOutput(m_audioOutput); +} + +void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) +{ + QMutexLocker locker(&m_mutex); + + if (m_graph) { + if (m_videoOutput) { + if (m_executedTasks & SetVideoOutput) { + removeOutput(m_videoOutput); + + m_executedTasks &= ~SetVideoOutput; + } + m_videoOutput->Release(); + } + + m_videoOutput = filter; + + if (m_videoOutput) { + m_videoOutput->AddRef(); + + m_pendingTasks |= SetVideoOutput; + } else { + m_pendingTasks &= ~ SetVideoOutput; + } + + if (m_executedTasks & SetSource) { + m_pendingTasks |= Render; + + m_wait.wakeAll(); + } + } else { + if (m_videoOutput) + m_videoOutput->Release(); + + m_videoOutput = filter; + + if (m_videoOutput) + m_videoOutput->AddRef(); + } +} + +void DirectShowPlayerService::customEvent(QEvent *event) +{ + if (event->type() == QEvent::Type(FinalizedLoad)) { + event->accept(); + + QMutexLocker locker(&m_mutex); + + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_metaDataControl->updateGraph(m_graph, m_source); + + updateStatus(); + } else if (event->type() == QEvent::Type(Error)) { + event->accept(); + + QMediaPlayer::Error error; + { + QMutexLocker locker(&m_mutex); + error = m_error; + + if (error != QMediaPlayer::NoError) { + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_playerControl->updateState(QMediaPlayer::StoppedState); + updateStatus(); + } + } + m_playerControl->error(error, QString()); + } else if (event->type() == QEvent::Type(RateChange)) { + event->accept(); + + QMutexLocker locker(&m_mutex); + + m_playerControl->updatePlaybackRate(m_rate); + } else if (event->type() == QEvent::Type(Started) || event->type() == QEvent::Type(Paused)) { + event->accept(); + + QMutexLocker locker(&m_mutex); + + updateStatus(); + } else if (event->type() == QEvent::Type(DurationChange)) { + event->accept(); + + QMutexLocker locker(&m_mutex); + + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + } else { + QMediaService::customEvent(event); + } +} + +void DirectShowPlayerService::videoOutputChanged() +{ + IBaseFilter *videoOutput = 0; + + switch (m_videoOutputControl->output()) { + case QVideoOutputControl::RendererOutput: + videoOutput = m_videoRendererControl->filter(); + break; + case QVideoOutputControl::WindowOutput: + videoOutput = m_videoWindowControl->filter(); + break; + default: + break; + } + + setVideoOutput(videoOutput); +} + +void DirectShowPlayerService::graphEvent(HANDLE handle) +{ + if (IMediaEvent *event = com_cast(m_graph)) { + long eventCode; + LONG_PTR param1; + LONG_PTR param2; + + while (event->GetEvent(&eventCode, ¶m1, ¶m2, 0) == S_OK) { + switch (eventCode) { + case EC_BUFFERING_DATA: + { + QMutexLocker locker(&m_mutex); + m_buffering = param1; + + updateStatus(); + } + break; + case EC_COMPLETE: + { + QMutexLocker locker(&m_mutex); + m_executedTasks &= ~(Play | Pause); + m_executedTasks |= Stop; + + m_buffering = false; + m_playerControl->updateStatus(QMediaPlayer::EndOfMedia); + m_playerControl->updateState(QMediaPlayer::StoppedState); + } + break; + case EC_LENGTH_CHANGED: + { + QMutexLocker locker(&m_mutex); + if (m_executedTasks & FinalizeLoad) { + m_pendingTasks |= UpdateDuration; + + m_wait.wakeAll(); + } + } + break; + default: + break; + } + + event->FreeEventParams(eventCode, param1, param2); + } + event->Release(); + } +} + +void DirectShowPlayerService::updateStatus() +{ + switch (m_graphStatus) { + case NoMedia: + m_playerControl->updateStatus(QMediaPlayer::NoMedia); + break; + case Loading: + m_playerControl->updateStatus(QMediaPlayer::LoadingMedia); + break; + case Loaded: + if ((m_pendingTasks | m_executingTask | m_executedTasks) & (Play | Pause)) { + if (m_buffering) + m_playerControl->updateStatus(QMediaPlayer::BufferingMedia); + else + m_playerControl->updateStatus(QMediaPlayer::BufferedMedia); + } else { + m_playerControl->updateStatus(QMediaPlayer::LoadedMedia); + } + break; + case InvalidMedia: + m_playerControl->updateStatus(QMediaPlayer::InvalidMedia); + break; + default: + m_playerControl->updateStatus(QMediaPlayer::UnknownMediaStatus); + } +} + +void DirectShowPlayerService::removeOutput(IBaseFilter *output) +{ + while (m_executingTask != 0) { + if (m_executingTask == Render) { + m_executingTask = 0; + + if (IAMOpenProgress *progress = com_cast(m_graph)) { + progress->AbortOperation(); + progress->Release(); + } + } + m_loop.wait(&m_mutex); + } + + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); + } + + if (IFilterChain *chain = com_cast(m_graph)) { + IBaseFilter *start = findChainStart(output); + + chain->RemoveChain(start, output); + + start->Release(); + chain->Release(); + } else { + m_graph->RemoveFilter(output); + } +} + +IBaseFilter *DirectShowPlayerService::findChainStart(IBaseFilter *end) const +{ + IBaseFilter *start = 0; + end->AddRef(); + + while (start != end) { + start = end; + + IEnumPins *pins = 0; + + if (SUCCEEDED(end->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION direction; + if (SUCCEEDED(pin->QueryDirection(&direction)) && direction == PINDIR_INPUT) { + IPin *peer = 0; + if (SUCCEEDED(pin->ConnectedTo(&peer))) { + PIN_INFO peerInfo; + if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) { + CLSID classId; + if (SUCCEEDED(peerInfo.pFilter->GetClassID(&classId)) + && classId == CLSID_Colour) { + end->Release(); + end = peerInfo.pFilter; + } else { + peerInfo.pFilter->Release(); + } + } + peer->Release(); + } + } + } + pins->Release(); + } + } + return start; +} + +bool DirectShowPlayerService::isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const +{ + bool connected = false; + + IEnumPins *pins = 0; + + if (SUCCEEDED(filter->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION dir; + if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) { + IPin *peer = 0; + if (SUCCEEDED(pin->ConnectedTo(&peer))) { + connected = true; + + peer->Release(); + } + } + } + pins->Release(); + } + return connected; +} + +void DirectShowPlayerService::run() +{ + QMutexLocker locker(&m_mutex); + + while (!(m_pendingTasks & Shutdown)) { + if (m_pendingTasks & SetUrlSource) { + m_pendingTasks ^= SetUrlSource; + m_executingTask = SetUrlSource; + + doSetUrlSource(&locker); + } else if (m_pendingTasks & SetStreamSource) { + m_pendingTasks ^= SetStreamSource; + m_executingTask = SetStreamSource; + + doSetStreamSource(&locker); + } else if (m_pendingTasks & Render) { + m_pendingTasks ^= Render; + m_executingTask = Render; + + doRender(&locker); + } else if (!(m_executedTasks & Render)) { + m_pendingTasks &= ~(FinalizeLoad | SetRate | Stop | Pause | Seek | Play); + } else if (m_pendingTasks & FinalizeLoad) { + m_pendingTasks ^= FinalizeLoad; + m_executingTask = FinalizeLoad; + + doFinalizeLoad(&locker); + } else if (m_pendingTasks & UpdateDuration) { + m_pendingTasks ^= UpdateDuration; + m_executingTask ^= UpdateDuration; + + doUpdateDuration(&locker); + } else if (m_pendingTasks & SetRate) { + m_pendingTasks ^= SetRate; + m_executingTask = SetRate; + + doSetRate(&locker); + } else if (m_pendingTasks & Stop) { + m_pendingTasks ^= Stop; + + m_loop.wake(); + } else if (m_pendingTasks & Pause) { + m_pendingTasks ^= Pause; + m_executingTask = Pause; + + doPause(&locker); + } else if (m_pendingTasks & Seek) { + m_pendingTasks ^= Seek; + m_executingTask = Seek; + + doSeek(&locker); + } else if (m_pendingTasks & Play) { + m_pendingTasks ^= Play; + m_executingTask = Play; + + doPlay(&locker); + } + m_executingTask = 0; + + if (m_pendingTasks == 0) + m_wait.wait(&m_mutex); + } + + m_loop.wake(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h new file mode 100644 index 0000000..3a01889 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWPLAYERSERVICE_H +#define DIRECTSHOWPLAYERSERVICE_H + +#include +#include +#include +#include + +#include "directshoweventloop.h" +#include "directshowglobal.h" + +#include +#include +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowAudioEndpointControl; +class DirectShowMetaDataControl; +class DirectShowPlayerControl; +class DirectShowVideoOutputControl; +class DirectShowVideoRendererControl; +class Vmr9VideoWindowControl; + +class DirectShowPlayerService : public QMediaService +{ + Q_OBJECT +public: + enum StreamType + { + AudioStream = 0x01, + VideoStream = 0x02 + }; + + DirectShowPlayerService(QObject *parent = 0); + ~DirectShowPlayerService(); + + QMediaControl* control(const char *name) const; + + void load(const QMediaContent &media, QIODevice *stream); + void play(); + void pause(); + void stop(); + + qint64 position() const; + QMediaTimeRange availablePlaybackRanges() const; + + void seek(qint64 position); + void setRate(qreal rate); + + int bufferStatus() const; + + void setAudioOutput(IBaseFilter *filter); + void setVideoOutput(IBaseFilter *filter); + +protected: + void customEvent(QEvent *event); + +private Q_SLOTS: + void videoOutputChanged(); + void graphEvent(HANDLE handle); + +private: + void updateStatus(); + + int findStreamTypes(IBaseFilter *source) const; + int findStreamType(IPin *pin) const; + + void removeOutput(IBaseFilter *output); + IBaseFilter *findChainStart(IBaseFilter *end) const; + bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const; + + void run(); + + void doSetUrlSource(QMutexLocker *locker); + void doSetStreamSource(QMutexLocker *locker); + void doRender(QMutexLocker *locker); + void doFinalizeLoad(QMutexLocker *locker); + void doSetRate(QMutexLocker *locker); + void doSeek(QMutexLocker *locker); + void doPlay(QMutexLocker *locker); + void doPause(QMutexLocker *locker); + void doUpdateDuration(QMutexLocker *locker); + + enum Task + { + Shutdown = 0x0001, + SetUrlSource = 0x0002, + SetStreamSource = 0x0004, + SetSource = SetUrlSource | SetStreamSource, + SetAudioOutput = 0x0008, + SetVideoOutput = 0x0010, + SetOutputs = SetAudioOutput | SetVideoOutput, + Render = 0x0020, + FinalizeLoad = 0x0040, + SetRate = 0x0080, + Seek = 0x0100, + Play = 0x0200, + Pause = 0x0400, + Stop = 0x0800, + UpdateDuration = 0x1000 + }; + + enum Event + { + FinalizedLoad = QEvent::User, + Error, + RateChange, + Started, + Paused, + DurationChange + }; + + enum GraphStatus + { + NoMedia, + Loading, + Loaded, + InvalidMedia + }; + + DirectShowPlayerControl *m_playerControl; + DirectShowMetaDataControl *m_metaDataControl; + DirectShowVideoOutputControl *m_videoOutputControl; + DirectShowVideoRendererControl *m_videoRendererControl; + Vmr9VideoWindowControl *m_videoWindowControl; + DirectShowAudioEndpointControl *m_audioEndpointControl; + + QThread *m_taskThread; + int m_pendingTasks; + int m_executingTask; + int m_executedTasks; + GraphStatus m_graphStatus; + QMediaPlayer::Error m_error; + QIODevice *m_stream; + IFilterGraph2 *m_graph; + IBaseFilter *m_source; + IBaseFilter *m_audioOutput; + IBaseFilter *m_videoOutput; + int m_streamTypes; + qreal m_rate; + qint64 m_position; + qint64 m_duration; + bool m_buffering; + bool m_seekable; + QMediaTimeRange m_playbackRange; + QUrl m_url; + QMediaResourceList m_resources; + QMutex m_mutex; + QWaitCondition m_wait; + QWinEventNotifier m_graphEventNotifier; + DirectShowEventLoop m_loop; + + friend class DirectShowPlayerServiceThread; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp new file mode 100644 index 0000000..921330c --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowsamplescheduler.h" + +#include + + +QT_BEGIN_NAMESPACE + +class DirectShowTimedSample +{ +public: + DirectShowTimedSample(IMediaSample *sample) + : m_next(0) + , m_sample(sample) + , m_cookie(0) + { + m_sample->AddRef(); + } + + ~DirectShowTimedSample() + { + m_sample->Release(); + } + + IMediaSample *sample() const { return m_sample; } + + DirectShowTimedSample *nextSample() const { return m_next; } + void setNextSample(DirectShowTimedSample *sample) { Q_ASSERT(!m_next); m_next = sample; } + + DirectShowTimedSample *remove() { + DirectShowTimedSample *next = m_next; delete this; return next; } + + bool schedule(IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle); + void unschedule(IReferenceClock *clock); + + bool isReady(IReferenceClock *clock) const; + +private: + DirectShowTimedSample *m_next; + IMediaSample *m_sample; + DWORD_PTR m_cookie; +}; + +bool DirectShowTimedSample::schedule( + IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle) +{ + REFERENCE_TIME sampleStartTime; + REFERENCE_TIME sampleEndTime; + if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) { + if (clock->AdviseTime( + startTime, sampleStartTime, reinterpret_cast(handle), &m_cookie) == S_OK) { + return true; + } + } + return false; +} + +void DirectShowTimedSample::unschedule(IReferenceClock *clock) +{ + clock->Unadvise(m_cookie); +} + +bool DirectShowTimedSample::isReady(IReferenceClock *clock) const +{ + REFERENCE_TIME sampleStartTime; + REFERENCE_TIME sampleEndTime; + REFERENCE_TIME currentTime; + if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) { + if (clock->GetTime(¤tTime) == S_OK) + return currentTime >= sampleStartTime; + } + return true; +} + +DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent) + : QWinEventNotifier(parent) + , m_pin(pin) + , m_clock(0) + , m_allocator(0) + , m_head(0) + , m_tail(0) + , m_maximumSamples(2) + , m_state(Stopped) + , m_startTime(0) + , m_timeoutEvent(::CreateEvent(0, 0, 0, 0)) +{ + m_semaphore.release(m_maximumSamples); + + setHandle(m_timeoutEvent); + setEnabled(true); +} + +DirectShowSampleScheduler::~DirectShowSampleScheduler() +{ + setEnabled(false); + + ::CloseHandle(m_timeoutEvent); + + Q_ASSERT(!m_clock); + Q_ASSERT(!m_allocator); +} + +HRESULT DirectShowSampleScheduler::QueryInterface(REFIID riid, void **ppvObject) +{ + return m_pin->QueryInterface(riid, ppvObject); +} + +ULONG DirectShowSampleScheduler::AddRef() +{ + return m_pin->AddRef(); +} + +ULONG DirectShowSampleScheduler::Release() +{ + return m_pin->Release(); +} + +// IMemInputPin +HRESULT DirectShowSampleScheduler::GetAllocator(IMemAllocator **ppAllocator) +{ + if (!ppAllocator) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_allocator) { + return VFW_E_NO_ALLOCATOR; + } else { + *ppAllocator = m_allocator; + + return S_OK; + } + } +} + +HRESULT DirectShowSampleScheduler::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly) +{ + Q_UNUSED(bReadOnly); + + HRESULT hr; + ALLOCATOR_PROPERTIES properties; + + if (!pAllocator) { + if (m_allocator) + m_allocator->Release(); + + m_allocator = 0; + + return S_OK; + } else if ((hr = pAllocator->GetProperties(&properties)) != S_OK) { + return hr; + } else { + if (properties.cBuffers == 1) { + ALLOCATOR_PROPERTIES actual; + + properties.cBuffers = 2; + if ((hr = pAllocator->SetProperties(&properties, &actual)) != S_OK) + return hr; + } + + QMutexLocker locker(&m_mutex); + + if (m_allocator) + m_allocator->Release(); + + m_allocator = pAllocator; + m_allocator->AddRef(); + + return S_OK; + } +} + +HRESULT DirectShowSampleScheduler::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps) +{ + if (!pProps) + return E_POINTER; + + pProps->cBuffers = 2; + + return S_OK; +} + +HRESULT DirectShowSampleScheduler::Receive(IMediaSample *pSample) +{ + if (!pSample) + return E_POINTER; + + m_semaphore.acquire(1); + + QMutexLocker locker(&m_mutex); + + if (m_state & Flushing) { + m_semaphore.release(1); + + return S_FALSE; + } else if (m_state == Stopped) { + m_semaphore.release(); + + return VFW_E_WRONG_STATE; + } else { + DirectShowTimedSample *timedSample = new DirectShowTimedSample(pSample); + + if (m_tail) + m_tail->setNextSample(timedSample); + else + m_head = timedSample; + + m_tail = timedSample; + + if (m_state == Running) { + if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) { + // Timing information is unavailable, so schedule frames immediately. + QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection); + } + } else if (m_tail == m_head) { + // If this is the first frame make is available. + QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection); + } + + return S_OK; + } +} + +HRESULT DirectShowSampleScheduler::ReceiveMultiple( + IMediaSample **pSamples, long nSamples, long *nSamplesProcessed) +{ + if (!pSamples || !nSamplesProcessed) + return E_POINTER; + + for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; ++(*nSamplesProcessed)) { + HRESULT hr = Receive(pSamples[*nSamplesProcessed]); + + if (hr != S_OK) + return hr; + } + return S_OK; +} + +HRESULT DirectShowSampleScheduler::ReceiveCanBlock() +{ + return S_OK; +} + +void DirectShowSampleScheduler::run(REFERENCE_TIME startTime) +{ + QMutexLocker locker(&m_mutex); + + m_state = (m_state & Flushing) | Running; + m_startTime = startTime; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) { + sample->schedule(m_clock, m_startTime, m_timeoutEvent); + } +} + +void DirectShowSampleScheduler::pause() +{ + QMutexLocker locker(&m_mutex); + + m_state = (m_state & Flushing) | Paused; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) + sample->unschedule(m_clock); +} + +void DirectShowSampleScheduler::stop() +{ + QMutexLocker locker(&m_mutex); + + m_state = m_state & Flushing; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) { + sample->unschedule(m_clock); + + m_semaphore.release(1); + } + + m_head = 0; + m_tail = 0; +} + +void DirectShowSampleScheduler::setFlushing(bool flushing) +{ + QMutexLocker locker(&m_mutex); + + const bool isFlushing = m_state & Flushing; + + if (isFlushing != flushing) { + if (flushing) { + m_state |= Flushing; + + for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) { + sample->unschedule(m_clock); + + m_semaphore.release(1); + } + m_head = 0; + m_tail = 0; + } else { + m_state &= ~Flushing; + } + } +} + +void DirectShowSampleScheduler::setClock(IReferenceClock *clock) +{ + QMutexLocker locker(&m_mutex); + + if (m_clock) + m_clock->Release(); + + m_clock = clock; + + if (m_clock) + m_clock->AddRef(); +} + +IMediaSample *DirectShowSampleScheduler::takeSample() +{ + QMutexLocker locker(&m_mutex); + + if (m_head && m_head->isReady(m_clock)) { + IMediaSample *sample = m_head->sample(); + sample->AddRef(); + + if (m_state == Running) { + m_head = m_head->remove(); + + if (!m_head) + m_tail = 0; + + m_semaphore.release(1); + } + + return sample; + } else { + return 0; + } +} + +bool DirectShowSampleScheduler::event(QEvent *event) +{ + if (event->type() == QEvent::WinEventAct) { + QObject::event(event); + + emit sampleReady(); + + return true; + } else { + return QWinEventNotifier::event(event); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h new file mode 100644 index 0000000..7af9112 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWSAMPLESCHEDULER_H +#define DIRECTSHOWSAMPLESCHEDULER_H + +#include +#include +#include + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowTimedSample; + +class DirectShowSampleScheduler : public QWinEventNotifier, public IMemInputPin +{ + Q_OBJECT +public: + + enum State + { + Stopped = 0x00, + Running = 0x01, + Paused = 0x02, + RunMask = 0x03, + Flushing = 0x04 + }; + + DirectShowSampleScheduler(IUnknown *pin, QObject *parent = 0); + ~DirectShowSampleScheduler(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IMemInputPin + HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator **ppAllocator); + HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly); + HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps); + + HRESULT STDMETHODCALLTYPE Receive(IMediaSample *pSample); + HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed); + HRESULT STDMETHODCALLTYPE ReceiveCanBlock(); + + void run(REFERENCE_TIME startTime); + void pause(); + void stop(); + void setFlushing(bool flushing); + + IReferenceClock *clock() const { return m_clock; } + void setClock(IReferenceClock *clock); + + bool schedule(IMediaSample *sample); + + IMediaSample *takeSample(); + + bool event(QEvent *event); + +Q_SIGNALS: + void sampleReady(); + +private: + IUnknown *m_pin; + IReferenceClock *m_clock; + IMemAllocator *m_allocator; + DirectShowTimedSample *m_head; + DirectShowTimedSample *m_tail; + int m_maximumSamples; + int m_state; + REFERENCE_TIME m_startTime; + HANDLE m_timeoutEvent; + QSemaphore m_semaphore; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp new file mode 100644 index 0000000..ee2bea8 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowvideooutputcontrol.h" + + +QT_BEGIN_NAMESPACE + +DirectShowVideoOutputControl::DirectShowVideoOutputControl(QObject *parent) + : QVideoOutputControl(parent) + , m_output(NoOutput) +{ + +} + +DirectShowVideoOutputControl::~DirectShowVideoOutputControl() +{ +} + +QList DirectShowVideoOutputControl::availableOutputs() const +{ + return QList() + << RendererOutput + << WindowOutput; +} + + +QVideoOutputControl::Output DirectShowVideoOutputControl::output() const +{ + return m_output; +} + +void DirectShowVideoOutputControl::setOutput(Output output) +{ + if (output != m_output) { + switch (output) { + case NoOutput: + case RendererOutput: + case WindowOutput: + m_output = output; + emit outputChanged(); + break; + default: + break; + } + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h new file mode 100644 index 0000000..acb2937 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWVIDEOUTPUTCONTROL_H +#define DIRECTSHOWVIDEOOUPUTCONTROL_H + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowVideoOutputControl : public QVideoOutputControl +{ + Q_OBJECT +public: + DirectShowVideoOutputControl(QObject *parent = 0); + ~DirectShowVideoOutputControl(); + + QList availableOutputs() const; + + Output output() const; + void setOutput(Output output); + +Q_SIGNALS: + void outputChanged(); + +private: + Output m_output; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp new file mode 100644 index 0000000..f27cb10 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "directshowvideorenderercontrol.h" + +#include "videosurfacefilter.h" + + +QT_BEGIN_NAMESPACE + + +DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent) + : QVideoRendererControl(parent) + , m_loop(loop) + , m_surface(0) + , m_filter(0) +{ +} + +DirectShowVideoRendererControl::~DirectShowVideoRendererControl() +{ + delete m_filter; +} + +QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const +{ + return m_surface; +} + +void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + if (surface != m_surface) { + m_surface = surface; + + VideoSurfaceFilter *existingFilter = m_filter; + + if (surface) { + m_filter = new VideoSurfaceFilter(surface, m_loop); + } else { + m_filter = 0; + } + + emit filterChanged(); + + delete existingFilter; + } +} + +IBaseFilter *DirectShowVideoRendererControl::filter() +{ + return m_filter; +} + + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h new file mode 100644 index 0000000..6b4f4a2 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 DIRECTSHOWVIDEORENDERERCONTROL_H +#define DIRECTSHOWVIDEORENDERERCONTROL_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DirectShowEventLoop; +class VideoSurfaceFilter; + +class DirectShowVideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT +public: + DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent = 0); + ~DirectShowVideoRendererControl(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + IBaseFilter *filter(); + +Q_SIGNALS: + void filterChanged(); + +private: + DirectShowEventLoop *m_loop; + QAbstractVideoSurface *m_surface; + VideoSurfaceFilter *m_filter; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri new file mode 100644 index 0000000..49ee9e5 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri @@ -0,0 +1,43 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_DIRECTSHOW_PLAYER + +HEADERS += \ + $$PWD/directshowaudioendpointcontrol.h \ + $$PWD/directshoweventloop.h \ + $$PWD/directshowglobal.h \ + $$PWD/directshowioreader.h \ + $$PWD/directshowiosource.h \ + $$PWD/directshowmediatype.h \ + $$PWD/directshowmediatypelist.h \ + $$PWD/directshowmetadatacontrol.h \ + $$PWD/directshowpinenum.h \ + $$PWD/directshowplayercontrol.h \ + $$PWD/directshowplayerservice.h \ + $$PWD/directshowsamplescheduler.h \ + $$PWD/directshowvideooutputcontrol.h \ + $$PWD/directshowvideorenderercontrol.h \ + $$PWD/mediasamplevideobuffer.h \ + $$PWD/videosurfacefilter.h \ + $$PWD/vmr9videowindowcontrol.h + +SOURCES += \ + $$PWD/directshowaudioendpointcontrol.cpp \ + $$PWD/directshoweventloop.cpp \ + $$PWD/directshowioreader.cpp \ + $$PWD/directshowiosource.cpp \ + $$PWD/directshowmediatype.cpp \ + $$PWD/directshowmediatypelist.cpp \ + $$PWD/directshowmetadatacontrol.cpp \ + $$PWD/directshowpinenum.cpp \ + $$PWD/directshowplayercontrol.cpp \ + $$PWD/directshowplayerservice.cpp \ + $$PWD/directshowsamplescheduler.cpp \ + $$PWD/directshowvideooutputcontrol.cpp \ + $$PWD/directshowvideorenderercontrol.cpp \ + $$PWD/mediasamplevideobuffer.cpp \ + $$PWD/videosurfacefilter.cpp \ + $$PWD/vmr9videowindowcontrol.cpp + +LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 + diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp new file mode 100644 index 0000000..7eff226 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "mediasamplevideobuffer.h" + + +QT_BEGIN_NAMESPACE + +MediaSampleVideoBuffer::MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine) + : QAbstractVideoBuffer(NoHandle) + , m_sample(sample) + , m_bytesPerLine(m_bytesPerLine) + , m_mapMode(NotMapped) +{ + m_sample->AddRef(); +} + +MediaSampleVideoBuffer::~MediaSampleVideoBuffer() +{ + m_sample->Release(); +} + +uchar *MediaSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (m_mapMode == NotMapped && mode != NotMapped) { + if (numBytes) + *numBytes = m_sample->GetActualDataLength(); + + if (bytesPerLine) + *bytesPerLine = m_bytesPerLine; + + BYTE *bytes = 0; + + if (m_sample->GetPointer(&bytes) == S_OK) { + m_mapMode = mode; + + return reinterpret_cast(bytes); + } + } + return 0; +} + +void MediaSampleVideoBuffer::unmap() +{ + m_mapMode = NotMapped; +} + +QAbstractVideoBuffer::MapMode MediaSampleVideoBuffer::mapMode() const +{ + return m_mapMode; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h new file mode 100644 index 0000000..06dc31c --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 MEDIASAMPLEVIDEOBUFFER_H +#define MEDIASAMPLEVIDEOBUFFER_H + +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class MediaSampleVideoBuffer : public QAbstractVideoBuffer +{ +public: + MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine); + ~MediaSampleVideoBuffer(); + + IMediaSample *sample() { return m_sample; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); + void unmap(); + + MapMode mapMode() const; + +private: + IMediaSample *m_sample; + int m_bytesPerLine; + MapMode m_mapMode; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp new file mode 100644 index 0000000..a5565f1 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp @@ -0,0 +1,600 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "videosurfacefilter.h" + +#include "directshoweventloop.h" +#include "directshowpinenum.h" +#include "mediasamplevideobuffer.h" + +#include +#include +#include +#include + +#include + + +QT_BEGIN_NAMESPACE + +// { e23cad72-153d-406c-bf3f-4c4b523d96f2 } +DEFINE_GUID(CLSID_VideoSurfaceFilter, +0xe23cad72, 0x153d, 0x406c, 0xbf, 0x3f, 0x4c, 0x4b, 0x52, 0x3d, 0x96, 0xf2); + +VideoSurfaceFilter::VideoSurfaceFilter( + QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent) + : QObject(parent) + , m_ref(1) + , m_state(State_Stopped) + , m_surface(surface) + , m_loop(loop) + , m_graph(0) + , m_peerPin(0) + , m_bytesPerLine(0) + , m_startResult(S_OK) + , m_pinId(QString::fromLatin1("reference")) + , m_sampleScheduler(static_cast(this)) +{ + connect(surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged())); + connect(&m_sampleScheduler, SIGNAL(sampleReady()), this, SLOT(sampleReady())); +} + +VideoSurfaceFilter::~VideoSurfaceFilter() +{ + Q_ASSERT(m_ref == 1); +} + +HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject) +{ + if (!ppvObject) { + return E_POINTER; + } else if (riid == IID_IUnknown + || riid == IID_IPersist + || riid == IID_IMediaFilter + || riid == IID_IBaseFilter) { + *ppvObject = static_cast(this); + } else if (riid == IID_IAMFilterMiscFlags) { + *ppvObject = static_cast(this); + } else if (riid == IID_IPin) { + *ppvObject = static_cast(this); + } else if (riid == IID_IMemInputPin) { + *ppvObject = static_cast(&m_sampleScheduler); + } else { + *ppvObject = 0; + + return E_NOINTERFACE; + } + + AddRef(); + + return S_OK; +} + +ULONG VideoSurfaceFilter::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG VideoSurfaceFilter::Release() +{ + ULONG ref = InterlockedDecrement(&m_ref); + + Q_ASSERT(ref != 0); + + return ref; +} + +HRESULT VideoSurfaceFilter::GetClassID(CLSID *pClassID) +{ + *pClassID = CLSID_VideoSurfaceFilter; + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Run(REFERENCE_TIME tStart) +{ + m_state = State_Running; + + m_sampleScheduler.run(tStart); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Pause() +{ + m_state = State_Paused; + + m_sampleScheduler.pause(); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::Stop() +{ + m_state = State_Stopped; + + m_sampleScheduler.stop(); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + if (!pState) + return E_POINTER; + + *pState = m_state; + + return S_OK; +} + +HRESULT VideoSurfaceFilter::SetSyncSource(IReferenceClock *pClock) +{ + + m_sampleScheduler.setClock(pClock); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::GetSyncSource(IReferenceClock **ppClock) +{ + if (!ppClock) { + return E_POINTER; + } else { + *ppClock = m_sampleScheduler.clock(); + + if (*ppClock) { + (*ppClock)->AddRef(); + + return S_OK; + } else { + return S_FALSE; + } + } +} + +HRESULT VideoSurfaceFilter::EnumPins(IEnumPins **ppEnum) +{ + if (ppEnum) { + *ppEnum = new DirectShowPinEnum(QList() << this); + + return S_OK; + } else { + return E_POINTER; + } +} + +HRESULT VideoSurfaceFilter::FindPin(LPCWSTR pId, IPin **ppPin) +{ + if (!ppPin || !pId) { + return E_POINTER; + } else if (QString::fromWCharArray(pId) == m_pinId) { + AddRef(); + + *ppPin = this; + + return S_OK; + } else { + return VFW_E_NOT_FOUND; + } +} + +HRESULT VideoSurfaceFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName) +{ + m_graph = pGraph; + m_name = QString::fromWCharArray(pName); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::QueryFilterInfo(FILTER_INFO *pInfo) +{ + if (pInfo) { + QString name = m_name; + + if (name.length() >= MAX_FILTER_NAME) + name.truncate(MAX_FILTER_NAME - 1); + + int length = name.toWCharArray(pInfo->achName); + pInfo->achName[length] = '\0'; + + if (m_graph) + m_graph->AddRef(); + + pInfo->pGraph = m_graph; + + return S_OK; + } else { + return E_POINTER; + } +} + +HRESULT VideoSurfaceFilter::QueryVendorInfo(LPWSTR *pVendorInfo) +{ + Q_UNUSED(pVendorInfo); + + return E_NOTIMPL; +} + +ULONG VideoSurfaceFilter::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_RENDERER; +} + + +HRESULT VideoSurfaceFilter::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) +{ + // This is an input pin, you shouldn't be calling Connect on it. + return E_POINTER; +} + +HRESULT VideoSurfaceFilter::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt) +{ + if (!pConnector) { + return E_POINTER; + } else if (!pmt) { + return E_POINTER; + } else { + HRESULT hr; + QMutexLocker locker(&m_mutex); + + if (m_peerPin) { + hr = VFW_E_ALREADY_CONNECTED; + } else if (pmt->majortype != MEDIATYPE_Video) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } else { + m_surfaceFormat = DirectShowMediaType::formatFromType(*pmt); + m_bytesPerLine = DirectShowMediaType::bytesPerLine(m_surfaceFormat); + + if (thread() == QThread::currentThread()) { + hr = start(); + } else { + m_loop->postEvent(this, new QEvent(QEvent::Type(StartSurface))); + + m_wait.wait(&m_mutex); + + hr = m_startResult; + } + } + if (hr == S_OK) { + m_peerPin = pConnector; + m_peerPin->AddRef(); + + DirectShowMediaType::copy(&m_mediaType, *pmt); + } + return hr; + } +} + +HRESULT VideoSurfaceFilter::start() +{ + if (!m_surface->start(m_surfaceFormat)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } else { + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::Disconnect() +{ + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) + return S_FALSE; + + if (thread() == QThread::currentThread()) { + stop(); + } else { + m_loop->postEvent(this, new QEvent(QEvent::Type(StopSurface))); + + m_wait.wait(&m_mutex); + } + + m_mediaType.clear(); + + m_sampleScheduler.NotifyAllocator(0, FALSE); + + m_peerPin->Release(); + m_peerPin = 0; + + return S_OK; +} + +void VideoSurfaceFilter::stop() +{ + m_surface->stop(); +} + +HRESULT VideoSurfaceFilter::ConnectedTo(IPin **ppPin) +{ + if (!ppPin) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + return VFW_E_NOT_CONNECTED; + } else { + m_peerPin->AddRef(); + + *ppPin = m_peerPin; + + return S_OK; + } + } +} + +HRESULT VideoSurfaceFilter::ConnectionMediaType(AM_MEDIA_TYPE *pmt) +{ + if (!pmt) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + if (!m_peerPin) { + return VFW_E_NOT_CONNECTED; + } else { + DirectShowMediaType::copy(pmt, m_mediaType); + + return S_OK; + } + } +} + +HRESULT VideoSurfaceFilter::QueryPinInfo(PIN_INFO *pInfo) +{ + if (!pInfo) { + return E_POINTER; + } else { + AddRef(); + + pInfo->pFilter = this; + pInfo->dir = PINDIR_INPUT; + + const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2); + + qMemCopy(pInfo->achName, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::QueryId(LPWSTR *Id) +{ + if (!Id) { + return E_POINTER; + } else { + const int bytes = (m_pinId.length() + 1) * 2; + + *Id = static_cast(::CoTaskMemAlloc(bytes)); + + qMemCopy(*Id, m_pinId.utf16(), bytes); + + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::QueryAccept(const AM_MEDIA_TYPE *pmt) +{ + return !m_surface->isFormatSupported(DirectShowMediaType::formatFromType(*pmt)) + ? S_OK + : S_FALSE; +} + +HRESULT VideoSurfaceFilter::EnumMediaTypes(IEnumMediaTypes **ppEnum) +{ + if (!ppEnum) { + return E_POINTER; + } else { + QMutexLocker locker(&m_mutex); + + *ppEnum = createMediaTypeEnum(); + + return S_OK; + } +} + +HRESULT VideoSurfaceFilter::QueryInternalConnections(IPin **apPin, ULONG *nPin) +{ + Q_UNUSED(apPin); + Q_UNUSED(nPin); + + return E_NOTIMPL; +} + +HRESULT VideoSurfaceFilter::EndOfStream() +{ + return S_OK; +} + +HRESULT VideoSurfaceFilter::BeginFlush() +{ + QMutexLocker locker(&m_mutex); + + m_sampleScheduler.setFlushing(true); + + if (thread() == QThread::currentThread()) { + flush(); + } else { + m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); + + m_wait.wait(&m_mutex); + } + + return S_OK; +} + +HRESULT VideoSurfaceFilter::EndFlush() +{ + QMutexLocker locker(&m_mutex); + + m_sampleScheduler.setFlushing(false); + + return S_OK; +} + +void VideoSurfaceFilter::flush() +{ + m_surface->present(QVideoFrame()); + + m_wait.wakeAll(); +} + +HRESULT VideoSurfaceFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + Q_UNUSED(tStart); + Q_UNUSED(tStop); + Q_UNUSED(dRate); + + return S_OK; +} + +HRESULT VideoSurfaceFilter::QueryDirection(PIN_DIRECTION *pPinDir) +{ + if (!pPinDir) { + return E_POINTER; + } else { + *pPinDir = PINDIR_INPUT; + + return S_OK; + } +} + +int VideoSurfaceFilter::currentMediaTypeToken() +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::currentMediaTypeToken(); +} + +HRESULT VideoSurfaceFilter::nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount) +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::nextMediaType(token, index, count, types, fetchedCount); + +} + +HRESULT VideoSurfaceFilter::skipMediaType(int token, int *index, ULONG count) +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::skipMediaType(token, index, count); +} + +HRESULT VideoSurfaceFilter::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration) +{ + QMutexLocker locker(&m_mutex); + + return DirectShowMediaTypeList::cloneMediaType(token, index, enumeration); +} + +void VideoSurfaceFilter::customEvent(QEvent *event) +{ + if (event->type() == StartSurface) { + QMutexLocker locker(&m_mutex); + + m_startResult = start(); + + m_wait.wakeAll(); + } else if (event->type() == StopSurface) { + QMutexLocker locker(&m_mutex); + + stop(); + + m_wait.wakeAll(); + } else if (event->type() == FlushSurface) { + QMutexLocker locker(&m_mutex); + + flush(); + + m_wait.wakeAll(); + } else { + QObject::customEvent(event); + } +} + +void VideoSurfaceFilter::supportedFormatsChanged() +{ + QMutexLocker locker(&m_mutex); + + QList formats = m_surface->supportedPixelFormats(); + + QVector mediaTypes; + mediaTypes.reserve(formats.count()); + + AM_MEDIA_TYPE type; + type.majortype = MEDIATYPE_Video; + type.bFixedSizeSamples = TRUE; + type.bTemporalCompression = FALSE; + type.lSampleSize = 0; + type.formattype = GUID_NULL; + type.pUnk = 0; + type.cbFormat = 0; + type.pbFormat = 0; + + foreach (QVideoFrame::PixelFormat format, formats) { + type.subtype = DirectShowMediaType::convertPixelFormat(format); + + if (type.subtype != MEDIASUBTYPE_None) + mediaTypes.append(type); + } + + setMediaTypes(mediaTypes); +} + +void VideoSurfaceFilter::sampleReady() +{ + IMediaSample *sample = m_sampleScheduler.takeSample(); + + if (sample) { + m_surface->present(QVideoFrame( + new MediaSampleVideoBuffer(sample, m_bytesPerLine), + m_surfaceFormat.frameSize(), + m_surfaceFormat.pixelFormat())); + + sample->Release(); + } +} + +QT_END_NAMESPACE + diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h new file mode 100644 index 0000000..8f3a101 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 VIDEOSURFACEFILTER_H +#define VIDEOSURFACEFILTER_H + +#include "directshowmediatypelist.h" +#include "directshowsamplescheduler.h" +#include "directshowmediatype.h" + +#include +#include +#include +#include +#include +#include + +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QAbstractVideoSurface; + +class DirectShowEventLoop; + +class VideoSurfaceFilter + : public QObject + , public DirectShowMediaTypeList + , public IBaseFilter + , public IAMFilterMiscFlags + , public IPin +{ + Q_OBJECT +public: + VideoSurfaceFilter( + QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent = 0); + ~VideoSurfaceFilter(); + + // IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + // IPersist + HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + + // IMediaFilter + HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); + HRESULT STDMETHODCALLTYPE Pause(); + HRESULT STDMETHODCALLTYPE Stop(); + + HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState); + + HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock); + HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock); + + // IBaseFilter + HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum); + HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin); + + HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName); + + HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo); + + // IAMFilterMiscFlags + ULONG STDMETHODCALLTYPE GetMiscFlags(); + + // IPin + HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt); + HRESULT STDMETHODCALLTYPE Disconnect(); + HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin); + + HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo); + HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id); + + HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt); + + HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum); + + HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin); + + HRESULT STDMETHODCALLTYPE EndOfStream(); + + HRESULT STDMETHODCALLTYPE BeginFlush(); + HRESULT STDMETHODCALLTYPE EndFlush(); + + HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir); + + int currentMediaTypeToken(); + HRESULT nextMediaType( + int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount); + HRESULT skipMediaType(int token, int *index, ULONG count); + HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); + +protected: + void customEvent(QEvent *event); + +private Q_SLOTS: + void supportedFormatsChanged(); + void sampleReady(); + +private: + HRESULT start(); + void stop(); + void flush(); + + enum + { + StartSurface = QEvent::User, + StopSurface, + FlushSurface + }; + + LONG m_ref; + FILTER_STATE m_state; + QAbstractVideoSurface *m_surface; + DirectShowEventLoop *m_loop; + IFilterGraph *m_graph; + IPin *m_peerPin; + int m_bytesPerLine; + HRESULT m_startResult; + QString m_name; + QString m_pinId; + DirectShowMediaType m_mediaType; + QVideoSurfaceFormat m_surfaceFormat; + QMutex m_mutex; + QWaitCondition m_wait; + DirectShowSampleScheduler m_sampleScheduler; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp new file mode 100644 index 0000000..a564e14 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp @@ -0,0 +1,308 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 "vmr9videowindowcontrol.h" + +#include "directshowglobal.h" + + +QT_BEGIN_NAMESPACE + +Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent) + : QVideoWindowControl(parent) + , m_filter(com_new(CLSID_VideoMixingRenderer9)) + , m_windowId(0) + , m_dirtyValues(0) + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_fullScreen(false) +{ + if (IVMRFilterConfig9 *config = com_cast(m_filter)) { + config->SetRenderingMode(VMR9Mode_Windowless); + config->SetNumberOfStreams(1); + config->Release(); + } +} + +Vmr9VideoWindowControl::~Vmr9VideoWindowControl() +{ + if (m_filter) + m_filter->Release(); +} + + +WId Vmr9VideoWindowControl::winId() const +{ + return m_windowId; + +} + +void Vmr9VideoWindowControl::setWinId(WId id) +{ + m_windowId = id; + + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + control->SetVideoClippingWindow(m_windowId); + control->Release(); + } +} + +QRect Vmr9VideoWindowControl::displayRect() const +{ + QRect rect; + + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + RECT sourceRect; + RECT displayRect; + + if (control->GetVideoPosition(&sourceRect, &displayRect) == S_OK) { + rect = QRect( + displayRect.left, + displayRect.bottom, + displayRect.right - displayRect.left, + displayRect.bottom - displayRect.top); + } + control->Release(); + } + return rect; +} + +void Vmr9VideoWindowControl::setDisplayRect(const QRect &rect) +{ + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + RECT sourceRect = { 0, 0, 0, 0 }; + RECT displayRect = { rect.left(), rect.top(), rect.right(), rect.bottom() }; + + control->GetNativeVideoSize(&sourceRect.right, &sourceRect.bottom, 0, 0); + control->SetVideoPosition(&sourceRect, &displayRect); + control->Release(); + } +} + +bool Vmr9VideoWindowControl::isFullScreen() const +{ + return m_fullScreen; +} + +void Vmr9VideoWindowControl::setFullScreen(bool fullScreen) +{ + emit fullScreenChanged(m_fullScreen = fullScreen); +} + +void Vmr9VideoWindowControl::repaint() +{ + + if (QWidget *widget = QWidget::find(m_windowId)) { + HDC dc = widget->getDC(); + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + control->RepaintVideo(m_windowId, dc); + control->Release(); + } + widget->releaseDC(dc); + } +} + +QSize Vmr9VideoWindowControl::nativeSize() const +{ + QSize size; + + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + LONG width; + LONG height; + + if (control->GetNativeVideoSize(&width, &height, 0, 0) == S_OK) + size = QSize(width, height); + control->Release(); + } + return size; +} + +QVideoWidget::AspectRatioMode Vmr9VideoWindowControl::aspectRatioMode() const +{ + QVideoWidget::AspectRatioMode mode = QVideoWidget::KeepAspectRatio; + + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + DWORD arMode; + + if (control->GetAspectRatioMode(&arMode) == S_OK && arMode == VMR9ARMode_None) + mode = QVideoWidget::IgnoreAspectRatio; + control->Release(); + } + return mode; +} + +void Vmr9VideoWindowControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode) +{ + if (IVMRWindowlessControl9 *control = com_cast(m_filter)) { + switch (mode) { + case QVideoWidget::IgnoreAspectRatio: + control->SetAspectRatioMode(VMR9ARMode_None); + break; + case QVideoWidget::KeepAspectRatio: + control->SetAspectRatioMode(VMR9ARMode_LetterBox); + break; + default: + break; + } + control->Release(); + } +} + +int Vmr9VideoWindowControl::brightness() const +{ + return m_brightness; +} + +void Vmr9VideoWindowControl::setBrightness(int brightness) +{ + m_brightness = brightness; + + m_dirtyValues |= ProcAmpControl9_Brightness; + + setProcAmpValues(); + + emit brightnessChanged(brightness); +} + +int Vmr9VideoWindowControl::contrast() const +{ + return m_contrast; +} + +void Vmr9VideoWindowControl::setContrast(int contrast) +{ + m_contrast = contrast; + + m_dirtyValues |= ProcAmpControl9_Contrast; + + setProcAmpValues(); + + emit contrastChanged(contrast); +} + +int Vmr9VideoWindowControl::hue() const +{ + return m_hue; +} + +void Vmr9VideoWindowControl::setHue(int hue) +{ + m_hue = hue; + + m_dirtyValues |= ProcAmpControl9_Hue; + + setProcAmpValues(); + + emit hueChanged(hue); +} + +int Vmr9VideoWindowControl::saturation() const +{ + return m_saturation; +} + +void Vmr9VideoWindowControl::setSaturation(int saturation) +{ + m_saturation = saturation; + + m_dirtyValues |= ProcAmpControl9_Saturation; + + setProcAmpValues(); + + emit saturationChanged(saturation); +} + +void Vmr9VideoWindowControl::setProcAmpValues() +{ + if (IVMRMixerControl9 *control = com_cast(m_filter)) { + VMR9ProcAmpControl procAmp; + procAmp.dwSize = sizeof(VMR9ProcAmpControl); + procAmp.dwFlags = m_dirtyValues; + + if (m_dirtyValues & ProcAmpControl9_Brightness) { + procAmp.Brightness = scaleProcAmpValue( + control, ProcAmpControl9_Brightness, m_brightness); + } + if (m_dirtyValues & ProcAmpControl9_Contrast) { + procAmp.Contrast = scaleProcAmpValue( + control, ProcAmpControl9_Contrast, m_contrast); + } + if (m_dirtyValues & ProcAmpControl9_Hue) { + procAmp.Hue = scaleProcAmpValue( + control, ProcAmpControl9_Hue, m_hue); + } + if (m_dirtyValues & ProcAmpControl9_Saturation) { + procAmp.Saturation = scaleProcAmpValue( + control, ProcAmpControl9_Saturation, m_saturation); + } + + if (SUCCEEDED(control->SetProcAmpControl(0, &procAmp))) { + m_dirtyValues = 0; + } + + control->Release(); + } +} + +float Vmr9VideoWindowControl::scaleProcAmpValue( + IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const +{ + float scaledValue = 0.0; + + VMR9ProcAmpControlRange range; + range.dwSize = sizeof(VMR9ProcAmpControlRange); + range.dwProperty = property; + + if (SUCCEEDED(control->GetProcAmpControlRange(0, &range))) { + scaledValue = range.DefaultValue; + if (value > 0) + scaledValue += float(value) * (range.MaxValue - range.DefaultValue) / 100; + else if (value < 0) + scaledValue -= float(value) * (range.MinValue - range.DefaultValue) / 100; + } + + return scaledValue; +} + +QT_END_NAMESPACE + diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h new file mode 100644 index 0000000..a0aca95 --- /dev/null +++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 VMR9VIDEOWINDOWCONTROL_H +#define VMR9VIDEOWINDOWCONTROL_H + +#include + +#include +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Vmr9VideoWindowControl : public QVideoWindowControl +{ + Q_OBJECT +public: + Vmr9VideoWindowControl(QObject *parent = 0); + ~Vmr9VideoWindowControl(); + + IBaseFilter *filter() const { return m_filter; } + + WId winId() const; + void setWinId(WId id); + + QRect displayRect() const; + void setDisplayRect(const QRect &rect); + + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + void repaint(); + + QSize nativeSize() const; + + QVideoWidget::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(QVideoWidget::AspectRatioMode mode); + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + +private: + void setProcAmpValues(); + float scaleProcAmpValue( + IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const; + + IBaseFilter *m_filter; + WId m_windowId; + DWORD m_dirtyValues; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + bool m_fullScreen; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro index 879d914..e48156b 100644 --- a/src/plugins/mediaservices/mediaservices.pro +++ b/src/plugins/mediaservices/mediaservices.pro @@ -1,5 +1,7 @@ TEMPLATE = subdirs +win32:!wince:SUBDIRS += directshow + mac:SUBDIRS += qt7 unix:!mac:!symbian { -- cgit v0.12 From 19a822ae09d3ccb8b3aacf96e2f4052c32722284 Mon Sep 17 00:00:00 2001 From: Nicholas Young Date: Fri, 29 Jan 2010 11:20:41 +1000 Subject: Fixed GStreamer Plugin. --- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp | 2 +- .../mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp index 93151e1..016909a 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -659,7 +659,7 @@ void QGstreamerPlayerSession::getStreamsInfo() if (type == GST_STREAM_TYPE_VIDEO) haveVideo = true; else if (type == GST_STREAM_TYPE_AUDIO) - hasAudio = true; + haveAudio = true; // QMediaStreamsControl::StreamType streamType = QMediaStreamsControl::UnknownStream; // diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h index 0da5f8f..d33ffd2 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h @@ -121,7 +121,7 @@ signals: void mediaStatusChanged(QMediaPlayer::MediaStatus mediaStatus); void volumeChanged(int volume); void mutedStateChanged(bool muted); - void audioAvailalbeChanged(bool audioAvailable); + void audioAvailableChanged(bool audioAvailable); void videoAvailableChanged(bool videoAvailable); void bufferingChanged(bool buffering); void bufferingProgressChanged(int percentFilled); -- cgit v0.12 From 5fdbc2e878898ae4314426414382aa8a8c7f2eac Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 29 Jan 2010 11:56:13 +0100 Subject: Initialize member variables in QStaticTextPrivate constructor Avoid crash when copying a QStaticTextPrivate object --- src/gui/text/qstatictext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index db10a03..3f26eb3 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -276,6 +276,7 @@ QStaticTextPrivate::QStaticTextPrivate() } QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) + : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false) { ref = 1; text = other.text; -- cgit v0.12 From 951922772c0c5f8b8833c2793064f8c6ebeecd9c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 29 Jan 2010 12:03:42 +0100 Subject: Remove unused constructor in QStaticTextPrivate The copy constructor for QStaticTextPrivate was never called. --- src/gui/text/qstatictext.cpp | 10 ---------- src/gui/text/qstatictext_p.h | 1 - 2 files changed, 11 deletions(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 3f26eb3..6c960bb 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -275,16 +275,6 @@ QStaticTextPrivate::QStaticTextPrivate() ref = 1; } -QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) - : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false) -{ - ref = 1; - text = other.text; - font = other.font; - size = other.size; - init(); -} - QStaticTextPrivate::~QStaticTextPrivate() { delete[] items; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 919589e..78f7896 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -82,7 +82,6 @@ class Q_AUTOTEST_EXPORT QStaticTextPrivate { public: QStaticTextPrivate(); - QStaticTextPrivate(const QStaticTextPrivate &other); ~QStaticTextPrivate(); void init(); -- cgit v0.12 From da388773f581e251054abd037dc410ae52cfa69c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 29 Jan 2010 16:53:39 +0100 Subject: Improve performance of QStaticText on OpenGL by caching data on GPU There's a big improvement to be seen in the OpenGL engine by caching the vertex data for the QStaticText in VBOs. In order to have the buffers properly disposed, I've implemented a userdata concept for QStaticTextItem. By default, the optimizations will be turned off, and can be turned on by using the useBackendOptimizations flag. --- src/gui/painting/qpainter.cpp | 1 + src/gui/text/qstatictext.cpp | 43 ++++++++++ src/gui/text/qstatictext.h | 3 + src/gui/text/qstatictext_p.h | 59 ++++++++++---- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 92 +++++++++++++++++++--- 5 files changed, 173 insertions(+), 25 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 54eed03..521072f 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5800,6 +5800,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static textItem->glyphPositions[i].x += fx - oldX; textItem->glyphPositions[i].y += fy - oldY; } + textItem->userDataNeedsUpdate = true; } staticText_d->position = transformedPosition; diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 6c960bb..7be89cb 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -236,6 +236,43 @@ QString QStaticText::text() const } /*! + Sets whether the QStaticText object should use optimizations specific to the paint engine + backend if they are available. If \a on is set to true, backend optimizations will be turned + on, otherwise they will be turned off. The default value is false. + + If backend optimizations are on, the paint engine used to draw the static text is allowed to + store data in the object which will assist it in future calls to drawStaticText. In particular, + when using the opengl graphics system, or when painting on a QGLWidget, turning this flag on will + improve performance, but increase the memory footprint of the QStaticText object. + + The default value is false. + + \note This function will cause the layout of the text to be recalculated. + + \sa useBackendOptimizations() +*/ +void QStaticText::setUseBackendOptimizations(bool on) +{ + if (on == d_ptr->useBackendOptimizations) + return; + + detach(); + d_ptr->useBackendOptimizations = on; + d_ptr->init(); +} + +/*! + Returns whether the QStaticText object should use optimizations specific to the paint engine + backend when possible. By default this setting is false. + + \sa setUseBackendOptimizations() +*/ +bool QStaticText::useBackendOptimizations() const +{ + return d_ptr->useBackendOptimizations; +} + +/*! Sets the maximum size of the QStaticText to \a maximumSize. \note This function will cause the layout of the text to be recalculated. @@ -470,6 +507,12 @@ void QStaticTextPrivate::init() itemCount = counterDevice.itemCount(); items = new QStaticTextItem[itemCount]; + if (useBackendOptimizations) { + for (int i=0; iwidth(); GLfloat dy = 1.0 / cache->height(); - vertexCoordinateArray.clear(); - textureCoordinateArray.clear(); + if (staticTextItem->userData == 0 + || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData + || staticTextItem->userDataNeedsUpdate) { + vertexCoordinateArray.clear(); + textureCoordinateArray.clear(); + + for (int i=0; inumGlyphs; ++i) { + const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); + int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; + int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; + + vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); + textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } + + + if (staticTextItem->useBackendOptimizations) { + QOpenGLStaticTextUserData *userData = + staticTextItem->userData != 0 && staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData + ? static_cast(staticTextItem->userData) + : new QOpenGLStaticTextUserData(ctx); + + int vertexCoordinateArraySize = vertexCoordinateArray.vertexCount() * sizeof(QGLPoint); + if (userData->vertexCoordVBOId == 0) + glGenBuffers(1, &userData->vertexCoordVBOId); + + int textureCoordinateArraySize = textureCoordinateArray.vertexCount() * sizeof(QGLPoint); + if (userData->textureCoordVBOId == 0) + glGenBuffers(1, &userData->textureCoordVBOId); + + glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->vertexCoordVBOId); + glBufferData(GL_ARRAY_BUFFER_ARB, vertexCoordinateArraySize, + vertexCoordinateArray.data(), GL_STATIC_DRAW_ARB); + + glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->textureCoordVBOId); + glBufferData(GL_ARRAY_BUFFER_ARB, textureCoordinateArraySize, + textureCoordinateArray.data(), GL_STATIC_DRAW_ARB); - for (int i=0; inumGlyphs; ++i) { - const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); - int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; - int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; + // If a new user data has been created, make sure we delete the old + staticTextItem->setUserData(userData); + staticTextItem->userDataNeedsUpdate = false; - vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); - textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } else { + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + } } - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + if (staticTextItem->useBackendOptimizations) { + Q_ASSERT(staticTextItem->userData != 0); + Q_ASSERT(staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData); + + QOpenGLStaticTextUserData *userData = static_cast(staticTextItem->userData); + + glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->vertexCoordVBOId); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->textureCoordVBOId); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + } if (addOffset) { addOffset = false; @@ -1420,6 +1489,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); + + // Reset bindings + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) -- cgit v0.12 From 3941f493f124298757d7b30b30f8781719cc89cc Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 1 Feb 2010 18:13:28 +1000 Subject: Export QPainterVideoSurface for QtWebKit. --- src/multimedia/base/qpaintervideosurface_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h index 67b514f..5340956 100644 --- a/src/multimedia/base/qpaintervideosurface_p.h +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -69,7 +69,7 @@ class QGLContext; class QVideoSurfacePainter; -class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface +class Q_MULTIMEDIA_EXPORT QPainterVideoSurface : public QAbstractVideoSurface { Q_OBJECT public: -- cgit v0.12 From a7a6db7edc8cd67fd257167ecb3ea3029f2be38a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 09:52:57 +0100 Subject: Remove reference to _ARB macros These belong to an OpenGL extension which is not in use. --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index f6ef827..2636761 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1362,13 +1362,13 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp if (userData->textureCoordVBOId == 0) glGenBuffers(1, &userData->textureCoordVBOId); - glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->vertexCoordVBOId); - glBufferData(GL_ARRAY_BUFFER_ARB, vertexCoordinateArraySize, - vertexCoordinateArray.data(), GL_STATIC_DRAW_ARB); + glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId); + glBufferData(GL_ARRAY_BUFFER, vertexCoordinateArraySize, + vertexCoordinateArray.data(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->textureCoordVBOId); - glBufferData(GL_ARRAY_BUFFER_ARB, textureCoordinateArraySize, - textureCoordinateArray.data(), GL_STATIC_DRAW_ARB); + glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); + glBufferData(GL_ARRAY_BUFFER, textureCoordinateArraySize, + textureCoordinateArray.data(), GL_STATIC_DRAW); // If a new user data has been created, make sure we delete the old staticTextItem->setUserData(userData); @@ -1386,10 +1386,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QOpenGLStaticTextUserData *userData = static_cast(staticTextItem->userData); - glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->vertexCoordVBOId); + glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId); glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); - glBindBuffer(GL_ARRAY_BUFFER_ARB, userData->textureCoordVBOId); + glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); } @@ -1491,7 +1491,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); // Reset bindings - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) -- cgit v0.12 From a5a9672d8e437461c53347d49b788a2e098501be Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 11:03:50 +0100 Subject: Compile on Windows The default GL header on Windows is GL 1.1, so the 1.5 extensions are not defined. To work around this, we define the macros when needed. The macros are required for QStaticText's OpenGL backend. --- src/opengl/qglextensions_p.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index b0cb429..e0fc99c 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -415,6 +415,14 @@ struct QGLExtensionFuncs // OpenGL constants +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#endif + +#ifndef GL_STATIC_DRAW +#define GL_STATIC_DRAW 0x88E4 +#endif + /* NV_texture_rectangle */ #ifndef GL_NV_texture_rectangle #define GL_TEXTURE_RECTANGLE_NV 0x84F5 -- cgit v0.12 From bb582974e48acacf7ff300cb03b0787b5dfc0b08 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 12:12:23 +0100 Subject: doc: Add \since to QStaticText QStaticText will be added as public API in Qt 4.7, and as private API in Qt 4.6. --- src/gui/text/qstatictext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 7be89cb..d94b9a3 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -52,6 +52,7 @@ 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 -- cgit v0.12 From 81b89c410a0df438db65b6124b4db94c8628c52c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 12:13:37 +0100 Subject: Don't compare bool to char (avoid warning on MSVC) Remove unsafe comparison since true is defined as non-zero only. --- src/gui/text/qstatictext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index d94b9a3..4daa40d 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -254,7 +254,8 @@ QString QStaticText::text() const */ void QStaticText::setUseBackendOptimizations(bool on) { - if (on == d_ptr->useBackendOptimizations) + if ((!on && !d_ptr->useBackendOptimizations) + || (on && d_ptr->useBackendOptimizations)) return; detach(); -- cgit v0.12 From 942cf8cc8504af0683c3d03c886418fb9e69bd7d Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 12:51:35 +0100 Subject: Make QStaticText private API Turns QStaticText into private API in preparation for Qt 4.6.x. The related functions in QPainter are marked as internal in the docs. There are already internal functions in QPainter, so this seemed like a reasonable solution. Since the functions require QStaticText they will not be accessible to anyone who does not include private API. --- src/gui/painting/qpaintbuffer.cpp | 1 + src/gui/painting/qpaintengine_raster.cpp | 2 +- src/gui/painting/qpaintengineex.cpp | 2 +- src/gui/painting/qpainter.cpp | 7 ++ src/gui/painting/qpainter.h | 2 +- src/gui/text/qstatictext.cpp | 3 +- src/gui/text/qstatictext.h | 98 --------------- src/gui/text/qstatictext_p.h | 122 ++++++------------ src/gui/text/qstatictext_p_p.h | 140 +++++++++++++++++++++ src/gui/text/text.pri | 2 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- src/opengl/qpaintengine_opengl.cpp | 2 +- src/openvg/qpaintengine_vg.cpp | 2 +- tests/auto/qstatictext/tst_qstatictext.cpp | 2 +- 14 files changed, 198 insertions(+), 189 deletions(-) delete mode 100644 src/gui/text/qstatictext.h create mode 100644 src/gui/text/qstatictext_p_p.h diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index e41ad57..b0a3d7a 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 1fbfbb4..29694d1 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -67,7 +67,7 @@ // #include // #include #include -#include +#include #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 1bbdafa..b61821d 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -44,7 +44,7 @@ #include "qstroker_p.h" #include "qbezier_p.h" #include -#include +#include #include #include diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 521072f..c29cf5d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -70,6 +70,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -5707,18 +5708,24 @@ void QPainter::drawText(const QPointF &p, const QString &str) /*! \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) + \internal + \overload */ /*! \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) + \internal + \overload */ /*! Draws the given \a staticText beginning at the given \a position. + \internal + This function can be used to optimize drawing text if the text and its layout is updated seldomly. diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 1ae7c08..181eba7 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -50,7 +50,6 @@ #include #include #include -#include #ifndef QT_INCLUDE_COMPAT #include @@ -79,6 +78,7 @@ class QPolygon; class QTextItem; class QMatrix; class QTransform; +class QStaticText; class QPainterPrivateDeleter; diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 4daa40d..922920e 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#include "qstatictext.h" #include "qstatictext_p.h" +#include "qstatictext_p_p.h" #include #include @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE /*! \class QStaticText + \internal \brief The QStaticText class enables optimized drawing of text when the text and its layout is updated rarely. \since 4.7 diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h deleted file mode 100644 index d79d887..0000000 --- a/src/gui/text/qstatictext.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSTATICTEXT_H -#define QSTATICTEXT_H - -#include -#include -#include - -#include -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QStaticTextPrivate; -class Q_GUI_EXPORT QStaticText -{ -public: - QStaticText(); - QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); - QStaticText(const QStaticText &other); - ~QStaticText(); - - void setText(const QString &text); - QString text() const; - - void setMaximumSize(const QSizeF &maximumSize); - QSizeF maximumSize() const; - - void prepare(const QTransform &matrix, const QFont &font); - - void setUseBackendOptimizations(bool on); - bool useBackendOptimizations() const; - - QStaticText &operator=(const QStaticText &); - bool operator==(const QStaticText &) const; - bool operator!=(const QStaticText &) const; - - bool isEmpty() const; - -private: - void detach(); - - QStaticTextPrivate *d_ptr; - 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 index bca59e0..d79d887 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -39,102 +39,60 @@ ** ****************************************************************************/ -#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 +#ifndef QSTATICTEXT_H +#define QSTATICTEXT_H -QT_BEGIN_NAMESPACE +#include +#include +#include -class QStaticTextUserData -{ -public: - enum Type { - NoUserData, - OpenGLUserData - }; +#include +#include - QStaticTextUserData(Type t) : type(t) {} - virtual ~QStaticTextUserData() {} - Type type; -}; +QT_BEGIN_HEADER -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 - QStaticTextUserData *userData; // 8 bytes per item - char useBackendOptimizations : 1; // 1 byte per item - char userDataNeedsUpdate : 1; // - // ================ - // 41 bytes per item -}; +QT_BEGIN_NAMESPACE -class QStaticText; -class Q_AUTOTEST_EXPORT QStaticTextPrivate -{ +QT_MODULE(Gui) + +class QStaticTextPrivate; +class Q_GUI_EXPORT QStaticText +{ public: - QStaticTextPrivate(); - ~QStaticTextPrivate(); + QStaticText(); + QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); + QStaticText(const QStaticText &other); + ~QStaticText(); + + void setText(const QString &text); + QString text() const; + + void setMaximumSize(const QSizeF &maximumSize); + QSizeF maximumSize() const; - void init(); + void prepare(const QTransform &matrix, const QFont &font); - QAtomicInt ref; // 4 bytes per text + void setUseBackendOptimizations(bool on); + bool useBackendOptimizations() const; - QString text; // 4 bytes per text - QFont font; // 8 bytes per text - QSizeF size; // 16 bytes per text - QPointF position; // 16 bytes per text + QStaticText &operator=(const QStaticText &); + bool operator==(const QStaticText &) const; + bool operator!=(const QStaticText &) const; - 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 + bool isEmpty() const; - char needsClipRect : 1; // 1 byte per text - char useBackendOptimizations : 1; - // ================ - // 145 bytes per text +private: + void detach(); - static QStaticTextPrivate *get(const QStaticText *q); + QStaticTextPrivate *d_ptr; + friend class QStaticTextPrivate; }; +Q_DECLARE_METATYPE(QStaticText) + QT_END_NAMESPACE -#endif // QSTATICTEXT_P_H +QT_END_HEADER + +#endif // QSTATICTEXT_H diff --git a/src/gui/text/qstatictext_p_p.h b/src/gui/text/qstatictext_p_p.h new file mode 100644 index 0000000..bca59e0 --- /dev/null +++ b/src/gui/text/qstatictext_p_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 + +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 + QStaticTextUserData *userData; // 8 bytes per item + char useBackendOptimizations : 1; // 1 byte per item + char userDataNeedsUpdate : 1; // + // ================ + // 41 bytes per item +}; + +class QStaticText; +class Q_AUTOTEST_EXPORT QStaticTextPrivate +{ +public: + QStaticTextPrivate(); + ~QStaticTextPrivate(); + + void init(); + + QAtomicInt ref; // 4 bytes per text + + QString text; // 4 bytes per text + QFont font; // 8 bytes per text + QSizeF size; // 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 + + char needsClipRect : 1; // 1 byte per text + char useBackendOptimizations : 1; + // ================ + // 145 bytes per text + + static QStaticTextPrivate *get(const QStaticText *q); +}; + +QT_END_NAMESPACE + +#endif // QSTATICTEXT_P_H diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 026e6c6..2eaa418 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -38,7 +38,7 @@ HEADERS += \ text/qzipreader_p.h \ text/qzipwriter_p.h \ text/qtextodfwriter_p.h \ - text/qstatictext.h \ + text/qstatictext_p_p.h \ text/qstatictext_p.h SOURCES += \ diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 2636761..17b3317 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -77,7 +77,7 @@ #include #include #include -#include +#include #include "qglgradientcache_p.h" #include "qglengineshadermanager_p.h" diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index a2f085c..e7a1b7e 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include "private/qtessellator_p.h" diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 0ef93b3..9bb513d 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index ca83f2f..9ad389d 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -42,10 +42,10 @@ #include #include #include -#include #include #include +#include // #define DEBUG_SAVE_IMAGE -- cgit v0.12 From c04b9d51011d11ff19719a4b96ad885ef89ea78d Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 12:57:20 +0100 Subject: Add private header warning to qstatictext_p.h Since QStaticText will be private API for Qt 4.6.x series, we need the regular warning in the header file. --- src/gui/text/qstatictext_p.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index d79d887..b07383e 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -42,6 +42,17 @@ #ifndef QSTATICTEXT_H #define QSTATICTEXT_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 #include #include -- cgit v0.12 From 4012ff8d08e5d6be738db88eda30dbe20d45c58a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 16:07:59 +0100 Subject: Fix one test and add tests for backend optimizations The rotatedTranslatedScaled-test would transform the text out of the destination rect, so we'd just confirm two blank images. Also added input to the two basic tests for backend optimizations. --- tests/auto/qstatictext/tst_qstatictext.cpp | 35 +++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 9ad389d..08e7079 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -57,7 +57,9 @@ private slots: void cleanup(); void constructionAndDestruction(); + void drawToPoint_data(); void drawToPoint(); + void drawToRect_data(); void drawToRect(); void setFont(); void setMaximumSize(); @@ -69,7 +71,7 @@ private slots: void scaledPainter(); void projectedPainter(); void rotatedScaledAndTranslatedPainter(); - void transformationChanged(); + void transformationChanged(); }; void tst_QStaticText::init() @@ -85,8 +87,18 @@ void tst_QStaticText::constructionAndDestruction() QStaticText text("My text"); } +void tst_QStaticText::drawToPoint_data() +{ + QTest::addColumn("useBackendOptimizations"); + + QTest::newRow("Without backend optimizations") << false; + QTest::newRow("With backend optimizations") << true; +} + void tst_QStaticText::drawToPoint() { + QFETCH(bool, useBackendOptimizations); + QPixmap imageDrawText(1000, 1000); imageDrawText.fill(Qt::white); { @@ -99,14 +111,25 @@ void tst_QStaticText::drawToPoint() { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setUseBackendOptimizations(useBackendOptimizations); p.drawStaticText(11, 12, text); } QCOMPARE(imageDrawStaticText, imageDrawText); } +void tst_QStaticText::drawToRect_data() +{ + QTest::addColumn("useBackendOptimizations"); + + QTest::newRow("Without backend optimizations") << false; + QTest::newRow("With backend optimizations") << true; +} + void tst_QStaticText::drawToRect() { + QFETCH(bool, useBackendOptimizations); + QPixmap imageDrawText(1000, 1000); imageDrawText.fill(Qt::white); { @@ -119,6 +142,7 @@ void tst_QStaticText::drawToRect() { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500)); + text.setUseBackendOptimizations(useBackendOptimizations); p.drawStaticText(11, 12, text); } @@ -342,7 +366,7 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() { QPainter p(&imageDrawText); p.rotate(45.0); - p.scale(0.2, 2.0); + p.scale(2.0, 2.0); p.translate(100, 200); p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); @@ -353,13 +377,18 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() { QPainter p(&imageDrawStaticText); p.rotate(45.0); - p.scale(0.2, 2.0); + p.scale(2.0, 2.0); p.translate(100, 200); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); p.drawStaticText(11, 12, text); } +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("rotatedScaledAndPainter_imageDrawText.png"); + imageDrawStaticText.save("rotatedScaledAndPainter_imageDrawStaticText.png"); +#endif + QCOMPARE(imageDrawStaticText, imageDrawText); } -- cgit v0.12 From d60916a4a9281ed1ce2fa5f360d512094b2548a6 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 16:09:36 +0100 Subject: Clarify comment in QPainter We support affine transformations in the drawStaticTextItem() backends, but for non-affine transformation, the fallback will be taken. --- src/gui/painting/qpainter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index c29cf5d..4f675ae 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5740,7 +5740,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static QStaticTextPrivate *staticText_d = const_cast(QStaticTextPrivate::get(&staticText)); - // If we don't have an extended paint engine, or if the painter is transformed, + // 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()) { if (staticText_d->size.isValid()) -- cgit v0.12 From f3cf5dd98e321980984288a1768f3375a8349800 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Feb 2010 16:10:58 +0100 Subject: Fix transformed painting of QStaticText in GL2 paint engine The GL2 paint engine was rewritten to use GL to transform glyphs when copying them from the glyph cache instead of keeping a separate cache for different transformations. Since the glyph positions in QStaticText already include the transformation, we need to run the gl calls with an identity matrix, otherwise the position of the glyphs will be transformed twice. The output from drawText() and drawStaticText() will for the same reason look different for the two different engines. The option here is to detect the problem when drawing to the opengl2 engine, and then recalculating the glyph positions for the QStaticText. This will of course create a big overhead when regularly switching between different paint devices, but it might make sense to optimize for one QStaticText per paint device. For the time being I haven't done that, though, since that change would require a bigger hack, so it warrants deeper consideration. --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 27 ++++++++++++++++------ .../gl2paintengineex/qpaintengineex_opengl2_p.h | 3 ++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 17b3317..544d327 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1204,9 +1204,8 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat) : d->glyphCacheType; - // ### What about transformations and huge fonts? These are not passed through cache - // in drawTextItem(). - d->drawCachedGlyphs(glyphType, textItem); + // ### What about huge fonts? These are not passed through cache in drawTextItem(). + d->drawCachedGlyphs(glyphType, textItem, true); } void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) @@ -1276,7 +1275,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem staticTextItem.numGlyphs = glyphs.size(); staticTextItem.glyphPositions = positions.data(); - d->drawCachedGlyphs(glyphType, &staticTextItem); + d->drawCachedGlyphs(glyphType, &staticTextItem, false); } return; } @@ -1307,14 +1306,22 @@ namespace { }; } -void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem) +void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, + QStaticTextItem *staticTextItem, + bool includeMatrixInCache) { Q_Q(QGL2PaintEngineEx); + QOpenGL2PaintEngineState *s = q->state(); + QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform()); + (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, + includeMatrixInCache + ? s->matrix + : QTransform()); if (!cache || cache->cacheType() != glyphType) { - cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); + cache = new QGLTextureGlyphCache(ctx, glyphType, + includeMatrixInCache ? s->matrix : QTransform()); staticTextItem->fontEngine->setGlyphCache(ctx, cache); } @@ -1405,6 +1412,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QBrush pensBrush = q->state()->pen.brush(); setBrush(pensBrush); + QTransform old = s->matrix; + if (includeMatrixInCache) + s->matrix = QTransform(); if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { // Subpixel antialiasing without gamma correction @@ -1492,6 +1502,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp // Reset bindings glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (includeMatrixInCache) + s->matrix = old; } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index a7a40a8..4ef1bb9 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -195,7 +195,8 @@ public: void stroke(const QVectorPath &path, const QPen &pen); void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); - void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem); + void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem, + bool includeMatrixInCache); // Calls glVertexAttributePointer if the pointer has changed inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer); -- cgit v0.12 From 6c353c246e16dcad37a000b5e9ce393be90d6b64 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 2 Feb 2010 11:07:07 +1000 Subject: Add lost QmlMediaBase header file. --- src/multimedia/qml/qmlmediabase_p.h | 155 ++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 src/multimedia/qml/qmlmediabase_p.h diff --git a/src/multimedia/qml/qmlmediabase_p.h b/src/multimedia/qml/qmlmediabase_p.h new file mode 100644 index 0000000..3b5c398 --- /dev/null +++ b/src/multimedia/qml/qmlmediabase_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QMLMEDIABASE_P_H +#define QMLMEDIABASE_P_H + + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QMediaPlayerControl; +class QMediaService; +class QMediaServiceProvider; +class QMetaDataControl; +class QMetaDataControlMetaObject; +class QmlMediaBaseAnimation; + +class QmlMediaBase +{ +public: + QmlMediaBase(); + virtual ~QmlMediaBase(); + + QUrl source() const; + void setSource(const QUrl &url); + + bool isPlaying() const; + void setPlaying(bool playing); + + bool isPaused() const; + void setPaused(bool paused); + + int duration() const; + + int position() const; + void setPosition(int position); + + qreal volume() const; + void setVolume(qreal volume); + + bool isMuted() const; + void setMuted(bool muted); + + qreal bufferProgress() const; + + bool isSeekable() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + + QString errorString() const; + + void _q_stateChanged(QMediaPlayer::State state); + void _q_mediaStatusChanged(QMediaPlayer::MediaStatus status); + + void _q_metaDataChanged(); + +protected: + void shutdown(); + + void setObject(QObject *object); + + virtual void sourceChanged() = 0; + + virtual void playingChanged() = 0; + virtual void pausedChanged() = 0; + + virtual void started() = 0; + virtual void resumed() = 0; + virtual void paused() = 0; + virtual void stopped() = 0; + + virtual void statusChanged() = 0; + + virtual void loaded() = 0; + virtual void buffering() = 0; + virtual void stalled() = 0; + virtual void buffered() = 0; + virtual void endOfMedia() = 0; + + virtual void durationChanged() = 0; + virtual void positionChanged() = 0; + + virtual void volumeChanged() = 0; + virtual void mutedChanged() = 0; + + virtual void bufferProgressChanged() = 0; + + virtual void seekableChanged() = 0; + virtual void playbackRateChanged() = 0; + + QMediaService *m_mediaService; + QMediaPlayerControl *m_playerControl; + + QMediaObject *m_mediaObject; + QMediaServiceProvider *m_mediaProvider; + QMetaDataControl *m_metaDataControl; + QMetaDataControlMetaObject *m_metaObject; + QmlMediaBaseAnimation *m_animation; + + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_status; + QMediaPlayer::Error m_error; + QString m_errorString; + + friend class QmlMediaBaseAnimation; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif -- cgit v0.12 From c3becaff5676eac34616bcd4aeba747ec4398ae6 Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Mon, 1 Feb 2010 09:44:44 -0800 Subject: Make QRasterPaintEngine::drawStaticText public. This is necessary so subclasses can chain to it. Reviewed-by: Donald Carr --- src/gui/painting/qpaintengine_raster_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 5e5d9b8..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 @@ -260,8 +262,6 @@ private: void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine); - void drawStaticTextItem(QStaticTextItem *textItem); - #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti); #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE -- cgit v0.12 From 8e4978fefaa52056dd0c58162d2eeeebdb739d36 Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Mon, 1 Feb 2010 09:51:19 -0800 Subject: Lock before calling drawStaticTextItem Reviewed-by: Donald Carr --- src/gui/embedded/directfb.pri | 2 +- src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp | 10 +++++++++- src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) 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/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index 2b11058..12f4c6b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -176,7 +176,7 @@ enum PaintOperation { DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100, DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800, FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000, - ALL = 0xffff + DRAW_STATICTEXT = 0x8000, ALL = 0xffff }; #endif @@ -711,6 +711,14 @@ void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode); } +void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item) +{ + RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG()); + Q_D(QDirectFBPaintEngine); + d->lock(); + QRasterPaintEngine::drawStaticTextItem(item); +} + void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) { Q_D(QDirectFBPaintEngine); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h index 64609d7..19e8b84 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -109,6 +109,8 @@ public: virtual void clip(const QRegion ®ion, Qt::ClipOperation op); virtual void clip(const QRect &rect, Qt::ClipOperation op); + virtual void drawStaticTextItem(QStaticTextItem *item); + static void initImageCache(int size); }; -- cgit v0.12 From c265f7ac9a7a2344cc441a474c76e2ecf36bafbf Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 2 Feb 2010 14:23:22 +0100 Subject: Add experimental support for using drawElements to draw cached text According to some design documents, drawElements() is likely to be quicker on some devices, as the driver then does not have to create the index array. To test the impact of this, we cache use drawElements and cache the index array in QStaticText --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 37 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index eff02b2..878faf4 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1276,6 +1276,8 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem QPaintEngineEx::drawTextItem(p, ti); } +#define QSTATICTEXT_USE_INDEXARRAY + namespace { class QOpenGLStaticTextUserData: public QStaticTextUserData @@ -1296,6 +1298,10 @@ namespace { QGLContext *ctx; GLuint vertexCoordVBOId; GLuint textureCoordVBOId; + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + QVector indices; +#endif }; } @@ -1332,12 +1338,21 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp GLfloat dx = 1.0 / cache->width(); GLfloat dy = 1.0 / cache->height(); +#if defined(QSTATICTEXT_USE_INDEXARRAY) + QVector indices; +#endif + if (staticTextItem->userData == 0 || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData || staticTextItem->userDataNeedsUpdate) { vertexCoordinateArray.clear(); textureCoordinateArray.clear(); +#if defined(QSTATICTEXT_USE_INDEXARRAY) + indices.clear(); + int j=0; +#endif + for (int i=0; inumGlyphs; ++i) { const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; @@ -1345,8 +1360,12 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); - } +#if defined(QSTATICTEXT_USE_INDEXARRAY) + for (int k=0; k<6; ++k) + indices.append(j++); +#endif + } if (staticTextItem->useBackendOptimizations) { QOpenGLStaticTextUserData *userData = @@ -1370,16 +1389,19 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp glBufferData(GL_ARRAY_BUFFER, textureCoordinateArraySize, textureCoordinateArray.data(), GL_STATIC_DRAW); +#if defined(QSTATICTEXT_USE_INDEXARRAY) + userData->indices = indices; +#endif + // If a new user data has been created, make sure we delete the old staticTextItem->setUserData(userData); - staticTextItem->userDataNeedsUpdate = false; + staticTextItem->userDataNeedsUpdate = false; } else { setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); } } - if (staticTextItem->useBackendOptimizations) { Q_ASSERT(staticTextItem->userData != 0); Q_ASSERT(staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData); @@ -1391,6 +1413,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + indices = userData->indices; +#endif } if (addOffset) { @@ -1491,7 +1517,12 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + glDrawElements(GL_TRIANGLES, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_BYTE, indices.constData()); +#else glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); +#endif // Reset bindings glBindBuffer(GL_ARRAY_BUFFER, 0); -- cgit v0.12 From 8aa94f13be95392d0bba911105bb118b48321a15 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 2 Feb 2010 15:36:55 +0100 Subject: Fix broken text drawing in OpenGL engine when text items are too long Passing text through drawElements introduced a bug when text items exceeded the range of GLubyte (seen in textedit demo.) --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 878faf4..d82d335 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1300,7 +1300,7 @@ namespace { GLuint textureCoordVBOId; #if defined(QSTATICTEXT_USE_INDEXARRAY) - QVector indices; + QVector indices; #endif }; } @@ -1339,7 +1339,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp GLfloat dy = 1.0 / cache->height(); #if defined(QSTATICTEXT_USE_INDEXARRAY) - QVector indices; + QVector indices; #endif if (staticTextItem->userData == 0 @@ -1519,7 +1519,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); #if defined(QSTATICTEXT_USE_INDEXARRAY) - glDrawElements(GL_TRIANGLES, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_BYTE, indices.constData()); + glDrawElements(GL_TRIANGLES, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_INT, indices.constData()); #else glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); #endif -- cgit v0.12 From 8acb069bd3a68afc36566503ca7f9d0fc808e170 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Tue, 2 Feb 2010 20:42:44 +0100 Subject: Doc: Synchronize configuration files for easier maintenance. Reviewed-by: Trust Me --- tools/qdoc3/test/qt-build-docs.qdocconf | 7 ++++--- tools/qdoc3/test/qt.qdocconf | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index e8595f6..dae5ca1 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -8,9 +8,9 @@ project = Qt description = Qt Reference Documentation url = http://qt.nokia.com/doc/4.7 -edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \ - QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ - QtDesigner QtAssistant QAxContainer Phonon \ +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ + QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ + Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ QAxServer QtUiTools QtTest QtDBus edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest @@ -94,6 +94,7 @@ excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ $QT_SOURCE_TREE/src/3rdparty/phonon/waveout sources.fileextensions = "*.cpp *.qdoc *.mm" diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index a066021..4dfabcf 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -12,7 +12,7 @@ url = http://qt.nokia.com/doc/4.7 edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ - Qt3Support QtHelp QtDesigner QAxContainer Phonon \ + Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ QAxServer QtUiTools QtTest QtDBus edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest edition.DesktopLight.groups = -graphicsview-api -- cgit v0.12 From 7a4d0130441bae27a302e694828ec71ade9e6005 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Tue, 2 Feb 2010 20:44:08 +0100 Subject: qdoc: Added support for different source and output character encodings. Previously, qdoc assumed Latin1 (ISO-8859-1) for source code and other documentation, and wrote out XHTML with the same encoding. This change adds additional configuration options (sourceencoding, outputencoding, naturallanguage) that enable translated documentation in non-Latin1 encodings to be built with qdoc. To be reviewed before merge into the master branch. Reviewed-by: Trust Me --- tools/qdoc3/config.h | 3 + tools/qdoc3/cppcodeparser.cpp | 12 ++-- tools/qdoc3/htmlgenerator.cpp | 137 ++++++++++++++++++++++------------------ tools/qdoc3/htmlgenerator.h | 3 +- tools/qdoc3/pagegenerator.cpp | 2 +- tools/qdoc3/pagegenerator.h | 6 ++ tools/qdoc3/qsakernelparser.cpp | 6 +- tools/qdoc3/qscodeparser.cpp | 6 +- tools/qdoc3/tokenizer.cpp | 25 ++++++-- tools/qdoc3/tokenizer.h | 9 ++- 10 files changed, 125 insertions(+), 84 deletions(-) diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h index 5e7e6f1..6f23469 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -140,8 +140,10 @@ class Config #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" #define CONFIG_MACRO "macro" +#define CONFIG_NATURALLANGUAGE "naturallanguage" #define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" +#define CONFIG_OUTPUTENCODING "outputencoding" #define CONFIG_OUTPUTLANGUAGE "outputlanguage" #define CONFIG_OUTPUTFORMATS "outputformats" #define CONFIG_PROJECT "project" @@ -150,6 +152,7 @@ class Config #define CONFIG_SLOW "slow" #define CONFIG_SHOWINTERNAL "showinternal" #define CONFIG_SOURCEDIRS "sourcedirs" +#define CONFIG_SOURCEENCODING "sourceencoding" #define CONFIG_SOURCES "sources" #define CONFIG_SPURIOUS "spurious" #define CONFIG_STYLESHEETS "stylesheets" diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 9b6a516..129fa7d 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -280,8 +280,8 @@ void CppCodeParser::parseHeaderFile(const Location& location, const QString& filePath, Tree *tree) { - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (!in) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open C++ header file '%1'").arg(filePath)); return; } @@ -294,7 +294,7 @@ void CppCodeParser::parseHeaderFile(const Location& location, matchDeclList(tree->root()); if (!fileTokenizer.version().isEmpty()) tree->setVersion(fileTokenizer.version()); - fclose(in); + in.close(); if (fileLocation.fileName() == "qiterator.h") parseQiteratorDotH(location, filePath); @@ -311,8 +311,8 @@ void CppCodeParser::parseSourceFile(const Location& location, const QString& filePath, Tree *tree) { - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (!in) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno))); return; } @@ -324,7 +324,7 @@ void CppCodeParser::parseSourceFile(const Location& location, readToken(); usedNamespaces.clear(); matchDocsAndStuff(); - fclose(in); + in.close(); } /*! diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index a3cdae6..21b358a 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -54,6 +54,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -266,6 +267,15 @@ void HtmlGenerator::initializeGenerator(const Config &config) projectUrl = config.getString(CONFIG_URL); + outputEncoding = config.getString(CONFIG_OUTPUTENCODING); + if (outputEncoding.isEmpty()) + outputEncoding = QLatin1String("ISO-8859-1"); + outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit()); + + naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE); + if (naturalLanguage.isEmpty()) + naturalLanguage = QLatin1String("en"); + QSet editionNames = config.subVars(CONFIG_EDITION); QSet::ConstIterator edition = editionNames.begin(); while (edition != editionNames.end()) { @@ -431,11 +441,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, endLink(); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::BaseName: @@ -483,7 +493,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::C: out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE]; if (inLink) { - out() << protect(plainCode(atom->string())); + out() << protectEnc(plainCode(atom->string())); } else { out() << highlightedCode(atom->string(), marker, relative); @@ -516,7 +526,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // fallthrough case Atom::CodeBad: out() << "
"
-              << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string()))))
+              << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string()))))
               << "
\n"; break; case Atom::FootnoteLeft: @@ -768,7 +778,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "\n"; - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; if (idx == Class) generateCompactList(0, marker, ncmap.value(), QString("Q")); else if (idx == MemberFunction) { @@ -792,7 +802,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, << linkForNode(pmap.key(), 0) << "\">"; QStringList pieces = fullName(pmap.key(), 0, marker).split("::"); - out() << protect(pieces.last()); + out() << protectEnc(pieces.last()); out() << "" << ":

\n"; generateSection(nlist, 0, marker, CodeMarker::Summary); @@ -820,12 +830,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "

"; if (fileName.isEmpty()) { out() << "[Missing image " - << protect(atom->string()) << "]"; + << protectEnc(atom->string()) << "]"; } else { - out() << "\"""; helpProjectWriter->addExtraFile(fileName); } @@ -923,7 +933,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // ### Trenton out() << "" - << protect(plainCode(marker->markedUpEnumValue(atom->next()->string(), + << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(), relative))) << ""; @@ -936,7 +946,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, if (itemValue.isEmpty()) out() << "?"; else - out() << "" << protect(itemValue) << ""; + out() << "" << protectEnc(itemValue) << ""; skipAhead = 1; } @@ -1052,7 +1062,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, generateLink(atom, relative, marker); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } break; case Atom::TableLeft: @@ -1166,7 +1176,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << "<Missing HTML>"; break; case Atom::UnknownCommand: - out() << "\\" << protect(atom->string()) + out() << "\\" << protectEnc(atom->string()) << ""; break; #ifdef QDOC_QML @@ -1295,7 +1305,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "\n"; - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; generateSection(s->members, inner, marker, CodeMarker::Summary); } if (!s->reimpMembers.isEmpty()) { @@ -1304,7 +1314,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "\n"; - out() << "

" << protect(name) << "

\n"; + out() << "

" << protectEnc(name) << "

\n"; generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); } @@ -1343,7 +1353,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, s = sections.begin(); while (s != sections.end()) { out() << "
\n"; - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { @@ -1513,7 +1523,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "\n"; - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; generateQmlSummary(*s,fake,marker); ++s; } @@ -1529,7 +1539,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); s = sections.begin(); while (s != sections.end()) { - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { generateDetailedQmlMember(*m, fake, marker); @@ -1549,7 +1559,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "\n"; - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } @@ -1578,7 +1588,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) s = sections.begin(); while (s != sections.end()) { out() << "
\n"; - out() << "

" << protect((*s).name) << "

\n"; + out() << "

" << protectEnc((*s).name) << "

\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { @@ -1624,11 +1634,11 @@ void HtmlGenerator::generateHeader(const QString& title, CodeMarker *marker, bool mainPage) { - out() << "\n"; + out() << QString("\n").arg(outputEncoding); out() << "\n" - "\n"; + " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n"; + out() << QString("\n").arg(naturalLanguage); QString shortVersion; if ((project != "Qtopia") && (project != "Qt Extended")) { @@ -1648,7 +1658,9 @@ void HtmlGenerator::generateHeader(const QString& title, } out() << "\n" - " " << shortVersion << protect(title) << "\n"; + " " << shortVersion << protectEnc(title) << "\n"; + out() << QString("").arg(outputEncoding); + if (!style.isEmpty()) out() << " \n"; @@ -1657,8 +1669,8 @@ void HtmlGenerator::generateHeader(const QString& title, QMapIterator i(metaMap); while (i.hasNext()) { i.next(); - out() << " \n"; + out() << " \n"; } } @@ -1682,9 +1694,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[Previous: "; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "]\n"; } if (node->links().contains(Node::ContentsLink)) { @@ -1700,9 +1712,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "["; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "]\n"; } if (node->links().contains(Node::NextLink)) { @@ -1718,9 +1730,9 @@ void HtmlGenerator::generateHeader(const QString& title, navigationLinks += "[Next: "; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + navigationLinks += protectEnc(anchorPair.second); else - navigationLinks += protect(linkPair.second); + navigationLinks += protectEnc(linkPair.second); navigationLinks += "]\n"; } if (node->links().contains(Node::IndexLink)) { @@ -1771,7 +1783,7 @@ void HtmlGenerator::generateTitle(const QString& title, const Node *relative, CodeMarker *marker) { - out() << "

" << protect(title); + out() << "

" << protectEnc(title); if (!subTitle.isEmpty()) { out() << "
"; if (subTitleSize == SmallSubTitle) @@ -2009,18 +2021,18 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, out() << "

\n"; for (i = 0; i < sections.size(); ++i) { - out() << "

" << protect(sections.at(i).name) << "

\n"; + out() << "

" << protectEnc(sections.at(i).name) << "

\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } sections = marker->sections(inner, CodeMarker::Detailed, status); for (i = 0; i < sections.size(); ++i) { out() << "
\n"; - out() << "

" << protect(sections.at(i).name) << "

\n"; + out() << "

" << protectEnc(sections.at(i).name) << "

\n"; NodeList::ConstIterator m = sections.at(i).members.begin(); while (m != sections.at(i).members.end()) { @@ -2113,7 +2125,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, } else { out() << ""; - out() << protect(node->doc().briefText().toString()); + out() << protectEnc(node->doc().briefText().toString()); out() << ""; } out() << "\n"; @@ -2315,7 +2327,7 @@ void HtmlGenerator::generateCompactList(const Node *relative, << linkForNode(it.value(), relative) << "\">"; QStringList pieces = fullName(it.value(), relative, marker).split("::"); - out() << protect(pieces.last()); + out() << protectEnc(pieces.last()); out() << ""; if (pieces.size() > 1) { out() << " ("; @@ -2357,7 +2369,7 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative, #else out() << "

"; #endif - out() << protect(f.key()) << ":"; + out() << protectEnc(f.key()) << ":"; currentLetter = f.key()[0].unicode(); while (islower(currentLetter) && currentLetter >= nextLetter) { @@ -2411,7 +2423,7 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2450,7 +2462,7 @@ void HtmlGenerator::generateQmlItem(const Node *node, QString marked = marker->markedUpQmlItem(node,summary); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -2556,7 +2568,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m const FakeNode *groupNode = groupTitlesMap[groupTitle]; out() << QString("

%2

\n").arg( linkForNode(groupNode, relative)).arg( - protect(groupNode->fullTitle())); + protectEnc(groupNode->fullTitle())); if (fakeNodeMap[groupNode].count() == 0) continue; @@ -2568,7 +2580,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m if (title.startsWith("The ")) title.remove(0, 4); out() << "
  • " - << protect(title) << "
  • \n"; + << protectEnc(title) << "\n"; } out() << "\n"; } @@ -2582,7 +2594,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m if (title.startsWith("The ")) title.remove(0, 4); out() << "
  • " - << protect(title) << "
  • \n"; + << protectEnc(title) << "\n"; } out() << "\n"; } @@ -2745,7 +2757,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, } out() << " inherited from " - << protect(marker->plainFullName((*p).first, relative)) + << protectEnc(marker->plainFullName((*p).first, relative)) << "\n"; ++p; } @@ -2760,7 +2772,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -3029,7 +3041,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, } out() << " inherited from " - << protect(marker->plainFullName((*p).first, relative)) + << protectEnc(marker->plainFullName((*p).first, relative)) << "\n"; ++p; } @@ -3043,7 +3055,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { - QString contents = protect(marked.mid(templateTag.pos(1), + QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); @@ -3241,7 +3253,7 @@ void HtmlGenerator::generateLink(const Atom* atom, if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { // hack for C++: move () outside of link int k = funcLeftParen.pos(1); - out() << protect(atom->string().left(k)); + out() << protectEnc(atom->string().left(k)); if (link.isEmpty()) { if (showBrokenLinks) out() << ""; @@ -3249,7 +3261,7 @@ void HtmlGenerator::generateLink(const Atom* atom, out() << ""; } inLink = false; - out() << protect(atom->string().mid(k)); + out() << protectEnc(atom->string().mid(k)); } else if (marker->recognizeLanguage("Java")) { // hack for Java: remove () and use when appropriate bool func = atom->string().endsWith("()"); @@ -3257,13 +3269,13 @@ void HtmlGenerator::generateLink(const Atom* atom, if (tt) out() << ""; if (func) { - out() << protect(atom->string().left(atom->string().length() - 2)); + out() << protectEnc(atom->string().left(atom->string().length() - 2)); } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } out() << ""; } else { - out() << protect(atom->string()); + out() << protectEnc(atom->string()); } } @@ -3337,7 +3349,12 @@ QString HtmlGenerator::registerRef(const QString& ref) return clean; } -QString HtmlGenerator::protect(const QString& string) +QString HtmlGenerator::protectEnc(const QString &string) +{ + return protect(string, outputEncoding); +} + +QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding) { #define APPEND(x) \ if (html.isEmpty()) { \ @@ -3360,7 +3377,7 @@ QString HtmlGenerator::protect(const QString& string) APPEND(">"); } else if (ch == QLatin1Char('"')) { APPEND("""); - } else if (ch.unicode() > 0x007F + } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F) || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator @@ -3490,7 +3507,7 @@ QString HtmlGenerator::refForNode(const Node *node) ref = node->name() + "-var"; break; case Node::Target: - return protect(node->name()); + return protectEnc(node->name()); } return registerRef(ref); } @@ -3564,7 +3581,7 @@ void HtmlGenerator::generateFullName(const Node *apparentNode, } } out() << "\">"; - out() << protect(fullName(apparentNode, relative, marker)); + out() << protectEnc(fullName(apparentNode, relative, marker)); out() << ""; } @@ -3625,12 +3642,12 @@ void HtmlGenerator::generateDetailedMember(const Node *node, else if (node->type() == Node::Enum) { const EnumNode *enume = static_cast(node); if (enume->flagsType()) { - out() << "

    The " << protect(enume->flagsType()->name()) + out() << "

    The " << protectEnc(enume->flagsType()->name()) << " type is a typedef for " << "QFlags<" - << protect(enume->name()) + << protectEnc(enume->name()) << ">. It stores an OR combination of " - << protect(enume->name()) + << protectEnc(enume->name()) << " values.

    \n"; } } diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 19a7c78..5ed26e0 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -104,7 +104,8 @@ class HtmlGenerator : public PageGenerator virtual QString format(); virtual void generateTree(const Tree *tree, CodeMarker *marker); - static QString protect(const QString& string); + QString protectEnc(const QString &string); + static QString protect(const QString &string, const QString &encoding = "ISO-8859-1"); static QString cleanRef(const QString& ref); static QString sinceTitle(int i) { return sinceTitles[i]; } diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index a001c10..e637109 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -176,7 +176,7 @@ void PageGenerator::beginSubPage(const Location& location, location.fatal(tr("Cannot open output file '%1'") .arg(outFile->fileName())); QTextStream *out = new QTextStream(outFile); - out->setCodec("ISO-8859-1"); + out->setCodec(outputCodec); outStreamStack.push(out); } diff --git a/tools/qdoc3/pagegenerator.h b/tools/qdoc3/pagegenerator.h index db24edd..20a6c3c 100644 --- a/tools/qdoc3/pagegenerator.h +++ b/tools/qdoc3/pagegenerator.h @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE +class QTextCodec; + class ClassNode; class InnerNode; class NamespaceNode; @@ -76,6 +78,10 @@ class PageGenerator : public Generator virtual void generateInnerNode(const InnerNode *node, CodeMarker *marker); QTextStream& out(); + QString naturalLanguage; + QString outputEncoding; + QTextCodec *outputCodec; + private: QStack outStreamStack; }; diff --git a/tools/qdoc3/qsakernelparser.cpp b/tools/qdoc3/qsakernelparser.cpp index 9320a17..8f12eda 100644 --- a/tools/qdoc3/qsakernelparser.cpp +++ b/tools/qdoc3/qsakernelparser.cpp @@ -70,8 +70,8 @@ void QsaKernelParser::parseSourceFile( const Location& location, const QString& filePath, Tree * /* tree */ ) { - FILE *in = fopen( QFile::encodeName(filePath), "r" ); - if ( in == 0 ) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error( tr("Cannot open QSA kernel file '%1'").arg(filePath) ); return; } @@ -171,7 +171,7 @@ void QsaKernelParser::parseSourceFile( const Location& location, readToken(); } } - fclose( in ); + in.close(); } void QsaKernelParser::doneParsingSourceFiles( Tree * /* tree */ ) diff --git a/tools/qdoc3/qscodeparser.cpp b/tools/qdoc3/qscodeparser.cpp index 8b3bc98..3b8bc1a 100644 --- a/tools/qdoc3/qscodeparser.cpp +++ b/tools/qdoc3/qscodeparser.cpp @@ -151,8 +151,8 @@ void QsCodeParser::parseHeaderFile(const Location& location, { qsTre = tree; - FILE *in = fopen(QFile::encodeName(filePath), "r"); - if (in == 0) { + QFile in(filePath); + if (!in.open(QIODevice::ReadOnly)) { location.error(tr("Cannot open Qt Script class list '%1'") .arg(filePath)); return; @@ -175,7 +175,7 @@ void QsCodeParser::parseHeaderFile(const Location& location, } tok = fileTokenizer.getToken(); } - fclose(in); + in.close(); } void QsCodeParser::parseSourceFile(const Location& location, diff --git a/tools/qdoc3/tokenizer.cpp b/tools/qdoc3/tokenizer.cpp index b391759..7c10de6 100644 --- a/tools/qdoc3/tokenizer.cpp +++ b/tools/qdoc3/tokenizer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,8 @@ static QRegExp *definedX = 0; static QRegExp *defines = 0; static QRegExp *falsehoods = 0; +static QTextCodec *sourceCodec = 0; + /* This function is a perfect hash function for the 37 keywords of C99 (with a hash table size of 512). It should perform well on our @@ -118,13 +121,10 @@ static void insertKwordIntoHash(const char *s, int number) kwordHashTable[k] = number; } -Tokenizer::Tokenizer(const Location& loc, FILE *in) +Tokenizer::Tokenizer(const Location& loc, QFile &in) { init(); - QFile file; - file.open(in, QIODevice::ReadOnly); - yyIn = file.readAll(); - file.close(); + yyIn = in.readAll(); yyPos = 0; start(loc); } @@ -483,6 +483,11 @@ void Tokenizer::initialize(const Config &config) { QString versionSym = config.getString(CONFIG_VERSIONSYM); + QString sourceEncoding = config.getString(CONFIG_SOURCEENCODING); + if (sourceEncoding.isEmpty()) + sourceEncoding = QLatin1String("ISO-8859-1"); + sourceCodec = QTextCodec::codecForName(sourceEncoding.toLocal8Bit()); + comment = new QRegExp("/(?:\\*.*\\*/|/.*\n|/[^\n]*$)"); comment->setMinimal(true); versionX = new QRegExp("$cannot possibly match^"); @@ -750,4 +755,14 @@ bool Tokenizer::isTrue(const QString &condition) return !falsehoods->exactMatch(t); } +QString Tokenizer::lexeme() const +{ + return sourceCodec->toUnicode(yyLex); +} + +QString Tokenizer::previousLexeme() const +{ + return sourceCodec->toUnicode(yyPrevLex); +} + QT_END_NAMESPACE diff --git a/tools/qdoc3/tokenizer.h b/tools/qdoc3/tokenizer.h index 519cffb..f55d2ef 100644 --- a/tools/qdoc3/tokenizer.h +++ b/tools/qdoc3/tokenizer.h @@ -46,11 +46,10 @@ #ifndef TOKENIZER_H #define TOKENIZER_H +#include #include #include -#include - #include "location.h" QT_BEGIN_NAMESPACE @@ -99,7 +98,7 @@ class Tokenizer { public: Tokenizer(const Location& loc, const QByteArray &in); - Tokenizer(const Location& loc, FILE *in); + Tokenizer(const Location& loc, QFile &file); ~Tokenizer(); @@ -108,8 +107,8 @@ class Tokenizer bool parsingFnOrMacro() const { return parsingMacro; } const Location &location() const { return yyTokLoc; } - QString previousLexeme() const { return QString(yyPrevLex); } - QString lexeme() const { return QString(yyLex); } + QString previousLexeme() const; + QString lexeme() const; QString version() const { return yyVersion; } int braceDepth() const { return yyBraceDepth; } int parenDepth() const { return yyParenDepth; } -- cgit v0.12 From 48b4d736a1cb19359e385aa8b86315eb8341b003 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 10:54:31 +1000 Subject: Compile fix for Direct Show media service plug-in. Remove duplicate #ifdef. --- src/plugins/mediaservices/directshow/dsserviceplugin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.cpp b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp index fc5d11f..f3ab889 100644 --- a/src/plugins/mediaservices/directshow/dsserviceplugin.cpp +++ b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp @@ -57,7 +57,6 @@ #ifdef QMEDIA_DIRECTSHOW_CAMERA -#ifdef QMEDIA_DIRECTSHOW_CAMERA #ifndef _STRSAFE_H_INCLUDED_ #include #endif -- cgit v0.12 From 396d731af30048e3b98be14a7b97e5ba682a86f8 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 10:56:50 +1000 Subject: Compile fix for DirectShowAudioEndpointControl. QAudioEndpointControl isn't defined in QtMultimedia, so inherit directly from QMediaControl instead. --- .../mediaplayer/directshowaudioendpointcontrol.cpp | 4 ++-- .../directshow/mediaplayer/directshowaudioendpointcontrol.h | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp index 2826ba5..4bb7228 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE DirectShowAudioEndpointControl::DirectShowAudioEndpointControl( DirectShowPlayerService *service, QObject *parent) - : QAudioEndpointSelector(parent) + : QMediaControl(parent) , m_service(service) , m_bindContext(0) , m_deviceEnumerator(0) @@ -130,7 +130,7 @@ void DirectShowAudioEndpointControl::updateEndpoints() oleMalloc->Free(string); moniker->AddRef(); - m_devices.insert(QString::fromWCharArray(string), moniker); + m_devices.insert(deviceId, moniker); if (m_defaultEndpoint.isEmpty() || deviceId.endsWith(QLatin1String("Default DirectSound Device"))) { diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h index 9ab188c..2faac13 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h @@ -42,19 +42,17 @@ #ifndef DIRECTSHOWAUDIOENDPOINTCONTROL_H #define DIRECTSHOWAUDIOENDPOINTCONTROL_H -#include +#include #include - QT_BEGIN_HEADER QT_BEGIN_NAMESPACE class DirectShowPlayerService; - -class DirectShowAudioEndpointControl : public QAudioEndpointSelector +class DirectShowAudioEndpointControl : public QMediaControl { Q_OBJECT public: @@ -82,6 +80,13 @@ private: QString m_activeEndpoint; }; +#define QAudioEndpointSelector_iid "com.nokia.Qt.QAudioEndpointSelector/1.0" + +class Duck +{ + uint quack; +}; + QT_END_NAMESPACE QT_END_HEADER -- cgit v0.12 From 5a43e96062f7bd82ff9deb57e065b757d784607d Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:01:11 +1000 Subject: Clip the paint region of QGraphicsVideoItem to it's bounding rect. --- src/multimedia/base/qgraphicsvideoitem.cpp | 50 ++++++++++++++++---------- src/multimedia/base/qpaintervideosurface.cpp | 54 ++++++++++++++++------------ src/multimedia/base/qpaintervideosurface_p.h | 2 +- 3 files changed, 64 insertions(+), 42 deletions(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp index 1a5ccd7..35baabe 100644 --- a/src/multimedia/base/qgraphicsvideoitem.cpp +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -64,6 +64,7 @@ public: , rendererControl(0) , aspectRatioMode(Qt::KeepAspectRatio) , updatePaintDevice(true) + , rect(0.0, 0.0, 320, 240) { } @@ -78,10 +79,11 @@ public: bool updatePaintDevice; QRectF rect; QRectF boundingRect; + QRectF sourceRect; QSizeF nativeSize; void clearService(); - void updateBoundingRect(); + void updateRects(); void _q_present(); void _q_formatChanged(const QVideoSurfaceFormat &format); @@ -106,22 +108,32 @@ void QGraphicsVideoItemPrivate::clearService() } } -void QGraphicsVideoItemPrivate::updateBoundingRect() +void QGraphicsVideoItemPrivate::updateRects() { q_ptr->prepareGeometryChange(); if (nativeSize.isEmpty()) { boundingRect = QRectF(); - } else { - if (aspectRatioMode == Qt::IgnoreAspectRatio) { - boundingRect = rect; - } else { - QSizeF size = nativeSize; - size.scale(rect.size(), aspectRatioMode); - - boundingRect = QRectF(QPointF(), size); - boundingRect.moveCenter(rect.center()); - } + } else if (aspectRatioMode == Qt::IgnoreAspectRatio) { + boundingRect = rect; + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatio) { + QSizeF size = nativeSize; + size.scale(rect.size(), Qt::KeepAspectRatio); + + boundingRect = QRectF(0, 0, size.width(), size.height()); + boundingRect.moveCenter(rect.center()); + + sourceRect = QRectF(0, 0, 1, 1); + } else if (aspectRatioMode == Qt::KeepAspectRatioByExpanding) { + boundingRect = rect; + + QSizeF size = rect.size(); + size.scale(nativeSize, Qt::KeepAspectRatio); + + sourceRect = QRectF( + 0, 0, size.width() / nativeSize.width(), size.height() / nativeSize.height()); + sourceRect.moveCenter(QPointF(0.5, 0.5)); } } @@ -139,7 +151,9 @@ void QGraphicsVideoItemPrivate::_q_formatChanged(const QVideoSurfaceFormat &form { nativeSize = format.sizeHint(); - updateBoundingRect(); + updateRects(); + + emit q_ptr->nativeSizeChanged(nativeSize); } void QGraphicsVideoItemPrivate::_q_serviceDestroyed() @@ -299,7 +313,7 @@ void QGraphicsVideoItem::setAspectRatioMode(Qt::AspectRatioMode mode) Q_D(QGraphicsVideoItem); d->aspectRatioMode = mode; - d->updateBoundingRect(); + d->updateRects(); } /*! @@ -320,7 +334,7 @@ void QGraphicsVideoItem::setOffset(const QPointF &offset) Q_D(QGraphicsVideoItem); d->rect.moveTo(offset); - d->updateBoundingRect(); + d->updateRects(); } /*! @@ -340,8 +354,8 @@ void QGraphicsVideoItem::setSize(const QSizeF &size) { Q_D(QGraphicsVideoItem); - d->rect.setSize(size); - d->updateBoundingRect(); + d->rect.setSize(size.isValid() ? size : QSizeF(0, 0)); + d->updateRects(); } /*! @@ -380,7 +394,7 @@ void QGraphicsVideoItem::paint( Q_UNUSED(widget); if (d->surface && d->surface->isActive()) { - d->surface->paint(painter, d->boundingRect); + d->surface->paint(painter, d->boundingRect, d->sourceRect); d->surface->setReady(true); #ifndef QGRAPHICSVIDEOITEM_SHADERS // Flickers } diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index 9953ae8..533ddee 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -73,7 +73,7 @@ public: virtual QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame) = 0; virtual QAbstractVideoSurface::Error paint( - const QRectF &target, QPainter *painter, const QRect &source) = 0; + const QRectF &target, QPainter *painter, const QRectF &source) = 0; virtual void updateColors(int brightness, int contrast, int hue, int saturation) = 0; }; @@ -99,7 +99,7 @@ public: QAbstractVideoSurface::Error setCurrentFrame(const QVideoFrame &frame); QAbstractVideoSurface::Error paint( - const QRectF &target, QPainter *painter, const QRect &source); + const QRectF &target, QPainter *painter, const QRectF &source); void updateColors(int brightness, int contrast, int hue, int saturation); @@ -167,7 +167,7 @@ QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::setCurrentFrame(const Q } QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::paint( - const QRectF &target, QPainter *painter, const QRect &source) + const QRectF &target, QPainter *painter, const QRectF &source) { if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { QImage image( @@ -183,7 +183,7 @@ QAbstractVideoSurface::Error QVideoSurfaceRasterPainter::paint( painter->scale(1, -1); painter->translate(0, -target.bottom()); painter->drawImage( - QRect(target.x(), 0, target.width(), target.height()), image, source); + QRectF(target.x(), 0, target.width(), target.height()), image, source); painter->setTransform(oldTransform); } else { painter->drawImage(target, image, source); @@ -540,7 +540,8 @@ public: QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); void stop(); - QAbstractVideoSurface::Error paint(const QRectF &target, QPainter *painter, const QRect &source); + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); private: typedef void (APIENTRY *_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *); @@ -700,19 +701,19 @@ void QVideoSurfaceArbFpPainter::stop() } QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::paint( - const QRectF &target, QPainter *painter, const QRect &source) + const QRectF &target, QPainter *painter, const QRectF &source) { if (m_frame.isValid()) { painter->beginNativePainting(); - const float txLeft = float(source.left()) / float(m_frameSize.width()); - const float txRight = float(source.right()) / float(m_frameSize.width()); + const float txLeft = source.left() / m_frameSize.width(); + const float txRight = source.right() / m_frameSize.width(); const float txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom - ? float(source.top()) / float(m_frameSize.height()) - : float(source.bottom()) / float(m_frameSize.height()); + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); const float txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom - ? float(source.bottom()) / float(m_frameSize.height()) - : float(source.top()) / float(m_frameSize.height()); + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); const float tx_array[] = @@ -857,7 +858,8 @@ public: QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format); void stop(); - QAbstractVideoSurface::Error paint(const QRectF &target, QPainter *painter, const QRect &source); + QAbstractVideoSurface::Error paint( + const QRectF &target, QPainter *painter, const QRectF &source); private: QGLShaderProgram m_program; @@ -975,7 +977,7 @@ void QVideoSurfaceGlslPainter::stop() } QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( - const QRectF &target, QPainter *painter, const QRect &source) + const QRectF &target, QPainter *painter, const QRectF &source) { if (m_frame.isValid()) { painter->beginNativePainting(); @@ -1021,14 +1023,14 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( target.right() + 1, target.top() }; - const GLfloat txLeft = float(source.left()) / float(m_frameSize.width()); - const GLfloat txRight = float(source.right()) / float(m_frameSize.width()); + const GLfloat txLeft = source.left() / m_frameSize.width(); + const GLfloat txRight = source.right() / m_frameSize.width(); const GLfloat txTop = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom - ? float(source.top()) / float(m_frameSize.height()) - : float(source.bottom()) / float(m_frameSize.height()); + ? source.top() / m_frameSize.height() + : source.bottom() / m_frameSize.height(); const GLfloat txBottom = m_scanLineDirection == QVideoSurfaceFormat::TopToBottom - ? float(source.bottom()) / float(m_frameSize.height()) - : float(source.top()) / float(m_frameSize.height()); + ? source.bottom() / m_frameSize.height() + : source.top() / m_frameSize.height(); const GLfloat textureCoordArray[] = { @@ -1289,17 +1291,23 @@ void QPainterVideoSurface::setReady(bool ready) /*! */ -void QPainterVideoSurface::paint(QPainter *painter, const QRectF &rect) +void QPainterVideoSurface::paint(QPainter *painter, const QRectF &target, const QRectF &source) { if (!isActive()) { - painter->fillRect(rect, QBrush(Qt::black)); + painter->fillRect(target, QBrush(Qt::black)); } else { if (m_colorsDirty) { m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); m_colorsDirty = false; } - QAbstractVideoSurface::Error error = m_painter->paint(rect, painter, m_sourceRect); + const QRectF sourceRect( + m_sourceRect.x() + m_sourceRect.width() * source.x(), + m_sourceRect.y() + m_sourceRect.height() * source.y(), + m_sourceRect.width() * source.width(), + m_sourceRect.height() * source.height()); + + QAbstractVideoSurface::Error error = m_painter->paint(target, painter, sourceRect); if (error != QAbstractVideoSurface::NoError) { setError(error); diff --git a/src/multimedia/base/qpaintervideosurface_p.h b/src/multimedia/base/qpaintervideosurface_p.h index 5340956..d4b6740 100644 --- a/src/multimedia/base/qpaintervideosurface_p.h +++ b/src/multimedia/base/qpaintervideosurface_p.h @@ -102,7 +102,7 @@ public: bool isReady() const; void setReady(bool ready); - void paint(QPainter *painter, const QRectF &rect); + void paint(QPainter *painter, const QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1)); #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) const QGLContext *glContext() const; -- cgit v0.12 From 25579113df82d0e665bb90831586b7510e52469e Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:14:49 +1000 Subject: Send an EC_COMPLETE event from the video surface filter on end of stream Otherwise the filter graph won't stop itself as it hasn't received the event from all the output filters. --- .../mediaplayer/directshowsamplescheduler.cpp | 22 +++++++++++++++++- .../mediaplayer/directshowsamplescheduler.h | 3 ++- .../directshow/mediaplayer/videosurfacefilter.cpp | 27 +++++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp index 921330c..733080e 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp @@ -53,6 +53,7 @@ public: : m_next(0) , m_sample(sample) , m_cookie(0) + , m_lastSample(false) { m_sample->AddRef(); } @@ -75,10 +76,14 @@ public: bool isReady(IReferenceClock *clock) const; + bool isLast() const { return m_lastSample; } + void setLast() { m_lastSample = true; } + private: DirectShowTimedSample *m_next; IMediaSample *m_sample; DWORD_PTR m_cookie; + bool m_lastSample; }; bool DirectShowTimedSample::schedule( @@ -355,7 +360,7 @@ void DirectShowSampleScheduler::setClock(IReferenceClock *clock) m_clock->AddRef(); } -IMediaSample *DirectShowSampleScheduler::takeSample() +IMediaSample *DirectShowSampleScheduler::takeSample(bool *eos) { QMutexLocker locker(&m_mutex); @@ -364,6 +369,8 @@ IMediaSample *DirectShowSampleScheduler::takeSample() sample->AddRef(); if (m_state == Running) { + *eos = m_head->isLast(); + m_head = m_head->remove(); if (!m_head) @@ -378,6 +385,19 @@ IMediaSample *DirectShowSampleScheduler::takeSample() } } +bool DirectShowSampleScheduler::scheduleEndOfStream() +{ + QMutexLocker locker(&m_mutex); + + if (m_tail) { + m_tail->setLast(); + + return true; + } else { + return false; + } +} + bool DirectShowSampleScheduler::event(QEvent *event) { if (event->type() == QEvent::WinEventAct) { diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h index 7af9112..007fa99 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h @@ -97,8 +97,9 @@ public: void setClock(IReferenceClock *clock); bool schedule(IMediaSample *sample); + bool scheduleEndOfStream(); - IMediaSample *takeSample(); + IMediaSample *takeSample(bool *eos); bool event(QEvent *event); diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp index a5565f1..7b4aad5 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp @@ -42,6 +42,7 @@ #include "videosurfacefilter.h" #include "directshoweventloop.h" +#include "directshowglobal.h" #include "directshowpinenum.h" #include "mediasamplevideobuffer.h" @@ -442,6 +443,18 @@ HRESULT VideoSurfaceFilter::QueryInternalConnections(IPin **apPin, ULONG *nPin) HRESULT VideoSurfaceFilter::EndOfStream() { + QMutexLocker locker(&m_mutex); + + if (!m_sampleScheduler.scheduleEndOfStream()) { + if (IMediaEventSink *sink = com_cast(m_graph)) { + sink->Notify( + EC_COMPLETE, + S_OK, + reinterpret_cast(static_cast(this))); + sink->Release(); + } + } + return S_OK; } @@ -584,7 +597,9 @@ void VideoSurfaceFilter::supportedFormatsChanged() void VideoSurfaceFilter::sampleReady() { - IMediaSample *sample = m_sampleScheduler.takeSample(); + bool eos = false; + + IMediaSample *sample = m_sampleScheduler.takeSample(&eos); if (sample) { m_surface->present(QVideoFrame( @@ -593,6 +608,16 @@ void VideoSurfaceFilter::sampleReady() m_surfaceFormat.pixelFormat())); sample->Release(); + + if (eos) { + if (IMediaEventSink *sink = com_cast(m_graph)) { + sink->Notify( + EC_COMPLETE, + S_OK, + reinterpret_cast(static_cast(this))); + sink->Release(); + } + } } } -- cgit v0.12 From b136d5a9c2dbb83199d61de2ce88f801637434bb Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:18:17 +1000 Subject: Handle graph events in the service thread rather than the gui thread. This makes the service thread responsible for the last of the graph manipulation and state update tasks. --- .../mediaplayer/directshowplayerservice.cpp | 382 +++++++++------------ .../mediaplayer/directshowplayerservice.h | 52 +-- 2 files changed, 201 insertions(+), 233 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index ea4b73c..d205ac1 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -88,6 +88,8 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) , m_pendingTasks(0) , m_executingTask(0) , m_executedTasks(0) + , m_taskHandle(::CreateEvent(0, 0, 0, 0)) + , m_eventHandle(0) , m_graphStatus(NoMedia) , m_stream(0) , m_graph(0) @@ -99,6 +101,7 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) , m_duration(0) , m_buffering(false) , m_seekable(false) + , m_atEnd(false) { m_playerControl = new DirectShowPlayerControl(this); m_metaDataControl = new DirectShowMetaDataControl(this); @@ -112,8 +115,6 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) connect(m_videoOutputControl, SIGNAL(outputChanged()), this, SLOT(videoOutputChanged())); connect(m_videoRendererControl, SIGNAL(filterChanged()), this, SLOT(videoOutputChanged())); - - connect(&m_graphEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(graphEvent(HANDLE))); } DirectShowPlayerService::~DirectShowPlayerService() @@ -121,43 +122,15 @@ DirectShowPlayerService::~DirectShowPlayerService() { QMutexLocker locker(&m_mutex); - m_pendingTasks = Shutdown; - - if (m_graph) { - m_graphEventNotifier.setEnabled(false); - - if (IAMOpenProgress *progress = com_cast(m_graph)) { - progress->AbortOperation(); - progress->Release(); - } - - m_graph->Abort(); + releaseGraph(); - if (IMediaControl *control = com_cast(m_graph)) { - control->Stop(); - OAFilterState state; - control->GetState(INFINITE, &state); - control->Release(); - } - } - m_wait.wakeAll(); - - m_loop.wait(&m_mutex); + m_pendingTasks = Shutdown; + ::SetEvent(m_taskHandle); } m_taskThread->wait(); delete m_taskThread; - if (m_graph) { - m_graph->Release(); - m_graph = 0; - } - - if (m_source) { - m_source->Release(); - m_source = 0; - } - if (m_audioOutput) { m_audioOutput->Release(); m_audioOutput = 0; @@ -174,6 +147,8 @@ DirectShowPlayerService::~DirectShowPlayerService() delete m_videoOutputControl; delete m_videoRendererControl; delete m_videoWindowControl; + + ::CloseHandle(m_taskHandle); } QMediaControl *DirectShowPlayerService::control(const char *name) const @@ -198,34 +173,10 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream { QMutexLocker locker(&m_mutex); - if (m_graph) { - m_graphEventNotifier.setEnabled(false); - - if (m_executingTask != 0) { - if (IAMOpenProgress *progress = com_cast(m_graph)) { - progress->AbortOperation(); - progress->Release(); - } else { - m_graph->Abort(); - } - - m_pendingTasks = Stop; + m_pendingTasks = 0; - m_loop.wait(&m_mutex); - } - if (IMediaControl *control = com_cast(m_graph)) { - control->Stop(); - control->Release(); - } - - if (m_source) { - m_source->Release(); - m_source = 0; - } - - m_graph->Release(); - m_graph = 0; - } + if (m_graph) + releaseGraph(); m_resources = media.resources(); m_stream = stream; @@ -234,6 +185,7 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_executedTasks = 0; m_buffering = false; m_seekable = false; + m_atEnd = false; m_metaDataControl->updateGraph(0, 0); if (m_resources.isEmpty() && !stream) { @@ -246,21 +198,12 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_graph = com_new(CLSID_FilterGraph); - if (IMediaEventEx *event = com_cast(m_graph)) { - HANDLE handle; - if (event->GetEventHandle(reinterpret_cast(&handle)) == S_OK) { - m_graphEventNotifier.setHandle(handle); - m_graphEventNotifier.setEnabled(true); - } - event->Release(); - } - if (stream) m_pendingTasks = SetStreamSource; else m_pendingTasks = SetUrlSource; - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); @@ -399,7 +342,7 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker) IBaseFilter *filter = filters[filters.size() - 1]; filters.removeLast(); - if (m_executingTask == Render && SUCCEEDED(filter->EnumPins(&pins))) { + if (!(m_pendingTasks & ReleaseFilters) && SUCCEEDED(filter->EnumPins(&pins))) { int outputs = 0; for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { PIN_DIRECTION direction; @@ -446,7 +389,7 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker) graph->Release(); - if (m_executingTask == Render) { + if (!(m_pendingTasks & ReleaseFilters)) { if (rendered) { if (!(m_executedTasks & FinalizeLoad)) m_pendingTasks |= FinalizeLoad; @@ -475,13 +418,15 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker) m_executedTasks |= Render; } - - m_loop.wake(); } void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker) { if (m_graphStatus != Loaded) { + if (IMediaEvent *event = com_cast(m_graph)) { + event->GetEventHandle(reinterpret_cast(&m_eventHandle)); + event->Release(); + } if (IMediaSeeking *seeking = com_cast(m_graph)) { LONGLONG duration = 0; seeking->GetDuration(&duration); @@ -508,22 +453,45 @@ void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker) QCoreApplication::postEvent(this, new QEvent(QEvent::Type(FinalizedLoad))); } - -void DirectShowPlayerService::doUpdateDuration(QMutexLocker *) +void DirectShowPlayerService::releaseGraph() { - if (IMediaSeeking *seeking = com_cast(m_graph)) { - LONGLONG duration = 0; - seeking->GetDuration(&duration); - m_duration = duration / 10; + if (m_graph) { + if (m_executingTask != 0) { + if (IAMOpenProgress *progress = com_cast(m_graph)) { + progress->AbortOperation(); + progress->Release(); + } + m_graph->Abort(); + } + + m_pendingTasks = ReleaseGraph; - DWORD capabilities = 0; - seeking->GetCapabilities(&capabilities); - m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute; + ::SetEvent(m_taskHandle); - seeking->Release(); + m_loop.wait(&m_mutex); + } +} - QCoreApplication::postEvent(this, new QEvent(QEvent::Type(DurationChange))); +void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker) +{ + Q_UNUSED(locker); + + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); } + + if (m_source) { + m_source->Release(); + m_source = 0; + } + + m_eventHandle = 0; + + m_graph->Release(); + m_graph = 0; + + m_loop.wake(); } int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const @@ -611,12 +579,13 @@ void DirectShowPlayerService::play() if (m_executedTasks & Render) { if (m_executedTasks & Stop) { + m_atEnd = false; m_position = 0; m_pendingTasks |= Seek; m_executedTasks ^= Stop; } - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } } @@ -635,7 +604,7 @@ void DirectShowPlayerService::doPlay(QMutexLocker *locker) if (SUCCEEDED(hr)) { m_executedTasks |= Play; - QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Started))); + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); } else { m_error = QMediaPlayer::ResourceError; qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", hr); @@ -654,12 +623,13 @@ void DirectShowPlayerService::pause() if (m_executedTasks & Render) { if (m_executedTasks & Stop) { + m_atEnd = false; m_position = 0; m_pendingTasks |= Seek; m_executedTasks ^= Stop; } - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } } @@ -675,7 +645,7 @@ void DirectShowPlayerService::doPause(QMutexLocker *locker) if (SUCCEEDED(hr)) { m_executedTasks |= Pause; - QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Paused))); + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); } else { m_error = QMediaPlayer::ResourceError; qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", hr); @@ -719,7 +689,7 @@ void DirectShowPlayerService::setRate(qreal rate) m_pendingTasks |= SetRate; if (m_executedTasks & FinalizeLoad) - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } void DirectShowPlayerService::doSetRate(QMutexLocker *locker) @@ -804,7 +774,7 @@ void DirectShowPlayerService::seek(qint64 position) m_pendingTasks |= Seek; if (m_executedTasks & FinalizeLoad) - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } void DirectShowPlayerService::doSeek(QMutexLocker *locker) @@ -856,9 +826,11 @@ void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) if (m_graph) { if (m_audioOutput) { if (m_executedTasks & SetAudioOutput) { - removeOutput(m_audioOutput); + m_pendingTasks |= ReleaseAudioOutput; - m_executedTasks &= ~SetAudioOutput; + ::SetEvent(m_taskHandle); + + m_loop.wait(&m_mutex); } m_audioOutput->Release(); } @@ -876,7 +848,7 @@ void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) if (m_executedTasks & SetSource) { m_pendingTasks |= Render; - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } } else { if (m_audioOutput) @@ -891,6 +863,22 @@ void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) m_playerControl->updateAudioOutput(m_audioOutput); } +void DirectShowPlayerService::doReleaseAudioOutput(QMutexLocker *locker) +{ + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); + } + + m_graph->RemoveFilter(m_audioOutput); + + m_executedTasks &= ~SetAudioOutput; + + m_loop.wake(); +} + void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) { QMutexLocker locker(&m_mutex); @@ -898,9 +886,11 @@ void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) if (m_graph) { if (m_videoOutput) { if (m_executedTasks & SetVideoOutput) { - removeOutput(m_videoOutput); + m_pendingTasks |= ReleaseVideoOutput; - m_executedTasks &= ~SetVideoOutput; + ::SetEvent(m_taskHandle); + + m_loop.wait(&m_mutex); } m_videoOutput->Release(); } @@ -918,7 +908,7 @@ void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) if (m_executedTasks & SetSource) { m_pendingTasks |= Render; - m_wait.wakeAll(); + ::SetEvent(m_taskHandle); } } else { if (m_videoOutput) @@ -931,11 +921,25 @@ void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) } } +void DirectShowPlayerService::doReleaseVideoOutput(QMutexLocker *locker) +{ + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); + } + + m_graph->RemoveFilter(m_videoOutput); + + m_executedTasks &= ~SetVideoOutput; + + m_loop.wake(); +} + void DirectShowPlayerService::customEvent(QEvent *event) { if (event->type() == QEvent::Type(FinalizedLoad)) { - event->accept(); - QMutexLocker locker(&m_mutex); m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); @@ -943,8 +947,6 @@ void DirectShowPlayerService::customEvent(QEvent *event) updateStatus(); } else if (event->type() == QEvent::Type(Error)) { - event->accept(); - QMediaPlayer::Error error; { QMutexLocker locker(&m_mutex); @@ -958,23 +960,24 @@ void DirectShowPlayerService::customEvent(QEvent *event) } m_playerControl->error(error, QString()); } else if (event->type() == QEvent::Type(RateChange)) { - event->accept(); - QMutexLocker locker(&m_mutex); m_playerControl->updatePlaybackRate(m_rate); - } else if (event->type() == QEvent::Type(Started) || event->type() == QEvent::Type(Paused)) { - event->accept(); - + } else if (event->type() == QEvent::Type(StatusChange)) { QMutexLocker locker(&m_mutex); updateStatus(); } else if (event->type() == QEvent::Type(DurationChange)) { - event->accept(); - QMutexLocker locker(&m_mutex); m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + } else if (event->type() == QEvent::Type(EndOfMedia)) { + QMutexLocker locker(&m_mutex); + + if (m_atEnd) { + m_playerControl->updateState(QMediaPlayer::StoppedState); + m_playerControl->updateStatus(QMediaPlayer::EndOfMedia); + } } else { QMediaService::customEvent(event); } @@ -998,7 +1001,7 @@ void DirectShowPlayerService::videoOutputChanged() setVideoOutput(videoOutput); } -void DirectShowPlayerService::graphEvent(HANDLE handle) +void DirectShowPlayerService::graphEvent(QMutexLocker *locker) { if (IMediaEvent *event = com_cast(m_graph)) { long eventCode; @@ -1008,32 +1011,32 @@ void DirectShowPlayerService::graphEvent(HANDLE handle) while (event->GetEvent(&eventCode, ¶m1, ¶m2, 0) == S_OK) { switch (eventCode) { case EC_BUFFERING_DATA: - { - QMutexLocker locker(&m_mutex); - m_buffering = param1; + m_buffering = param1; - updateStatus(); - } + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); break; case EC_COMPLETE: - { - QMutexLocker locker(&m_mutex); - m_executedTasks &= ~(Play | Pause); - m_executedTasks |= Stop; - - m_buffering = false; - m_playerControl->updateStatus(QMediaPlayer::EndOfMedia); - m_playerControl->updateState(QMediaPlayer::StoppedState); - } + m_executedTasks &= ~(Play | Pause); + m_executedTasks |= Stop; + + m_buffering = false; + m_atEnd = true; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(EndOfMedia))); break; case EC_LENGTH_CHANGED: - { - QMutexLocker locker(&m_mutex); - if (m_executedTasks & FinalizeLoad) { - m_pendingTasks |= UpdateDuration; + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG duration = 0; + seeking->GetDuration(&duration); + m_duration = duration / 10; - m_wait.wakeAll(); - } + DWORD capabilities = 0; + seeking->GetCapabilities(&capabilities); + m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute; + + seeking->Release(); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(DurationChange))); } break; default: @@ -1073,76 +1076,6 @@ void DirectShowPlayerService::updateStatus() } } -void DirectShowPlayerService::removeOutput(IBaseFilter *output) -{ - while (m_executingTask != 0) { - if (m_executingTask == Render) { - m_executingTask = 0; - - if (IAMOpenProgress *progress = com_cast(m_graph)) { - progress->AbortOperation(); - progress->Release(); - } - } - m_loop.wait(&m_mutex); - } - - m_pendingTasks |= m_executedTasks & (Play | Pause); - - if (IMediaControl *control = com_cast(m_graph)) { - control->Stop(); - control->Release(); - } - - if (IFilterChain *chain = com_cast(m_graph)) { - IBaseFilter *start = findChainStart(output); - - chain->RemoveChain(start, output); - - start->Release(); - chain->Release(); - } else { - m_graph->RemoveFilter(output); - } -} - -IBaseFilter *DirectShowPlayerService::findChainStart(IBaseFilter *end) const -{ - IBaseFilter *start = 0; - end->AddRef(); - - while (start != end) { - start = end; - - IEnumPins *pins = 0; - - if (SUCCEEDED(end->EnumPins(&pins))) { - for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { - PIN_DIRECTION direction; - if (SUCCEEDED(pin->QueryDirection(&direction)) && direction == PINDIR_INPUT) { - IPin *peer = 0; - if (SUCCEEDED(pin->ConnectedTo(&peer))) { - PIN_INFO peerInfo; - if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) { - CLSID classId; - if (SUCCEEDED(peerInfo.pFilter->GetClassID(&classId)) - && classId == CLSID_Colour) { - end->Release(); - end = peerInfo.pFilter; - } else { - peerInfo.pFilter->Release(); - } - } - peer->Release(); - } - } - } - pins->Release(); - } - } - return start; -} - bool DirectShowPlayerService::isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const { bool connected = false; @@ -1170,8 +1103,45 @@ void DirectShowPlayerService::run() { QMutexLocker locker(&m_mutex); - while (!(m_pendingTasks & Shutdown)) { - if (m_pendingTasks & SetUrlSource) { + for (;;) { + ::ResetEvent(m_taskHandle); + + while (m_pendingTasks == 0) { + DWORD result = 0; + + locker.unlock(); + if (m_eventHandle) { + HANDLE handles[] = { m_taskHandle, m_eventHandle }; + + result = ::WaitForMultipleObjects(2, handles, false, INFINITE); + } else { + result = ::WaitForSingleObject(m_taskHandle, INFINITE); + } + locker.relock(); + + if (result == WAIT_OBJECT_0 + 1) { + graphEvent(&locker); + } + } + + if (m_pendingTasks & ReleaseGraph) { + m_pendingTasks ^= ReleaseGraph; + m_executingTask = ReleaseGraph; + + doReleaseGraph(&locker); + } else if (m_pendingTasks & Shutdown) { + return; + } else if (m_pendingTasks & ReleaseAudioOutput) { + m_pendingTasks ^= ReleaseAudioOutput; + m_executingTask = ReleaseAudioOutput; + + doReleaseAudioOutput(&locker); + } else if (m_pendingTasks & ReleaseVideoOutput) { + m_pendingTasks ^= ReleaseVideoOutput; + m_executingTask = ReleaseVideoOutput; + + doReleaseVideoOutput(&locker); + } else if (m_pendingTasks & SetUrlSource) { m_pendingTasks ^= SetUrlSource; m_executingTask = SetUrlSource; @@ -1193,11 +1163,6 @@ void DirectShowPlayerService::run() m_executingTask = FinalizeLoad; doFinalizeLoad(&locker); - } else if (m_pendingTasks & UpdateDuration) { - m_pendingTasks ^= UpdateDuration; - m_executingTask ^= UpdateDuration; - - doUpdateDuration(&locker); } else if (m_pendingTasks & SetRate) { m_pendingTasks ^= SetRate; m_executingTask = SetRate; @@ -1224,12 +1189,7 @@ void DirectShowPlayerService::run() doPlay(&locker); } m_executingTask = 0; - - if (m_pendingTasks == 0) - m_wait.wait(&m_mutex); } - - m_loop.wake(); } QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h index 3a01889..9ea5d7d 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h @@ -105,16 +105,14 @@ protected: private Q_SLOTS: void videoOutputChanged(); - void graphEvent(HANDLE handle); private: + void releaseGraph(); void updateStatus(); int findStreamTypes(IBaseFilter *source) const; int findStreamType(IPin *pin) const; - void removeOutput(IBaseFilter *output); - IBaseFilter *findChainStart(IBaseFilter *end) const; bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const; void run(); @@ -127,25 +125,32 @@ private: void doSeek(QMutexLocker *locker); void doPlay(QMutexLocker *locker); void doPause(QMutexLocker *locker); - void doUpdateDuration(QMutexLocker *locker); + void doReleaseAudioOutput(QMutexLocker *locker); + void doReleaseVideoOutput(QMutexLocker *locker); + void doReleaseGraph(QMutexLocker *locker); + + void graphEvent(QMutexLocker *locker); enum Task { - Shutdown = 0x0001, - SetUrlSource = 0x0002, - SetStreamSource = 0x0004, - SetSource = SetUrlSource | SetStreamSource, - SetAudioOutput = 0x0008, - SetVideoOutput = 0x0010, - SetOutputs = SetAudioOutput | SetVideoOutput, - Render = 0x0020, - FinalizeLoad = 0x0040, - SetRate = 0x0080, - Seek = 0x0100, - Play = 0x0200, - Pause = 0x0400, - Stop = 0x0800, - UpdateDuration = 0x1000 + Shutdown = 0x0001, + SetUrlSource = 0x0002, + SetStreamSource = 0x0004, + SetSource = SetUrlSource | SetStreamSource, + SetAudioOutput = 0x0008, + SetVideoOutput = 0x0010, + SetOutputs = SetAudioOutput | SetVideoOutput, + Render = 0x0020, + FinalizeLoad = 0x0040, + SetRate = 0x0080, + Seek = 0x0100, + Play = 0x0200, + Pause = 0x0400, + Stop = 0x0800, + ReleaseGraph = 0x1000, + ReleaseAudioOutput = 0x2000, + ReleaseVideoOutput = 0x4000, + ReleaseFilters = ReleaseGraph | ReleaseAudioOutput | ReleaseVideoOutput }; enum Event @@ -155,7 +160,9 @@ private: RateChange, Started, Paused, - DurationChange + DurationChange, + StatusChange, + EndOfMedia }; enum GraphStatus @@ -177,6 +184,8 @@ private: int m_pendingTasks; int m_executingTask; int m_executedTasks; + HANDLE m_taskHandle; + HANDLE m_eventHandle; GraphStatus m_graphStatus; QMediaPlayer::Error m_error; QIODevice *m_stream; @@ -190,12 +199,11 @@ private: qint64 m_duration; bool m_buffering; bool m_seekable; + bool m_atEnd; QMediaTimeRange m_playbackRange; QUrl m_url; QMediaResourceList m_resources; QMutex m_mutex; - QWaitCondition m_wait; - QWinEventNotifier m_graphEventNotifier; DirectShowEventLoop m_loop; friend class DirectShowPlayerServiceThread; -- cgit v0.12 From 53ff697fb83c69e02a72a73ee13e9ca4f795c5a8 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:29:50 +1000 Subject: Compile fix for DirectShowEventLoop. QT_END_NAMESPAC -> QT_END_NAMESPACE --- src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h index eb68af3..f46e65a 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h @@ -76,7 +76,7 @@ private: QMutex m_mutex; }; -QT_END_NAMESPAC +QT_END_NAMESPACE QT_END_HEADER -- cgit v0.12 From 3c90f04c31d266a640ccf3b187d6971f7ade7500 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:42:04 +1000 Subject: Share a single instance of DirectShowEventLoop between services. --- .../mediaplayer/directshowplayerservice.cpp | 22 ++++++++++++---------- .../mediaplayer/directshowplayerservice.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index d205ac1..a3362db 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -58,6 +58,7 @@ #include +Q_GLOBAL_STATIC(DirectShowEventLoop, qt_directShowEventLoop) QT_BEGIN_NAMESPACE @@ -85,6 +86,7 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) , m_videoRendererControl(0) , m_videoWindowControl(0) , m_taskThread(0) + , m_loop(qt_directShowEventLoop()) , m_pendingTasks(0) , m_executingTask(0) , m_executedTasks(0) @@ -107,7 +109,7 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) m_metaDataControl = new DirectShowMetaDataControl(this); m_videoOutputControl = new DirectShowVideoOutputControl; m_audioEndpointControl = new DirectShowAudioEndpointControl(this); - m_videoRendererControl = new DirectShowVideoRendererControl(&m_loop); + m_videoRendererControl = new DirectShowVideoRendererControl(m_loop); m_videoWindowControl = new Vmr9VideoWindowControl; m_taskThread = new DirectShowPlayerServiceThread(this); @@ -284,7 +286,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker) { - IBaseFilter *source = new DirectShowIOSource(m_stream, &m_loop); + IBaseFilter *source = new DirectShowIOSource(m_stream, m_loop); if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) { m_executedTasks = SetSource; @@ -468,7 +470,7 @@ void DirectShowPlayerService::releaseGraph() ::SetEvent(m_taskHandle); - m_loop.wait(&m_mutex); + m_loop->wait(&m_mutex); } } @@ -491,7 +493,7 @@ void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker) m_graph->Release(); m_graph = 0; - m_loop.wake(); + m_loop->wake(); } int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const @@ -665,7 +667,7 @@ void DirectShowPlayerService::stop() if (m_executingTask & (Play | Pause | Seek)) { m_pendingTasks |= Stop; - m_loop.wait(&m_mutex); + m_loop->wait(&m_mutex); } if (m_executedTasks & (Play | Pause)) { @@ -830,7 +832,7 @@ void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) ::SetEvent(m_taskHandle); - m_loop.wait(&m_mutex); + m_loop->wait(&m_mutex); } m_audioOutput->Release(); } @@ -876,7 +878,7 @@ void DirectShowPlayerService::doReleaseAudioOutput(QMutexLocker *locker) m_executedTasks &= ~SetAudioOutput; - m_loop.wake(); + m_loop->wake(); } void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) @@ -890,7 +892,7 @@ void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) ::SetEvent(m_taskHandle); - m_loop.wait(&m_mutex); + m_loop->wait(&m_mutex); } m_videoOutput->Release(); } @@ -934,7 +936,7 @@ void DirectShowPlayerService::doReleaseVideoOutput(QMutexLocker *locker) m_executedTasks &= ~SetVideoOutput; - m_loop.wake(); + m_loop->wake(); } void DirectShowPlayerService::customEvent(QEvent *event) @@ -1171,7 +1173,7 @@ void DirectShowPlayerService::run() } else if (m_pendingTasks & Stop) { m_pendingTasks ^= Stop; - m_loop.wake(); + m_loop->wake(); } else if (m_pendingTasks & Pause) { m_pendingTasks ^= Pause; m_executingTask = Pause; diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h index 9ea5d7d..576520e 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h @@ -181,6 +181,7 @@ private: DirectShowAudioEndpointControl *m_audioEndpointControl; QThread *m_taskThread; + DirectShowEventLoop *m_loop; int m_pendingTasks; int m_executingTask; int m_executedTasks; @@ -204,7 +205,6 @@ private: QUrl m_url; QMediaResourceList m_resources; QMutex m_mutex; - DirectShowEventLoop m_loop; friend class DirectShowPlayerServiceThread; }; -- cgit v0.12 From 3cd93dfb61eee61523af02cfc117c53ef9ee1336 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:50:12 +1000 Subject: Enable building the Direct Show plugin without the Window Media SDK. --- .../mediaplayer/directshowmetadatacontrol.cpp | 27 ++++++++++++++++++---- .../mediaplayer/directshowmetadatacontrol.h | 5 ++++ .../mediaplayer/directshowplayerservice.cpp | 8 +++++++ .../directshow/mediaplayer/mediaplayer.pri | 2 ++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp index 7335e3d..e95ddcd 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_WMSDK namespace { struct QWMMetaDataKeyLookup @@ -227,11 +228,14 @@ static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key) } return QVariant(); } +#endif DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent) : QMetaDataControl(parent) , m_content(0) +#ifndef QT_NO_WMSDK , m_headerInfo(0) +#endif { } @@ -246,13 +250,18 @@ bool DirectShowMetaDataControl::isWritable() const bool DirectShowMetaDataControl::isMetaDataAvailable() const { +#ifndef QT_NO_WMSDK return m_content || m_headerInfo; +#else + return m_content; +#endif } QVariant DirectShowMetaDataControl::metaData(QtMedia::MetaData key) const { QVariant value; +#ifndef QT_NO_WMSDK if (m_headerInfo) { static const int count = sizeof(qt_wmMetaDataKeys) / sizeof(QWMMetaDataKeyLookup); for (int i = 0; i < count; ++i) { @@ -262,6 +271,9 @@ QVariant DirectShowMetaDataControl::metaData(QtMedia::MetaData key) const } } } else if (m_content) { +#else + if (m_content) { +#endif BSTR string = 0; switch (key) { @@ -321,16 +333,19 @@ void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *s if (m_content) m_content->Release(); - if (m_headerInfo) - m_headerInfo->Release(); - if (!graph || graph->QueryInterface( IID_IAMMediaContent, reinterpret_cast(&m_content)) != S_OK) { m_content = 0; } - m_headerInfo = com_cast(source); +#ifdef QT_NO_WMSDK + Q_UNUSED(source); +#else + if (m_headerInfo) + m_headerInfo->Release(); + m_headerInfo = com_cast(source); +#endif // DirectShowMediaPlayerService holds a lock at this point so defer emitting signals to a later // time. QCoreApplication::postEvent(this, new QEvent(QEvent::Type(MetaDataChanged))); @@ -342,7 +357,11 @@ void DirectShowMetaDataControl::customEvent(QEvent *event) event->accept(); emit metaDataChanged(); +#ifndef QT_NO_WMSDK emit metaDataAvailableChanged(m_content || m_headerInfo); +#else + emit metaDataAvailableChanged(m_content); +#endif } else { QMetaDataControl::customEvent(event); } diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h index 9bb5fcc..eb3bbb7 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h @@ -46,7 +46,10 @@ #include #include + +#ifndef QT_NO_WMSDK #include +#endif #include @@ -88,7 +91,9 @@ private: }; IAMMediaContent *m_content; +#ifndef QT_NO_WMSDK IWMHeaderInfo *m_headerInfo; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index a3362db..fdbee81 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -222,6 +222,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) HRESULT hr = E_FAIL; +#ifndef QT_NO_WMSDK if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) { if (IFileSourceFilter *fileSource = com_new(CLSID_WMAsfReader)) { locker->unlock(); @@ -242,10 +243,13 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) } if (!SUCCEEDED(hr)) { +#endif locker->unlock(); hr = m_graph->AddSourceFilter(url.toString().utf16(), L"Source", &source); locker->relock(); +#ifndef QT_NO_WMSDK } +#endif if (SUCCEEDED(hr)) { m_executedTasks = SetSource; @@ -807,6 +811,7 @@ void DirectShowPlayerService::doSeek(QMutexLocker *locker) int DirectShowPlayerService::bufferStatus() const { +#ifndef QT_NO_WMSDK QMutexLocker locker(const_cast(&m_mutex)); if (IWMReaderAdvanced2 *reader = com_cast(m_source)) { @@ -819,6 +824,9 @@ int DirectShowPlayerService::bufferStatus() const } else { return 0; } +#else + return 0; +#endif } void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri index 49ee9e5..a7adb38 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri +++ b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri @@ -2,6 +2,8 @@ INCLUDEPATH += $$PWD DEFINES += QMEDIA_DIRECTSHOW_PLAYER +win32-g++: DEFINES += QT_NO_WMSDK + HEADERS += \ $$PWD/directshowaudioendpointcontrol.h \ $$PWD/directshoweventloop.h \ -- cgit v0.12 From 6c9daca8e51726472d24200654af0015f1e54eff Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 11:51:09 +1000 Subject: Enable building the Direct Show media service plugin. Some white space is required between the condtion and declaration statements. --- src/plugins/mediaservices/mediaservices.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro index e48156b..55e6aba 100644 --- a/src/plugins/mediaservices/mediaservices.pro +++ b/src/plugins/mediaservices/mediaservices.pro @@ -1,8 +1,8 @@ TEMPLATE = subdirs -win32:!wince:SUBDIRS += directshow +win32:!wince: SUBDIRS += directshow -mac:SUBDIRS += qt7 +mac: SUBDIRS += qt7 unix:!mac:!symbian { TMP_GST_LIBS = \ -- cgit v0.12 From 8a37893db7e340eb1dc3076496aef448c81fd4e7 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 12:00:06 +1000 Subject: Construct the meta-object directly instead of using QMetaObjectBuilder. Removes the dependency on QtDeclarative for this class. --- src/multimedia/qml/qmetadatacontrolmetaobject.cpp | 214 +++++++++++++++++----- src/multimedia/qml/qmetadatacontrolmetaobject_p.h | 10 +- 2 files changed, 175 insertions(+), 49 deletions(-) diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp index c2b5e78..6b0164b 100644 --- a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp +++ b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp @@ -40,12 +40,68 @@ ****************************************************************************/ #include - -#include /qmetadatacontrol.h> +#include QT_BEGIN_NAMESPACE +// copied from qmetaobject.cpp +// do not touch without touching the moc as well +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000, + Dynamic = 0x00800000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40 +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; + int flags; +}; + +static inline const QMetaObjectPrivate *priv(const uint* m_data) +{ return reinterpret_cast(m_data); } +// end of copied lines from qmetaobject.cpp + namespace { struct MetaDataKey @@ -76,7 +132,7 @@ namespace // Media { QtMedia::Size, "size" }, { QtMedia::MediaType, "mediaType" }, - { QtMedia::Duration, "duration" }, +// { QtMedia::Duration, "duration" }, // Audio { QtMedia::AudioBitRate, "audioBitRate" }, @@ -146,37 +202,132 @@ namespace { QtMedia::Sharpness, "sharpness" }, { QtMedia::DeviceSettingDescription, "deviceSettingDescription" } }; + + class QMetaDataControlObject : public QObject + { + public: + inline QObjectData *data() { return d_ptr.data(); } + }; } QMetaDataControlMetaObject::QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object) : m_control(control) , m_object(object) - , m_mem(0) + , m_data(0) + , m_string(0) , m_propertyOffset(0) , m_signalOffset(0) { - m_builder.setSuperClass(m_object->metaObject()); - m_builder.setClassName(m_object->metaObject()->className()); - m_builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + const QMetaObject *superClass = m_object->metaObject(); + + const int propertyCount = sizeof(qt_metaDataKeys) / sizeof(MetaDataKey); + const int dataSize = sizeof(uint) + * (13 // QMetaObjectPrivate members. + + 5 // 5 members per signal. + + 4 * propertyCount // 3 members per property + 1 notify signal per property. + + 1); // Terminating value. + + m_data = reinterpret_cast(qMalloc(dataSize)); + + QMetaObjectPrivate *pMeta = reinterpret_cast(m_data); + + pMeta->revision = 3; + pMeta->className = 0; + pMeta->classInfoCount = 0; + pMeta->classInfoData = 0; + pMeta->methodCount = 1; + pMeta->methodData = 13; + pMeta->propertyCount = propertyCount; + pMeta->propertyData = 18; + pMeta->enumeratorCount = 0; + pMeta->enumeratorData = 0; + pMeta->constructorCount = 0; + pMeta->constructorData = 0; + pMeta->flags = 0x01; // Dynamic meta object flag. + + const int classNameSize = qstrlen(superClass->className()) + 1; + + int stringIndex = classNameSize + 1; + + // __metaDataChanged() signal. + static const char *changeSignal = "__metaDataChanged()"; + const int changeSignalSize = qstrlen(changeSignal) + 1; + + m_data[13] = stringIndex; // Signature. + m_data[14] = classNameSize; // Parameters. + m_data[15] = classNameSize; // Type. + m_data[16] = classNameSize; // Tag. + m_data[17] = MethodSignal | AccessProtected; // Flags. + + stringIndex += changeSignalSize; + + const char *qvariantName = "QVariant"; + const int qvariantSize = qstrlen(qvariantName) + 1; + const int qvariantIndex = stringIndex; + + stringIndex += qvariantSize; + + // Properties. + for (int i = 0; i < propertyCount; ++i) { + m_data[18 + 3 * i] = stringIndex; // Name. + m_data[19 + 3 * i] = qvariantIndex; // Type. + m_data[20 + 3 * i] + = Readable | Writable | Notify | Dynamic | (0xffffffff << 24); // Flags. + m_data[18 + propertyCount * 3 + i] = 0; // Notify signal. + + stringIndex += qstrlen(qt_metaDataKeys[i].name) + 1; + } + + // Terminating value. + m_data[18 + propertyCount * 4] = 0; + + // Build string. + m_string = reinterpret_cast(qMalloc(stringIndex + 1)); + + // Class name. + qMemCopy(m_string, superClass->className(), classNameSize); + + stringIndex = classNameSize; + + // Null m_string. + m_string[stringIndex] = '\0'; + stringIndex += 1; + + // __metaDataChanged() signal. + qMemCopy(m_string + stringIndex, changeSignal, changeSignalSize); + stringIndex += changeSignalSize; - QObjectPrivate *op = QObjectPrivate::get(m_object); - if (op->metaObject) - m_builder.setSuperClass(op->metaObject); + qMemCopy(m_string + stringIndex, qvariantName, qvariantSize); + stringIndex += qvariantSize; - m_mem = m_builder.toMetaObject(); - *static_cast(this) = *m_mem; + // Properties. + for (int i = 0; i < propertyCount; ++i) { + const int propertyNameSize = qstrlen(qt_metaDataKeys[i].name) + 1; + + qMemCopy(m_string + stringIndex, qt_metaDataKeys[i].name, propertyNameSize); + stringIndex += propertyNameSize; + } + + // Terminating character. + m_string[stringIndex] = '\0'; + + d.superdata = superClass; + d.stringdata = m_string; + d.data = m_data; + d.extradata = 0; + + static_cast(m_object)->data()->metaObject = this; - op->metaObject = this; m_propertyOffset = propertyOffset(); m_signalOffset = methodOffset(); } QMetaDataControlMetaObject::~QMetaDataControlMetaObject() { - qFree(m_mem); + static_cast(m_object)->data()->metaObject = 0; - QObjectPrivate *op = QObjectPrivate::get(m_object); - op->metaObject = 0; + qFree(m_data); + qFree(m_string); } int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a) @@ -184,15 +335,15 @@ int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a) if (c == QMetaObject::ReadProperty && id >= m_propertyOffset) { int propId = id - m_propertyOffset; - *reinterpret_cast(a[0]) = m_control->metaData(m_keys.at(propId)); + *reinterpret_cast(a[0]) = m_control->metaData(qt_metaDataKeys[propId].key); return -1; } else if (c == QMetaObject::WriteProperty && id >= m_propertyOffset) { int propId = id - m_propertyOffset; - m_control->setMetaData(m_keys.at(propId), *reinterpret_cast(a[0])); + m_control->setMetaData(qt_metaDataKeys[propId].key, *reinterpret_cast(a[0])); - activate(m_object, m_signalOffset + propId, 0); + activate(m_object, m_signalOffset, 0); return -1; } else { @@ -200,35 +351,14 @@ int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a) } } -int QMetaDataControlMetaObject::createProperty(const char *name, const char *) +int QMetaDataControlMetaObject::createProperty(const char *, const char *) { - const int count = sizeof(qt_metaDataKeys) / sizeof(MetaDataKey); - - for (int i = 0; i < count; ++i) { - if (qstrcmp(name, qt_metaDataKeys[i].name) == 0) { - int id = m_keys.count(); - m_keys.append(qt_metaDataKeys[i].key); - - m_builder.addSignal("__" + QByteArray::number(id) + "()"); - - QMetaPropertyBuilder build = m_builder.addProperty(name, "QVariant", id); - build.setDynamic(true); - - qFree(m_mem); - m_mem = m_builder.toMetaObject(); - *static_cast(this) = *m_mem; - - return m_propertyOffset + id; - } - } - return -1; } void QMetaDataControlMetaObject::metaDataChanged() { - for (int i = 0; i < m_keys.count(); ++i) - activate(m_object, m_signalOffset + i, 0); + activate(m_object, m_signalOffset, 0); } QT_END_NAMESPACE diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject_p.h b/src/multimedia/qml/qmetadatacontrolmetaobject_p.h index b7f88fe..c0fd4e8 100644 --- a/src/multimedia/qml/qmetadatacontrolmetaobject_p.h +++ b/src/multimedia/qml/qmetadatacontrolmetaobject_p.h @@ -42,12 +42,10 @@ #ifndef QMETADATACONTROLMETAOBJECT_P_H #define QMETADATACONTROLMETAOJBECT_P_H +#include #include -#include #include -#include - QT_BEGIN_HEADER @@ -69,13 +67,11 @@ public: private: QMetaDataControl *m_control; QObject *m_object; - QMetaObject *m_mem; + char *m_string; + uint *m_data; int m_propertyOffset; int m_signalOffset; - - QVector m_keys; - QMetaObjectBuilder m_builder; }; QT_END_NAMESPACE -- cgit v0.12 From 5588657ba3b2a060e60bf8d83fd5ba60bbdc9c64 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 3 Feb 2010 12:57:47 +1000 Subject: Add tests fro QGraphicsVideoItem. --- tests/auto/auto.pro | 1 + .../auto/qgraphicsvideoitem/qgraphicsvideoitem.pro | 5 + .../qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp | 670 +++++++++++++++++++++ 3 files changed, 676 insertions(+) create mode 100644 tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro create mode 100644 tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index aacb1dc..809b523 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -171,6 +171,7 @@ SUBDIRS += \ qgraphicsscene \ qgraphicssceneindex \ qgraphicstransform \ + qgraphicsvideoitem \ qgraphicsview \ qgraphicswidget \ qgridlayout \ diff --git a/tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro b/tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro new file mode 100644 index 0000000..da00baf --- /dev/null +++ b/tests/auto/qgraphicsvideoitem/qgraphicsvideoitem.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qgraphicsvideoitem.cpp + +QT += multimedia +requires(contains(QT_CONFIG, multimedia)) diff --git a/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp new file mode 100644 index 0000000..19433e4 --- /dev/null +++ b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp @@ -0,0 +1,670 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class tst_QGraphicsVideoItem : public QObject +{ + Q_OBJECT +public slots: + void initTestCase(); + +private slots: + void nullObject(); + void nullService(); + void nullOutputControl(); + void noOutputs(); + void serviceDestroyed(); + void mediaObjectDestroyed(); + void setMediaObject(); + + void show(); + + void aspectRatioMode(); + void offset(); + void size(); + void nativeSize_data(); + void nativeSize(); + + void boundingRect_data(); + void boundingRect(); + + void paint(); +}; + +Q_DECLARE_METATYPE(const uchar *) +Q_DECLARE_METATYPE(Qt::AspectRatioMode) + +class QtTestOutputControl : public QVideoOutputControl +{ +public: + QtTestOutputControl() : m_output(NoOutput) {} + + QList availableOutputs() const { return m_outputs; } + void setAvailableOutputs(const QList outputs) { m_outputs = outputs; } + + Output output() const { return m_output; } + virtual void setOutput(Output output) { m_output = output; } + +private: + Output m_output; + QList m_outputs; +}; + +class QtTestRendererControl : public QVideoRendererControl +{ +public: + QtTestRendererControl() + : m_surface(0) + { + } + + QAbstractVideoSurface *surface() const { return m_surface; } + void setSurface(QAbstractVideoSurface *surface) { m_surface = surface; } + +private: + QAbstractVideoSurface *m_surface; +}; + +class QtTestVideoService : public QMediaService +{ + Q_OBJECT +public: + QtTestVideoService( + QtTestOutputControl *output, + QtTestRendererControl *renderer) + : QMediaService(0) + , outputControl(output) + , rendererControl(renderer) + { + } + + ~QtTestVideoService() + { + delete outputControl; + delete rendererControl; + } + + QMediaControl *control(const char *name) const + { + if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return outputControl; + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return rendererControl; + else + return 0; + } + + QtTestOutputControl *outputControl; + QtTestRendererControl *rendererControl; +}; + +class QtTestVideoObject : public QMediaObject +{ + Q_OBJECT +public: + QtTestVideoObject(QtTestRendererControl *renderer): + QMediaObject(0, new QtTestVideoService(new QtTestOutputControl, renderer)) + { + testService = qobject_cast(service()); + QList outputs; + + if (renderer) + outputs.append(QVideoOutputControl::RendererOutput); + + testService->outputControl->setAvailableOutputs(outputs); + } + + QtTestVideoObject(QtTestVideoService *service): + QMediaObject(0, service), + testService(service) + { + } + + ~QtTestVideoObject() + { + delete testService; + } + + QtTestVideoService *testService; +}; + +class QtTestGraphicsVideoItem : public QGraphicsVideoItem +{ +public: + QtTestGraphicsVideoItem(QGraphicsItem *parent = 0) + : QGraphicsVideoItem(parent) + , m_paintCount(0) + { + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + ++m_paintCount; + + QTestEventLoop::instance().exitLoop(); + + QGraphicsVideoItem::paint(painter, option, widget); + } + + bool waitForPaint(int secs) + { + const int paintCount = m_paintCount; + + QTestEventLoop::instance().enterLoop(secs); + + return m_paintCount != paintCount; + } + + int paintCount() const + { + return m_paintCount; + } + +private: + int m_paintCount; +}; + +void tst_QGraphicsVideoItem::initTestCase() +{ + qRegisterMetaType(); +} + +void tst_QGraphicsVideoItem::nullObject() +{ + QGraphicsVideoItem item(0); + + QVERIFY(item.boundingRect().isEmpty()); +} + +void tst_QGraphicsVideoItem::nullService() +{ + QtTestVideoService *service = 0; + + QtTestVideoObject object(service); + + QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem; + item->setMediaObject(&object); + + QVERIFY(item->boundingRect().isEmpty()); + + item->hide(); + item->show(); + + QGraphicsScene graphicsScene; + graphicsScene.addItem(item); + QGraphicsView graphicsView(&graphicsScene); + graphicsView.show(); +} + +void tst_QGraphicsVideoItem::nullOutputControl() +{ + QtTestVideoObject object(new QtTestVideoService(0, 0)); + + QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem; + item->setMediaObject(&object); + + QVERIFY(item->boundingRect().isEmpty()); + + item->hide(); + item->show(); + + QGraphicsScene graphicsScene; + graphicsScene.addItem(item); + QGraphicsView graphicsView(&graphicsScene); + graphicsView.show(); +} + +void tst_QGraphicsVideoItem::noOutputs() +{ + QtTestRendererControl *control = 0; + QtTestVideoObject object(control); + + QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem; + item->setMediaObject(&object); + + QVERIFY(item->boundingRect().isEmpty()); + + item->hide(); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + item->show(); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + QGraphicsScene graphicsScene; + graphicsScene.addItem(item); + QGraphicsView graphicsView(&graphicsScene); + graphicsView.show(); +} + +void tst_QGraphicsVideoItem::serviceDestroyed() +{ + QtTestVideoObject object(new QtTestRendererControl); + + QGraphicsVideoItem item; + item.setMediaObject(&object); + + QtTestVideoService *service = object.testService; + object.testService = 0; + + delete service; + + QCOMPARE(item.mediaObject(), static_cast(&object)); + QVERIFY(item.boundingRect().isEmpty()); +} + +void tst_QGraphicsVideoItem::mediaObjectDestroyed() +{ + QtTestVideoObject *object = new QtTestVideoObject(new QtTestRendererControl); + + QGraphicsVideoItem item; + item.setMediaObject(object); + + delete object; + object = 0; + + QCOMPARE(item.mediaObject(), static_cast(object)); + QVERIFY(item.boundingRect().isEmpty()); +} + +void tst_QGraphicsVideoItem::setMediaObject() +{ + QMediaObject *nullObject = 0; + QtTestVideoObject object(new QtTestRendererControl); + + QGraphicsVideoItem item; + + QCOMPARE(item.mediaObject(), nullObject); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + item.setMediaObject(&object); + QCOMPARE(item.mediaObject(), static_cast(&object)); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(object.testService->rendererControl->surface() != 0); + + item.setMediaObject(0); + QCOMPARE(item.mediaObject(), nullObject); + + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + item.setVisible(false); + + item.setMediaObject(&object); + QCOMPARE(item.mediaObject(), static_cast(&object)); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QVERIFY(object.testService->rendererControl->surface() != 0); +} + +void tst_QGraphicsVideoItem::show() +{ + QtTestVideoObject object(new QtTestRendererControl); + QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem; + item->setMediaObject(&object); + + // Graphics items are visible by default + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(object.testService->rendererControl->surface() != 0); + + item->hide(); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + + item->show(); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); + QVERIFY(object.testService->rendererControl->surface() != 0); + + QVERIFY(item->boundingRect().isEmpty()); + + QVideoSurfaceFormat format(QSize(320,240),QVideoFrame::Format_RGB32); + QVERIFY(object.testService->rendererControl->surface()->start(format)); + + QVERIFY(!item->boundingRect().isEmpty()); + + QGraphicsScene graphicsScene; + graphicsScene.addItem(item); + QGraphicsView graphicsView(&graphicsScene); + graphicsView.show(); + + QVERIFY(item->paintCount() || item->waitForPaint(1)); +} + +void tst_QGraphicsVideoItem::aspectRatioMode() +{ + QGraphicsVideoItem item; + + QCOMPARE(item.aspectRatioMode(), Qt::KeepAspectRatio); + + item.setAspectRatioMode(Qt::IgnoreAspectRatio); + QCOMPARE(item.aspectRatioMode(), Qt::IgnoreAspectRatio); + + item.setAspectRatioMode(Qt::KeepAspectRatioByExpanding); + QCOMPARE(item.aspectRatioMode(), Qt::KeepAspectRatioByExpanding); + + item.setAspectRatioMode(Qt::KeepAspectRatio); + QCOMPARE(item.aspectRatioMode(), Qt::KeepAspectRatio); +} + +void tst_QGraphicsVideoItem::offset() +{ + QGraphicsVideoItem item; + + QCOMPARE(item.offset(), QPointF(0, 0)); + + item.setOffset(QPointF(-32.4, 43.0)); + QCOMPARE(item.offset(), QPointF(-32.4, 43.0)); + + item.setOffset(QPointF(1, 1)); + QCOMPARE(item.offset(), QPointF(1, 1)); + + item.setOffset(QPointF(12, -30.4)); + QCOMPARE(item.offset(), QPointF(12, -30.4)); + + item.setOffset(QPointF(-90.4, -75)); + QCOMPARE(item.offset(), QPointF(-90.4, -75)); +} + +void tst_QGraphicsVideoItem::size() +{ + QGraphicsVideoItem item; + + QCOMPARE(item.size(), QSizeF(320, 240)); + + item.setSize(QSizeF(542.5, 436.3)); + QCOMPARE(item.size(), QSizeF(542.5, 436.3)); + + item.setSize(QSizeF(-43, 12)); + QCOMPARE(item.size(), QSizeF(0, 0)); + + item.setSize(QSizeF(54, -9)); + QCOMPARE(item.size(), QSizeF(0, 0)); + + item.setSize(QSizeF(-90, -65)); + QCOMPARE(item.size(), QSizeF(0, 0)); + + item.setSize(QSizeF(1000, 1000)); + QCOMPARE(item.size(), QSizeF(1000, 1000)); +} + +void tst_QGraphicsVideoItem::nativeSize_data() +{ + QTest::addColumn("frameSize"); + QTest::addColumn("viewport"); + QTest::addColumn("pixelAspectRatio"); + QTest::addColumn("nativeSize"); + + QTest::newRow("640x480") + << QSize(640, 480) + << QRect(0, 0, 640, 480) + << QSize(1, 1) + << QSizeF(640, 480); + + QTest::newRow("800x600, (80,60, 640x480) viewport") + << QSize(800, 600) + << QRect(80, 60, 640, 480) + << QSize(1, 1) + << QSizeF(640, 480); + + QTest::newRow("800x600, (80,60, 640x480) viewport, 4:3") + << QSize(800, 600) + << QRect(80, 60, 640, 480) + << QSize(4, 3) + << QSizeF(853, 480); +} + +void tst_QGraphicsVideoItem::nativeSize() +{ + QFETCH(QSize, frameSize); + QFETCH(QRect, viewport); + QFETCH(QSize, pixelAspectRatio); + QFETCH(QSizeF, nativeSize); + + QtTestVideoObject object(new QtTestRendererControl); + QGraphicsVideoItem item; + item.setMediaObject(&object); + + QCOMPARE(item.nativeSize(), QSizeF()); + + QSignalSpy spy(&item, SIGNAL(nativeSizeChanged(QSizeF))); + + QVideoSurfaceFormat format(frameSize, QVideoFrame::Format_ARGB32); + format.setViewport(viewport); + format.setPixelAspectRatio(pixelAspectRatio); + + QVERIFY(object.testService->rendererControl->surface()->start(format)); + + QCOMPARE(item.nativeSize(), nativeSize); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.last().first().toSizeF(), nativeSize); + + object.testService->rendererControl->surface()->stop(); + + QCOMPARE(item.nativeSize(), QSizeF(0, 0)); + QCOMPARE(spy.count(), 2); + QCOMPARE(spy.last().first().toSizeF(), QSizeF(0, 0)); +} + +void tst_QGraphicsVideoItem::boundingRect_data() +{ + QTest::addColumn("frameSize"); + QTest::addColumn("offset"); + QTest::addColumn("size"); + QTest::addColumn("aspectRatioMode"); + QTest::addColumn("expectedRect"); + + + QTest::newRow("640x480: (0,0 640x480), Keep") + << QSize(640, 480) + << QPointF(0, 0) + << QSizeF(640, 480) + << Qt::KeepAspectRatio + << QRectF(0, 0, 640, 480); + + QTest::newRow("800x600, (0,0, 640x480), Keep") + << QSize(800, 600) + << QPointF(0, 0) + << QSizeF(640, 480) + << Qt::KeepAspectRatio + << QRectF(0, 0, 640, 480); + + QTest::newRow("800x600, (0,0, 640x480), KeepByExpanding") + << QSize(800, 600) + << QPointF(0, 0) + << QSizeF(640, 480) + << Qt::KeepAspectRatioByExpanding + << QRectF(0, 0, 640, 480); + + QTest::newRow("800x600, (0,0, 640x480), Ignore") + << QSize(800, 600) + << QPointF(0, 0) + << QSizeF(640, 480) + << Qt::IgnoreAspectRatio + << QRectF(0, 0, 640, 480); + + QTest::newRow("800x600, (100,100, 640x480), Keep") + << QSize(800, 600) + << QPointF(100, 100) + << QSizeF(640, 480) + << Qt::KeepAspectRatio + << QRectF(100, 100, 640, 480); + + QTest::newRow("800x600, (100,-100, 640x480), KeepByExpanding") + << QSize(800, 600) + << QPointF(100, -100) + << QSizeF(640, 480) + << Qt::KeepAspectRatioByExpanding + << QRectF(100, -100, 640, 480); + + QTest::newRow("800x600, (-100,-100, 640x480), Ignore") + << QSize(800, 600) + << QPointF(-100, -100) + << QSizeF(640, 480) + << Qt::IgnoreAspectRatio + << QRectF(-100, -100, 640, 480); + + QTest::newRow("800x600, (0,0, 1920x1024), Keep") + << QSize(800, 600) + << QPointF(0, 0) + << QSizeF(1920, 1024) + << Qt::KeepAspectRatio + << QRectF(832.0 / 3, 0, 4096.0 / 3, 1024); + + QTest::newRow("800x600, (0,0, 1920x1024), KeepByExpanding") + << QSize(800, 600) + << QPointF(0, 0) + << QSizeF(1920, 1024) + << Qt::KeepAspectRatioByExpanding + << QRectF(0, 0, 1920, 1024); + + QTest::newRow("800x600, (0,0, 1920x1024), Ignore") + << QSize(800, 600) + << QPointF(0, 0) + << QSizeF(1920, 1024) + << Qt::IgnoreAspectRatio + << QRectF(0, 0, 1920, 1024); + + QTest::newRow("800x600, (100,100, 1920x1024), Keep") + << QSize(800, 600) + << QPointF(100, 100) + << QSizeF(1920, 1024) + << Qt::KeepAspectRatio + << QRectF(100 + 832.0 / 3, 100, 4096.0 / 3, 1024); + + QTest::newRow("800x600, (100,-100, 1920x1024), KeepByExpanding") + << QSize(800, 600) + << QPointF(100, -100) + << QSizeF(1920, 1024) + << Qt::KeepAspectRatioByExpanding + << QRectF(100, -100, 1920, 1024); + + QTest::newRow("800x600, (-100,-100, 1920x1024), Ignore") + << QSize(800, 600) + << QPointF(-100, -100) + << QSizeF(1920, 1024) + << Qt::IgnoreAspectRatio + << QRectF(-100, -100, 1920, 1024); +} + +void tst_QGraphicsVideoItem::boundingRect() +{ + QFETCH(QSize, frameSize); + QFETCH(QPointF, offset); + QFETCH(QSizeF, size); + QFETCH(Qt::AspectRatioMode, aspectRatioMode); + QFETCH(QRectF, expectedRect); + + QtTestVideoObject object(new QtTestRendererControl); + QGraphicsVideoItem item; + item.setMediaObject(&object); + + item.setOffset(offset); + item.setSize(size); + item.setAspectRatioMode(aspectRatioMode); + + QVideoSurfaceFormat format(frameSize, QVideoFrame::Format_ARGB32); + + QVERIFY(object.testService->rendererControl->surface()->start(format)); + + QCOMPARE(item.boundingRect(), expectedRect); +} + +static const uchar rgb32ImageData[] = +{ + 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00 +}; + +void tst_QGraphicsVideoItem::paint() +{ + QtTestVideoObject object(new QtTestRendererControl); + QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem; + item->setMediaObject(&object); + + QGraphicsScene graphicsScene; + graphicsScene.addItem(item); + QGraphicsView graphicsView(&graphicsScene); + graphicsView.show(); + + QPainterVideoSurface *surface = qobject_cast( + object.testService->rendererControl->surface()); + + QVideoSurfaceFormat format(QSize(2, 2), QVideoFrame::Format_RGB32); + + QVERIFY(surface->start(format)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QVERIFY(item->waitForPaint(1)); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QVideoFrame frame(sizeof(rgb32ImageData), QSize(2, 2), 8, QVideoFrame::Format_RGB32); + + frame.map(QAbstractVideoBuffer::WriteOnly); + memcpy(frame.bits(), rgb32ImageData, frame.mappedBytes()); + frame.unmap(); + + QVERIFY(surface->present(frame)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), false); + + QVERIFY(item->waitForPaint(1)); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); +} + + +QTEST_MAIN(tst_QGraphicsVideoItem) + +#include "tst_qgraphicsvideoitem.moc" -- cgit v0.12 From 1d48062f758ae82129583b0e95b18d06faf57547 Mon Sep 17 00:00:00 2001 From: Nicholas Young Date: Thu, 4 Feb 2010 10:45:43 +1000 Subject: Added QNetworkRequest constructor to QMediaResource. --- src/multimedia/base/base.pri | 1 + src/multimedia/base/qmediaresource.cpp | 24 +++++++++++-- src/multimedia/base/qmediaresource.h | 6 +++- tests/auto/qmediaresource/qmediaresource.pro | 2 +- tests/auto/qmediaresource/tst_qmediaresource.cpp | 45 ++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/multimedia/base/base.pri b/src/multimedia/base/base.pri index fb2784d..5aebbf0 100644 --- a/src/multimedia/base/base.pri +++ b/src/multimedia/base/base.pri @@ -1,4 +1,5 @@ +QT += network contains(QT_CONFIG, opengl):QT += opengl HEADERS += \ diff --git a/src/multimedia/base/qmediaresource.cpp b/src/multimedia/base/qmediaresource.cpp index ab18ce7..515e432 100644 --- a/src/multimedia/base/qmediaresource.cpp +++ b/src/multimedia/base/qmediaresource.cpp @@ -93,7 +93,17 @@ QMediaResource::QMediaResource() */ QMediaResource::QMediaResource(const QUrl &url, const QString &mimeType) { - values.insert(Url, qVariantFromValue(url)); + values.insert(Url, url); + values.insert(MimeType, mimeType); +} + +/*! + Constructs a media resource with the given \a mimeType from a network \a request. +*/ +QMediaResource::QMediaResource(const QNetworkRequest &request, const QString &mimeType) +{ + values.insert(Request, QVariant::fromValue(request)); + values.insert(Url, request.url()); values.insert(MimeType, mimeType); } @@ -162,6 +172,17 @@ QUrl QMediaResource::url() const } /*! + Returns the network request associated with this media resource. +*/ +QNetworkRequest QMediaResource::request() const +{ + if(values.contains(Request)) + return qvariant_cast(values.value(Request)); + + return QNetworkRequest(url()); +} + +/*! Returns the MIME type of a media resource. This may be null if the MIME type is unknown. @@ -373,6 +394,5 @@ void QMediaResource::setResolution(int width, int height) else values.remove(Resolution); } - QT_END_NAMESPACE diff --git a/src/multimedia/base/qmediaresource.h b/src/multimedia/base/qmediaresource.h index 33b5a79..516120a 100644 --- a/src/multimedia/base/qmediaresource.h +++ b/src/multimedia/base/qmediaresource.h @@ -44,6 +44,7 @@ #include #include +#include QT_BEGIN_HEADER @@ -58,6 +59,7 @@ class Q_MULTIMEDIA_EXPORT QMediaResource public: QMediaResource(); QMediaResource(const QUrl &url, const QString &mimeType = QString()); + QMediaResource(const QNetworkRequest &request, const QString &mimeType = QString()); QMediaResource(const QMediaResource &other); QMediaResource &operator =(const QMediaResource &other); ~QMediaResource(); @@ -68,6 +70,7 @@ public: bool operator !=(const QMediaResource &other) const; QUrl url() const; + QNetworkRequest request() const; QString mimeType() const; QString language() const; @@ -103,6 +106,7 @@ private: enum Property { Url, + Request, MimeType, Language, AudioCodec, @@ -112,7 +116,7 @@ private: VideoBitRate, SampleRate, ChannelCount, - Resolution, + Resolution }; QMap values; }; diff --git a/tests/auto/qmediaresource/qmediaresource.pro b/tests/auto/qmediaresource/qmediaresource.pro index 2741608..c8e3d9c 100644 --- a/tests/auto/qmediaresource/qmediaresource.pro +++ b/tests/auto/qmediaresource/qmediaresource.pro @@ -2,5 +2,5 @@ load(qttest_p4) SOURCES = tst_qmediaresource.cpp -QT = core multimedia +QT = core multimedia network diff --git a/tests/auto/qmediaresource/tst_qmediaresource.cpp b/tests/auto/qmediaresource/tst_qmediaresource.cpp index 55ddcab..127144d 100644 --- a/tests/auto/qmediaresource/tst_qmediaresource.cpp +++ b/tests/auto/qmediaresource/tst_qmediaresource.cpp @@ -63,6 +63,7 @@ void tst_QMediaResource::constructNull() QCOMPARE(resource.isNull(), true); QCOMPARE(resource.url(), QUrl()); + QCOMPARE(resource.request(), QNetworkRequest()); QCOMPARE(resource.mimeType(), QString()); QCOMPARE(resource.language(), QString()); QCOMPARE(resource.audioCodec(), QString()); @@ -78,6 +79,7 @@ void tst_QMediaResource::constructNull() void tst_QMediaResource::construct_data() { QTest::addColumn("url"); + QTest::addColumn("request"); QTest::addColumn("mimeType"); QTest::addColumn("language"); QTest::addColumn("audioCodec"); @@ -91,6 +93,7 @@ void tst_QMediaResource::construct_data() QTest::newRow("audio content") << QUrl(QString::fromLatin1("http:://test.com/test.mp3")) + << QNetworkRequest(QUrl(QString::fromLatin1("http:://test.com/test.mp3"))) << QString::fromLatin1("audio/mpeg") << QString::fromLatin1("eng") << QString::fromLatin1("mp3") @@ -103,6 +106,7 @@ void tst_QMediaResource::construct_data() << QSize(); QTest::newRow("image content") << QUrl(QString::fromLatin1("http:://test.com/test.jpg")) + << QNetworkRequest(QUrl(QString::fromLatin1("http:://test.com/test.jpg"))) << QString::fromLatin1("image/jpeg") << QString() << QString() @@ -115,6 +119,7 @@ void tst_QMediaResource::construct_data() << QSize(640, 480); QTest::newRow("video content") << QUrl(QString::fromLatin1("http:://test.com/test.mp4")) + << QNetworkRequest(QUrl(QString::fromLatin1("http:://test.com/test.mp4"))) << QString::fromLatin1("video/mp4") << QString() << QString::fromLatin1("aac") @@ -127,6 +132,7 @@ void tst_QMediaResource::construct_data() << QSize(720, 576); QTest::newRow("thumbnail") << QUrl(QString::fromLatin1("file::///thumbs/test.png")) + << QNetworkRequest(QUrl(QString::fromLatin1("file::///thumbs/test.png"))) << QString::fromLatin1("image/png") << QString() << QString() @@ -142,6 +148,7 @@ void tst_QMediaResource::construct_data() void tst_QMediaResource::construct() { QFETCH(QUrl, url); + QFETCH(QNetworkRequest, request); QFETCH(QString, mimeType); QFETCH(QString, language); QFETCH(QString, audioCodec); @@ -174,6 +181,44 @@ void tst_QMediaResource::construct() QCOMPARE(resource.isNull(), false); QCOMPARE(resource.url(), url); + QCOMPARE(resource.request(), request); + QCOMPARE(resource.mimeType(), mimeType); + QCOMPARE(resource.language(), QString()); + QCOMPARE(resource.audioCodec(), QString()); + QCOMPARE(resource.videoCodec(), QString()); + QCOMPARE(resource.dataSize(), qint64(0)); + QCOMPARE(resource.audioBitRate(), 0); + QCOMPARE(resource.sampleRate(), 0); + QCOMPARE(resource.channelCount(), 0); + QCOMPARE(resource.videoBitRate(), 0); + QCOMPARE(resource.resolution(), QSize()); + + resource.setLanguage(language); + resource.setAudioCodec(audioCodec); + resource.setVideoCodec(videoCodec); + resource.setDataSize(dataSize); + resource.setAudioBitRate(audioBitRate); + resource.setSampleRate(sampleRate); + resource.setChannelCount(channelCount); + resource.setVideoBitRate(videoBitRate); + resource.setResolution(resolution); + + QCOMPARE(resource.language(), language); + QCOMPARE(resource.audioCodec(), audioCodec); + QCOMPARE(resource.videoCodec(), videoCodec); + QCOMPARE(resource.dataSize(), dataSize); + QCOMPARE(resource.audioBitRate(), audioBitRate); + QCOMPARE(resource.sampleRate(), sampleRate); + QCOMPARE(resource.channelCount(), channelCount); + QCOMPARE(resource.videoBitRate(), videoBitRate); + QCOMPARE(resource.resolution(), resolution); + } + { + QMediaResource resource(request, mimeType); + + QCOMPARE(resource.isNull(), false); + QCOMPARE(resource.url(), url); + QCOMPARE(resource.request(), request); QCOMPARE(resource.mimeType(), mimeType); QCOMPARE(resource.language(), QString()); QCOMPARE(resource.audioCodec(), QString()); -- cgit v0.12 From 623fa99d781a5cc2ddbd330f949764333fcd7ab1 Mon Sep 17 00:00:00 2001 From: Nicholas Young Date: Thu, 4 Feb 2010 11:18:31 +1000 Subject: Revert "Added QtMultimedia audio/video to Webkit." This reverts commit 7574328b1bdfb5d7d34aa2428cb5dc623f19f4aa. --- src/3rdparty/webkit/WebCore/WebCore.pro | 28 +- .../WebCore/platform/graphics/MediaPlayer.cpp | 2 +- .../platform/graphics/qt/MediaPlayerPrivateQt.cpp | 583 --------------------- .../platform/graphics/qt/MediaPlayerPrivateQt.h | 110 ---- 4 files changed, 18 insertions(+), 705 deletions(-) delete mode 100644 src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp delete mode 100644 src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index 337a6b5..04aba62 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -166,8 +166,8 @@ contains(DEFINES, ENABLE_SINGLE_THREADED=1) { # HTML5 media support !contains(DEFINES, ENABLE_VIDEO=.) { - contains(QT_CONFIG, multimedia): DEFINES += ENABLE_VIDEO=1 - else: DEFINES += ENABLE_VIDEO=0 + contains(QT_CONFIG, phonon):DEFINES += ENABLE_VIDEO=1 + else:DEFINES += ENABLE_VIDEO=0 } # HTML5 datalist support @@ -2732,17 +2732,23 @@ contains(DEFINES, ENABLE_VIDEO=1) { rendering/RenderMedia.cpp \ bindings/js/JSAudioConstructor.cpp - INCLUDEPATH += \ - $$PWD/../../../multimedia/base - - HEADERS += \ - platform/graphics/qt/MediaPlayerPrivateQt.h + HEADERS += \ + platform/graphics/qt/MediaPlayerPrivatePhonon.h - SOURCES += \ - platform/graphics/qt/MediaPlayerPrivateQt.cpp + SOURCES += \ + platform/graphics/qt/MediaPlayerPrivatePhonon.cpp + + # Add phonon manually to prevent it from coming first in + # the include paths, as Phonon's path.h conflicts with + # WebCore's Path.h on case-insensitive filesystems. + qtAddLibrary(phonon) + INCLUDEPATH -= $$QMAKE_INCDIR_QT/phonon + INCLUDEPATH += $$QMAKE_INCDIR_QT/phonon + mac { + INCLUDEPATH -= $$QMAKE_LIBDIR_QT/phonon.framework/Headers + INCLUDEPATH += $$QMAKE_LIBDIR_QT/phonon.framework/Headers + } - QT += multimedia - contains(QT_CONFIG, opengl): QT += opengl } contains(DEFINES, ENABLE_XPATH=1) { diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp index 07232fd..3b32b65 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/MediaPlayer.cpp @@ -46,7 +46,7 @@ #elif PLATFORM(GTK) #include "MediaPlayerPrivateGStreamer.h" #elif PLATFORM(QT) -#include "MediaPlayerPrivateQt.h" +#include "MediaPlayerPrivatePhonon.h" #elif PLATFORM(CHROMIUM) #include "MediaPlayerPrivateChromium.h" #endif diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp deleted file mode 100644 index 967e125..0000000 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ /dev/null @@ -1,583 +0,0 @@ -/* - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2009 Apple Inc. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "MediaPlayerPrivateQt.h" - -#include - -// WebCore Includes -#include "CString.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "NotImplemented.h" -#include "TimeRanges.h" -#include "Widget.h" - -// WebKit Includes -#include - -// Qt Includes -#include -#include -#include -#include -#include -#include - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) -#include -#endif - -// Qt Multimedia Includes -#include -#include -#include -#include - - -//#define QT_WEBKIT_MEDIA_INSTRUMENTATION - -using namespace WTF; - -namespace WebCore { - -#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION -class MediaPlayerPrivateInstrumentation -{ -public: - MediaPlayerPrivateInstrumentation() - : update(false) - , frameCount(0) - , paintTimeTotal(0) - , framesPerSecond(0) - , averagePaintTime(0) - , preTime(QTime()) - , lastUpdate(QTime::currentTime()) {} - - void prePaint() { preTime = QTime::currentTime(); } - - void postPaint() - { - QTime time = QTime::currentTime(); - - // Measure seconds different - int paintTime = (time.second() - preTime.second() - 1) * 1000; - paintTime = qMax(0, paintTime); - - // Measure milliseconds different - if(time.msec() < preTime.msec()) - paintTime += time.msec() + (1000 - preTime.msec()); - else - paintTime += time.msec() - preTime.msec(); - - // Add to the total paint time for this second - paintTimeTotal += paintTime; - - // Check for update time - if(time.second() != lastUpdate.second()) { - // Calculate Values - framesPerSecond = frameCount; - averagePaintTime = static_cast(paintTimeTotal) / static_cast(frameCount); - - // Next Update - update = true; - frameCount = 1; - paintTimeTotal = 0; - lastUpdate = time; - } else { - frameCount++; - } - } - - bool updateAvailable() { return update; } - - int fps() { update = false; return framesPerSecond; } - qreal paintTime() { update = false; return averagePaintTime; } - -private: - bool update; - - int frameCount; - qint64 paintTimeTotal; - - int framesPerSecond; - qreal averagePaintTime; - - QTime preTime; - QTime lastUpdate; -}; -#endif // QT_WEBKIT_MEDIA_INSTRUMENTATION - -class MediaPlayerPrivateDefault : public MediaPlayerPrivate { -public: - IntSize naturalSize() const; - void setSize(const IntSize&) {} - void paint(GraphicsContext*, const IntRect&); - bool supportsFullscreen() const { return true; } - -private slots: - void repaint(); - -private: - friend class MediaPlayerPrivate; - MediaPlayerPrivateDefault(MediaPlayer*); - ~MediaPlayerPrivateDefault(); - - QPainterVideoSurface* m_videoSurface; - QVideoOutputControl* m_outputControl; - QVideoRendererControl* m_rendererControl; - - bool m_isActive; - -#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION - MediaPlayerPrivateInstrumentation* m_instruments; -#endif -}; - -MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) -{ - return new MediaPlayerPrivateDefault(player); -} - -void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) -{ - registrar(create, getSupportedTypes, supportsType); -} - -void MediaPlayerPrivate::getSupportedTypes(HashSet &supported) -{ - QStringList types = QMediaPlayer::supportedMimeTypes(); - - for (int i = 0; i < types.size(); i++) { - supported.add(types.at(i)); - } -} - -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, const String& codec) -{ - if(QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMedia::ProbablySupported) { - return MediaPlayer::IsSupported; - } - - return MediaPlayer::MayBeSupported; -} - -MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) - : m_player(player) - , m_mediaPlayer(new QMediaPlayer) - , m_networkState(MediaPlayer::Empty) - , m_readyState(MediaPlayer::HaveNothing) - , m_isVisible(false) - , m_endTime(std::numeric_limits::max()) -{ - // Signal Handlers - connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), - this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); - connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), - this, SLOT(stateChanged(QMediaPlayer::State))); - connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), - this, SLOT(handleError(QMediaPlayer::Error))); - connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)), - this, SLOT(durationChanged(qint64))); - connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)), - this, SLOT(positionChanged(qint64))); - - // Grab the player control - if (m_mediaPlayer) { - QMediaService *service = m_mediaPlayer->service(); - if (service) { - m_mediaPlayerControl = qobject_cast( - service->control(QMediaPlayerControl_iid)); - } - } -} - -MediaPlayerPrivate::~MediaPlayerPrivate() -{ - delete m_mediaPlayer; - m_mediaPlayer = 0; -} - -bool MediaPlayerPrivate::hasVideo() const -{ - return m_mediaPlayer->isVideoAvailable(); -} - -bool MediaPlayerPrivate::hasAudio() const -{ - return true; -} - -void MediaPlayerPrivate::load(const String& url) -{ - // We are now loading - if (m_networkState != MediaPlayer::Loading) { - m_networkState = MediaPlayer::Loading; - m_player->networkStateChanged(); - } - - // And we don't have any data yet - if (m_readyState != MediaPlayer::HaveNothing) { - m_readyState = MediaPlayer::HaveNothing; - m_player->readyStateChanged(); - } - - m_mediaPlayer->setMedia(QUrl(url)); -} - -void MediaPlayerPrivate::cancelLoad() -{ - m_mediaPlayer->setMedia(QMediaContent()); - updateStates(); -} - -void MediaPlayerPrivate::play() -{ - if(m_mediaPlayer->state() != QMediaPlayer::PlayingState) { - m_mediaPlayer->play(); - } -} - -void MediaPlayerPrivate::pause() -{ - if(m_mediaPlayer->state() == QMediaPlayer::PlayingState) { - m_mediaPlayer->pause(); - } -} - -bool MediaPlayerPrivate::paused() const -{ - return m_mediaPlayer->state() != QMediaPlayer::PlayingState; -} - -void MediaPlayerPrivate::seek(float position) -{ - if (!m_mediaPlayer->isSeekable()) - return; - - if (m_mediaPlayerControl != 0 && - !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000)) - return; - - if (position > duration()) - position = duration(); - - m_mediaPlayer->setPosition(position * 1000.0f); -} - -bool MediaPlayerPrivate::seeking() const -{ - return false; -} - -void MediaPlayerPrivate::setEndTime(float time) -{ - // Set the end time in milliseconds - m_endTime = static_cast(time * 1000.0f); - - // Duration may return a smaller value as of now - m_player->durationChanged(); -} - -float MediaPlayerPrivate::duration() const -{ - if (m_readyState < MediaPlayer::HaveMetadata) - return 0.0f; - - float duration = qMin(m_mediaPlayer->duration(), m_endTime) / 1000.0f; - - // We are streaming - if (duration <= 0.0f) - duration = std::numeric_limits::infinity(); - - return duration; -} - -float MediaPlayerPrivate::currentTime() const -{ - float currentTime = m_mediaPlayer->position() / 1000.0f; - return currentTime; -} - -PassRefPtr MediaPlayerPrivate::buffered() const -{ - RefPtr buffered = TimeRanges::create(); - - if(m_mediaPlayerControl == 0) - return buffered; - - QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges(); - - foreach(const QMediaTimeInterval interval, playbackRanges.intervals()) { - float rangeMin = static_cast(interval.start()) / 1000.0f; - float rangeMax = static_cast(interval.end()) / 1000.0f; - buffered->add(rangeMin, rangeMax); - } - - return buffered.release(); -} - -float MediaPlayerPrivate::maxTimeSeekable() const -{ - if(m_mediaPlayerControl == 0) - return 0; - - return static_cast(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f; -} - -unsigned MediaPlayerPrivate::bytesLoaded() const -{ - unsigned percentage = m_mediaPlayer->bufferStatus(); - - if(percentage == 100) { - if(m_networkState != MediaPlayer::Idle) { - m_networkState = MediaPlayer::Idle; - m_player->networkStateChanged(); - } - if(m_readyState != MediaPlayer::HaveEnoughData) { - m_readyState = MediaPlayer::HaveEnoughData; - m_player->readyStateChanged(); - } - } - - QLatin1String blKey("bytes-loaded"); - if(m_mediaPlayer->availableExtendedMetaData().contains(blKey)) - return m_mediaPlayer->extendedMetaData(blKey).toInt(); - - return percentage; -} - -unsigned MediaPlayerPrivate::totalBytes() const -{ - if(m_mediaPlayer->availableMetaData().contains(QtMedia::Size)) - return m_mediaPlayer->metaData(QtMedia::Size).toInt(); - - return 100; -} - -bool MediaPlayerPrivate::totalBytesKnown() const -{ - return m_mediaPlayer->availableMetaData().contains(QtMedia::Size); -} - -void MediaPlayerPrivate::setRate(float rate) -{ - m_mediaPlayer->setPlaybackRate(rate); -} - -void MediaPlayerPrivate::setVolume(float volume) -{ - m_mediaPlayer->setVolume(static_cast(volume * 100.0)); -} - -void MediaPlayerPrivate::setMuted(bool muted) -{ - m_mediaPlayer->setMuted(muted); -} - -int MediaPlayerPrivate::dataRate() const -{ - return 0; -} - -MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const -{ - return m_networkState; -} - -MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const -{ - return m_readyState; -} - -void MediaPlayerPrivate::setVisible(bool visible) -{ - m_isVisible = visible; -} - -void MediaPlayerPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus) -{ - updateStates(); -} - -void MediaPlayerPrivate::handleError(QMediaPlayer::Error) -{ - updateStates(); -} - -void MediaPlayerPrivate::durationChanged(qint64) -{ - m_player->durationChanged(); -} - -void MediaPlayerPrivate::updateStates() -{ - // Store the old states so that we can detect a change and raise change events - MediaPlayer::NetworkState oldNetworkState = m_networkState; - MediaPlayer::ReadyState oldReadyState = m_readyState; - - QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus(); - QMediaPlayer::Error currentError = m_mediaPlayer->error(); - - if(currentError != QMediaPlayer::NoError) { - m_readyState = MediaPlayer::HaveNothing; - if(currentError == QMediaPlayer::FormatError) { - m_networkState = MediaPlayer::FormatError; - } else { - // ResourceError, NetworkError, AccessDeniedError, ServiceMissingError - m_networkState = MediaPlayer::NetworkError; - } - } else if(currentStatus == QMediaPlayer::UnknownMediaStatus || - currentStatus == QMediaPlayer::NoMedia) { - m_networkState = MediaPlayer::Idle; - m_readyState = MediaPlayer::HaveNothing; - } else if(currentStatus == QMediaPlayer::LoadingMedia) { - m_networkState = MediaPlayer::Loading; - m_readyState = MediaPlayer::HaveNothing; - } else if(currentStatus == QMediaPlayer::LoadedMedia) { - m_networkState = MediaPlayer::Loading; - m_readyState = MediaPlayer::HaveMetadata; - } else if(currentStatus == QMediaPlayer::BufferingMedia) { - m_networkState = MediaPlayer::Loading; - m_readyState = MediaPlayer::HaveFutureData; - } else if(currentStatus == QMediaPlayer::StalledMedia) { - m_networkState = MediaPlayer::Loading; - m_readyState = MediaPlayer::HaveCurrentData; - } else if(currentStatus == QMediaPlayer::BufferedMedia || - currentStatus == QMediaPlayer::EndOfMedia) { - m_networkState = MediaPlayer::Idle; - m_readyState = MediaPlayer::HaveEnoughData; - } else if(currentStatus == QMediaPlayer::InvalidMedia) { - m_networkState = MediaPlayer::FormatError; - m_readyState = MediaPlayer::HaveMetadata; - } - - // Log the state changes and raise the state change events - if (m_networkState != oldNetworkState) { - m_player->networkStateChanged(); - } - - if (m_readyState != oldReadyState) { - m_player->readyStateChanged(); - } -} - -MediaPlayerPrivateDefault::MediaPlayerPrivateDefault(MediaPlayer *player) - : MediaPlayerPrivate(player) - , m_videoSurface(new QPainterVideoSurface(m_mediaPlayer)) -{ -#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION - m_instruments = new MediaPlayerPrivateInstrumentation; -#endif - - if (m_mediaPlayer) { - QMediaService *service = m_mediaPlayer->service(); - if (service) { - m_outputControl = qobject_cast( - service->control(QVideoOutputControl_iid)); - m_rendererControl = qobject_cast( - service->control(QVideoRendererControl_iid)); - - if (m_outputControl != 0 && m_rendererControl != 0) { - connect(m_videoSurface, SIGNAL(frameChanged()), this, SLOT(repaint())); - - m_rendererControl->setSurface(m_videoSurface); - m_outputControl->setOutput(QVideoOutputControl::RendererOutput); - } - } - } -} - -MediaPlayerPrivateDefault::~MediaPlayerPrivateDefault() -{ -#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION - delete m_instruments; - m_instruments = 0; -#endif -} - -IntSize MediaPlayerPrivateDefault::naturalSize() const -{ - if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) - return IntSize(); - - QSize videoSize = m_videoSurface->surfaceFormat().sizeHint(); - return IntSize(videoSize.width(), videoSize.height()); -} - -void MediaPlayerPrivateDefault::paint(GraphicsContext* context, const IntRect& rect) -{ - if (context->paintingDisabled()) - return; - - if (!m_isVisible) - return; - -#ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION - m_instruments->prePaint(); -#endif - - // Grab the painter - QPainter* painter = context->platformContext(); - - if(!m_isActive) { - // Attempt GL Setup -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) - if ((painter->paintEngine()->type() == QPaintEngine::OpenGL || - painter->paintEngine()->type() == QPaintEngine::OpenGL2)) { - // Set GL Context - m_videoSurface->setGLContext(const_cast(QGLContext::currentContext())); - - // Check Shader Types - if (m_videoSurface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) { - m_videoSurface->setShaderType(QPainterVideoSurface::GlslShader); - } else { - m_videoSurface->setShaderType(QPainterVideoSurface::FragmentProgramShader); - } - } -#endif - - // Setup Completed - m_isActive = true; - } - - // Paint the frame - m_videoSurface->paint(painter, QRect(rect.x(), rect.y(), - rect.width(), rect.height())); - m_videoSurface->setReady(true); - - #ifdef QT_WEBKIT_MEDIA_INSTRUMENTATION - m_instruments->postPaint(); - - if(m_instruments->updateAvailable()) { - qDebug("FPS: %d, Average Paint Time: %f", m_instruments->fps(), m_instruments->paintTime()); - } - #endif -} - -void MediaPlayerPrivateDefault::repaint() -{ - m_player->repaint(); -} - -} // namespace WebCore - -#include "moc_MediaPlayerPrivateQt.cpp" diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h deleted file mode 100644 index f2d4040..0000000 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2009 Apple Inc. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef MediaPlayerPrivateQt_h -#define MediaPlayerPrivateQt_h - -#include "MediaPlayerPrivate.h" -#include -#include -#include - -namespace WebCore { - - class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface { - - Q_OBJECT - - public: - static MediaPlayerPrivateInterface* create(MediaPlayer* player); - virtual ~MediaPlayerPrivate(); - - static void registerMediaEngine(MediaEngineRegistrar); - static void getSupportedTypes(HashSet&); - static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); - static bool isAvailable() { return true; } - - bool hasVideo() const; - bool hasAudio() const; - - void load(const String &url); - void cancelLoad(); - - void play(); - void pause(); - - bool paused() const; - bool seeking() const; - - float duration() const; - float currentTime() const; - void seek(float); - void setEndTime(float); - - void setRate(float); - void setVolume(float); - void setMuted(bool); - - // State Information - MediaPlayer::NetworkState networkState() const; - MediaPlayer::ReadyState readyState() const; - - // Network Information - PassRefPtr buffered() const; - float maxTimeSeekable() const; - unsigned bytesLoaded() const; - unsigned totalBytes() const; - bool totalBytesKnown() const; - int dataRate() const; - - virtual void setVisible(bool); - - virtual IntSize naturalSize() const = 0; - virtual void setSize(const IntSize&) = 0; - virtual void paint(GraphicsContext*, const IntRect&) = 0; - virtual bool supportsFullscreen() const = 0; - - protected slots: - virtual void mediaStatusChanged(QMediaPlayer::MediaStatus); - virtual void handleError(QMediaPlayer::Error); - virtual void stateChanged(QMediaPlayer::State) {} - virtual void positionChanged(qint64) {} - virtual void durationChanged(qint64); - virtual void repaint() {} - - protected: - MediaPlayerPrivate(MediaPlayer*); - - MediaPlayer* m_player; - QMediaPlayer* m_mediaPlayer; - QMediaPlayerControl* m_mediaPlayerControl; - - mutable MediaPlayer::NetworkState m_networkState; - mutable MediaPlayer::ReadyState m_readyState; - - bool m_isVisible; - qint64 m_endTime; - - private: - void updateStates(); - }; -} - -#endif // MediaPlayerPrivateQt_h -- cgit v0.12 From 2ac3bffd816d9fbe9646b6126b4a882f391b466f Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 4 Feb 2010 10:43:52 +0100 Subject: Small optimization for QStaticText when used with index arrays Don't recalculate the index array when the glyphs are simply moved. --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index d82d335..d20c258 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1349,7 +1349,13 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp textureCoordinateArray.clear(); #if defined(QSTATICTEXT_USE_INDEXARRAY) - indices.clear(); + QStaticTextUserData *uData = staticTextItem->userData; + QOpenGLStaticTextUserData *openGlUserData = uData != 0 + && uData->type == QStaticTextUserData::OpenGLUserData + ? static_cast(uData) + : 0; + bool updateIndices = openGlUserData == 0 + || openGlUserData->indices.size() < staticTextItem->numGlyphs; int j=0; #endif @@ -1362,8 +1368,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); #if defined(QSTATICTEXT_USE_INDEXARRAY) - for (int k=0; k<6; ++k) - indices.append(j++); + if (updateIndices) { + for (int k=0; k<6; ++k) + indices.append(j++); + } #endif } @@ -1390,7 +1398,8 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp textureCoordinateArray.data(), GL_STATIC_DRAW); #if defined(QSTATICTEXT_USE_INDEXARRAY) - userData->indices = indices; + if (updateIndices) + userData->indices = indices; #endif // If a new user data has been created, make sure we delete the old -- cgit v0.12 From d2944ffaa8830628182d4e7c944c6cf4763bb115 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 4 Feb 2010 11:39:36 +0100 Subject: Remove unused code Removed an commented-out, empty functions which was previously there for testing purposes. --- src/gui/painting/qpaintengineex.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index faf5a37..99f26a3 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -592,13 +592,6 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) } } -/* -void QPaintEngineEx::drawStaticTextItem(const QPointF &position, QStaticTextItem *item) -{ - // ### Make this pure virtual after implementing in all subclasses -} -*/ - void QPaintEngineEx::draw(const QVectorPath &path) { const QBrush &brush = state()->brush; -- cgit v0.12 From 8701b7eb49cc1e01fc00516b792894f262ff8cff Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 4 Feb 2010 11:57:00 +0100 Subject: Clean up diff for QStaticText Revert some unnecessary changes from the QStaticText diff. --- src/gui/painting/qpaintengineex.cpp | 1 - src/gui/painting/qtextureglyphcache.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 99f26a3..4f2fffa 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -44,7 +44,6 @@ #include "qstroker_p.h" #include "qbezier_p.h" #include -#include #include #include diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 5a6a0d9..7f32d19 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -320,13 +320,13 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g) #ifdef CACHE_DEBUG // QPainter p(&m_image); // p.drawLine( - /*QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1); + QPoint base(c.x + glyphMargin(), c.y + glyphMargin() + c.baseLineY-1); if (m_image.rect().contains(base)) m_image.setPixel(base, 255); m_image.save(QString::fromLatin1("cache-%1-%2-%3.png") .arg(m_current_textitem->font().family()) .arg(m_current_textitem->font().pointSize()) - .arg(m_transform.type()));*/ + .arg(m_transform.type())); #endif } -- cgit v0.12 From 0c444f72281fded5e226ec786614595a86bff4e3 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 4 Feb 2010 14:01:33 +0100 Subject: Revert changes made to QTextEngine for QStaticText Some changes were made to QTextEngine for the sake of QStaticText, but as the implementation of QStaticText changed, these are no longer needed. Although they are harmless, I'll remove them to minimize the diff. --- src/gui/text/qtextengine.cpp | 58 -------------------------------------------- src/gui/text/qtextengine_p.h | 11 +-------- 2 files changed, 1 insertion(+), 68 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index b55ac68..02eae98 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2109,19 +2109,6 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs) allocated = newAllocated; } -QGlyphLayout QGlyphLayout::clone(char *address) const -{ - QGlyphLayout layout(address, numGlyphs); - memmove(layout.offsets, offsets, numGlyphs * sizeof(QFixedPoint)); - memmove(layout.attributes, attributes, numGlyphs * sizeof(HB_GlyphAttributes)); - memmove(layout.justifications, justifications, numGlyphs * sizeof(QGlyphJustification)); - memmove(layout.advances_y, advances_y, numGlyphs * sizeof(QFixed)); - memmove(layout.advances_x, advances_x, numGlyphs * sizeof(QFixed)); - memmove(layout.glyphs, glyphs, numGlyphs * sizeof(HB_Glyph)); - - return layout; -} - // grow to the new size, copying the existing data to the new layout void QGlyphLayout::grow(char *address, int totalGlyphs) { @@ -2637,51 +2624,6 @@ QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFo : justified(false), underlineStyle(QTextCharFormat::NoUnderline), charFormat(format), num_chars(0), chars(0), logClusters(0), f(0), fontEngine(0) { - init(si, font, format); -} - -QTextItemInt::QTextItemInt(const QTextItemInt &other) - : descent(other.descent), ascent(other.ascent), width(other.width), - flags(other.flags), justified(other.justified), underlineStyle(other.underlineStyle), - charFormat(other.charFormat), num_chars(other.num_chars), chars(other.chars), - fontEngine(other.fontEngine), f(other.f), glyphs(other.glyphs), - logClusters(other.logClusters) -{ -} - - -QTextItemInt QTextItemInt::clone(char *glyphLayoutMemory, unsigned short *logClusterMemory) const -{ - QTextItemInt ti(*this); - - ti.glyphs = glyphs.clone(glyphLayoutMemory); - ti.logClusters = logClusterMemory; - memmove(logClusterMemory, logClusters, glyphs.numGlyphs * sizeof(unsigned short)); - - return ti; -} - -QTextItemInt &QTextItemInt::operator=(const QTextItemInt &other) -{ - descent = other.descent; - ascent = other.ascent; - width = other.width; - flags = other.flags; - justified = other.justified; - underlineStyle = other.underlineStyle; - charFormat = other.charFormat; - num_chars = other.num_chars; - chars = other.chars; - fontEngine = other.fontEngine; - f = other.f; - glyphs = other.glyphs; - logClusters = other.logClusters; - - return *this; -} - -void QTextItemInt::init(const QScriptItem &si, QFont *font, const QTextCharFormat &format) -{ // explicitly initialize flags so that initFontAttributes can be called // multiple times on the same TextItem flags = 0; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 347b71e..f36cbd2 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -262,8 +262,6 @@ struct QGlyphLayout } void grow(char *address, int totalGlyphs); - - QGlyphLayout clone(char *address) const; }; class QVarLengthGlyphLayoutArray : private QVarLengthArray, public QGlyphLayout @@ -312,19 +310,12 @@ public: : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0), logClusters(0), f(0), fontEngine(0) {} - - QTextItemInt(const QTextItemInt &other); QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); - void init(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); - - QTextItemInt clone(char *glyphLayoutMemory, unsigned short *logClusterMemory) const; /// copy the structure items, adjusting the glyphs arrays to the right subarrays. /// the width of the returned QTextItemInt is not adjusted, for speed reasons QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const; - QTextItemInt &operator=(const QTextItemInt &other); - QFixed descent; QFixed ascent; QFixed width; @@ -332,7 +323,7 @@ public: RenderFlags flags; bool justified; QTextCharFormat::UnderlineStyle underlineStyle; - QTextCharFormat charFormat; + const QTextCharFormat charFormat; int num_chars; const QChar *chars; const unsigned short *logClusters; -- cgit v0.12 From a2fe25025f75ae750df22c59c338005eeda3d744 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Thu, 4 Feb 2010 21:17:42 +0100 Subject: Doc: Added Simplified Chinese documents and build rules for them. Also updated qdoc's configuration reader so that we can put UTF-8 content in the .qdocconf files later. Reviewed-by: Trust Me --- doc/doc.pri | 11 +- doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc | 96 +++ doc/src/zh_CN/getting-started/tutorials.qdoc | 103 ++++ doc/src/zh_CN/tutorials/addressbook.qdoc | 673 +++++++++++++++++++++ doc/src/zh_CN/tutorials/widgets-tutorial.qdoc | 244 ++++++++ tools/qdoc3/config.cpp | 4 +- 6 files changed, 1129 insertions(+), 2 deletions(-) create mode 100644 doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc create mode 100644 doc/src/zh_CN/getting-started/tutorials.qdoc create mode 100644 doc/src/zh_CN/tutorials/addressbook.qdoc create mode 100644 doc/src/zh_CN/tutorials/widgets-tutorial.qdoc diff --git a/doc/doc.pri b/doc/doc.pri index 463c447..ccbef1a 100644 --- a/doc/doc.pri +++ b/doc/doc.pri @@ -30,8 +30,14 @@ QT_DOCUMENTATION = ($$QDOC qt-api-only.qdocconf assistant.qdocconf designer.qdoc $$GENERATOR doc-build/html-qmake/qmake.qhp -o doc/qch/qmake.qch \ ) +QT_ZH_CN_DOCUMENTATION = ($$QDOC qt-api-only_zh_CN.qdocconf) && \ + (cd $$QT_BUILD_TREE && \ + $$GENERATOR doc-build/html-qt_zh_CN/qt.qhp -o doc/qch/qt_zh_CN.qch \ + ) + win32-g++:isEmpty(QMAKE_SH) { QT_DOCUMENTATION = $$replace(QT_DOCUMENTATION, "/", "\\\\") + QT_ZH_CN_DOCUMENTATION = $$replace(QT_ZH_CN_DOCUMENTATION, "/", "\\\\") } # Build rules: @@ -42,6 +48,9 @@ qch_docs.depends += sub-tools docs.depends = adp_docs qch_docs +docs_zh_CN.depends = docs +docs_zh_CN.commands = $$QT_ZH_CN_DOCUMENTATION + # Install rules htmldocs.files = $$QT_BUILD_TREE/doc/html htmldocs.path = $$[QT_INSTALL_DOCS] @@ -54,5 +63,5 @@ qchdocs.CONFIG += no_check_exist docimages.files = $$QT_BUILD_TREE/doc/src/images docimages.path = $$[QT_INSTALL_DOCS]/src -QMAKE_EXTRA_TARGETS += qdoc adp_docs qch_docs docs +QMAKE_EXTRA_TARGETS += qdoc adp_docs qch_docs docs docs_zh_CN INSTALLS += htmldocs qchdocs docimages diff --git a/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc new file mode 100644 index 0000000..5f95dde --- /dev/null +++ b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 documentation 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$ +** +****************************************************************************/ + +/*! + \page how-to-learn-qt.html + \title 如何学习 Qt + \brief Links to guides and resources for learning Qt. + \nextpage Tutorials + + \section1 Getting Started + + 我们å‡å®šæ‚¨å·²äº†è§£ C++, 并将用于 Qt å¼€å‘。有关将 Qt 与其他编程语言一起使用的更多信æ¯ï¼Œè¯·å‚è§ \l{Qt website}{Qt 网站}。 + + 如果你想仅使用 C++ 编程, ä¸ä½¿ç”¨ä»»ä½•设计工具而仅使用代ç è®¾è®¡ç”¨æˆ·ç•Œé¢ï¼Œè¯·è§‚看\l{教程}。这些教程是为您了解 Qt 编程é‡èº«å®šåšçš„,并侧é‡äºŽç¼–写å¯ç”¨ä»£ç ï¼Œè€Œå¹¶éžåŠŸèƒ½ç®€ä»‹ã€‚ + + 如果您想使用设计工具æ¥è®¾è®¡ç”¨æˆ·ç•Œé¢ï¼Œåˆ™è‡³å°‘è¦é˜…读 \l{Qt Designer manual}{Qt 设计者手册}çš„å‰å‡ ç« ã€‚ + + 现在您已ç»ç¼–写了一些å°åž‹å¯ç”¨çš„应用程åºï¼Œå¹¶å¯¹ Qt 编程有更加广泛的了解。您å¯ä»¥ç›´æŽ¥ç€æ‰‹åšè‡ªå·±çš„项目,但我们建议您阅读以下一些关键简介以加深您对 Qt 的了解:\l{Qt Object Model}Qt 对象模型}å’Œ\l{Signals and Slots}{ä¿¡å·å’Œæ§½}。 + + \beginfloatleft + \inlineimage qtdemo-small.png + \endfloat + + \section1 了解概况 + + 在这个阶段,我们建议您æµè§ˆä¸€ä¸‹\l{All Overviews and HOWTOs}{简介},然åŽé˜…读与您项目相关的章节。您å¯èƒ½è¿˜ä¼šå‘现,æµè§ˆä¸Žæ‚¨é¡¹ç›®ç±»ä¼¼çš„\l{Qt Examples}{示例}çš„æºä»£ç ä¹Ÿä¼šå¯¹æ‚¨æœ‰æ‰€å¸®åŠ©ã€‚ç”±äºŽ Qt æºä»£ç å·²é¢å‘公众开放,您也å¯é˜…读 Qt æºä»£ç ã€‚ + + 如果您è¿è¡Œ\l{Examples and Demos Launcher}{示例和演示å¯åŠ¨ç¨‹åº},您就会看到许多正在使用的 Qt widget。 + + \l{Qt Widget Gallery} 还按照在ä¸åŒæ”¯æŒå¹³å°ä¸Šçš„使用风格æä¾›äº†ç²¾é€‰ Qt widget 简介。 + \clearfloat + + \section1 Books and Learning Materials + + Qt 附另大釿–‡æ¡£ï¼Œå¹¶å…¨æ–‡å¸¦æœ‰è¶…文本交å‰å¼•用,å¯è½»æ¾åœ°ç‚¹å‡»äº†è§£è‡ªå·±æƒ³çŸ¥é“的内容。您使用最多的文档å¯èƒ½æ˜¯ \l{index.html}{API 引用}。æ¯ä¸ªé“¾æŽ¥éƒ½æä¾›äº†æµè§ˆ API 引用的ä¸åŒæ–¹å¼ï¼Œæ‚¨å¯æ¯ä¸ªéƒ½å°è¯•一下,看哪个更适åˆè‡ªå·±ã€‚您还å¯ä»¥å°è¯• \l{Qt Assistant}ï¼Œè¿™æ˜¯éš Qt 附带的工具,å¯è®¿é—®å…¨éƒ¨ Qt API,并æä¾›å…¨æ–‡æœ¬æœç´¢åŠŸèƒ½ã€‚ + + 有大é‡çš„ä¹¦ç±æ˜¯å…³äºŽ Qt 编程的。有关 Qt 书ç±çš„完整列表。 + We recommend the official Qt book, + \l{http://www.amazon.com/gp/product/0132354160/ref=ase_trolltech/}{C++ + GUI Programming with Qt 4, Second Edition} (ISBN 0-13-235416-0). + 本书从 "Hello Qt" 到高级功能(如多线程ã€2D å’Œ 3D 图形ã€ç½‘络ã€å†…容视图类与 XML),全é¢è¯¦å®žåœ°è¯´æ˜Žäº† Qt 编程。(第一版基于 Qt 4.1,å¯\l{http://www.qtrac.eu/C++-GUI-Programming-with-Qt-4-1st-ed.zip}{在线}获得。) + + 包括ä¸åŒè¯­è¨€çš„翻译版本,请å‚è§\l{Books about Qt Programming}{有关 Qt 编程的书ç±}。 + + å¦ä¸€ä¸ªæœ‰å…³å®žä¾‹ä»£ç å’Œ Qt 功能说明的有用资æºå°±æ˜¯å­˜æ¡£çš„ \l{Qt Quarterly}{Qt 季讯}文章,季讯是为 Qt 用户æä¾›çš„æ–°é—»æ—¶è®¯ã€‚ + + 有关特定 Qt 模å—和其他指å—的文档,请å‚è§\l{All Overviews and HOWTOs}。 + + \section1 Further Reading + + Qt has an active and helpful user community who communicate using + the \l{Qt Mailing Lists}{qt-interest} mailing list, the \l{Qt Centre} + Web site, and a number of other community Web sites and Weblogs. + In addition, many Qt developers are active members of the + \l{KDE}{KDE community}. + + ç¥æ‚¨å¥½è¿å¹¶ä¸”å­¦ä¹ æ„‰å¿«ï¼ +*/ diff --git a/doc/src/zh_CN/getting-started/tutorials.qdoc b/doc/src/zh_CN/getting-started/tutorials.qdoc new file mode 100644 index 0000000..56d147e --- /dev/null +++ b/doc/src/zh_CN/getting-started/tutorials.qdoc @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 documentation 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$ +** +****************************************************************************/ + +/*! + \page tutorials.html + \title Tutorials + + \contentspage How to Learn Qt + \nextpage Qt Examples + + \brief Tutorials, guides and overviews to help you learn Qt. + + \nextpage Qt Examples + + A collection of tutorials and "walkthrough" guides are provided with Qt to + help new users get started with Qt development. These documents cover a + range of topics, from basic use of widgets to step-by-step tutorials that + show how an application is put together. + + \table + \row + \o{2,1} \l{Widgets 教程}{\bold Widgets} + \o{2,1} \l{地å€ç°¿æ•™ç¨‹}{\bold {地å€ç°¿}} + \row + \o \image widget-examples.png Widgets + \o + A beginner's guide to getting started with widgets and layouts to create + GUI applications. + + \o \image addressbook-tutorial.png 地å€ç°¿ + \o + A seven part guide to creating a fully-functioning address book + application. This tutorial is also available with + \l{Tutoriel "Carnet d'adresses"}{French explanation}. + + \row + \o{2,1} \l{A Quick Start to Qt Designer}{\bold{Qt Designer}} + \o{2,1} \l{Qt Linguist Manual: Programmers#Tutorials}{\bold {Qt Linguist}} + \row + \o \image designer-examples.png QtDesigner + \o + A quick guide through \QD showing the basic steps to create a + form with this interactive tool. + + \o \image linguist-examples.png QtLinguist + \o + A guided tour through the translations process, explaining the + tools provided for developers, translators and release managers. + + \row + \o{2,1} \l{QTestLib Tutorial}{\bold QTestLib} + \o{2,1} \l{qmake Tutorial}{\bold qmake} + \row + \o{2,1} + This tutorial gives a short introduction to how to use some of the + features of Qt's unit-testing framework, QTestLib. It is divided into + four chapters. + + \o{2,1} + This tutorial teaches you how to use \c qmake. We recommend that + you read the \l{qmake Manual}{qmake user guide} after completing + this tutorial. + + \endtable +*/ diff --git a/doc/src/zh_CN/tutorials/addressbook.qdoc b/doc/src/zh_CN/tutorials/addressbook.qdoc new file mode 100644 index 0000000..5bd0d35 --- /dev/null +++ b/doc/src/zh_CN/tutorials/addressbook.qdoc @@ -0,0 +1,673 @@ +/**************************************************************************** +** +** 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 documentation 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$ +** +****************************************************************************/ + +/*! + \page tutorials-addressbook.html + + \startpage {index.html}{Qt Reference Documentation} + \contentspage Tutorials + \nextpage {tutorials/addressbook/part1}{第一章} + + \title 地å€ç°¿æ•™ç¨‹ + \brief 本教程介ç»äº†ä½¿ç”¨ Qt è·¨å¹³å°æ¡†æž¶çš„ GUI 编程。 + + 本教程介ç»äº†ä½¿ç”¨ Qt è·¨å¹³å°æ¡†æž¶çš„ GUI 编程。 + + \image addressbook-tutorial-screenshot.png + + \omit + It doesn't cover everything; the emphasis is on teaching the programming + philosophy of GUI programming, and Qt's features are introduced as needed. + Some commonly used features are never used in this tutorial. + \endomit + + 在学习过程中,我们将了解部分 Qt 基本技术,如 + + \list + \o Widget 和布局管ç†å™¨ + \o 容器类 + \o ä¿¡å·å’Œæ§½ + \o 输入和输出设备 + \endlist + + 如果您完全ä¸äº†è§£ Qt,请阅读\l{How to Learn Qt}{如何学习 Qt}(如果您还未阅读)。 + + 教程的æºä»£ç ä½äºŽ Qt çš„ \c examples/tutorials/addressbook 目录下。 + + 教程章节: + + \list 1 + \o \l{tutorials/addressbook/part1}{设计用户界é¢} + \o \l{tutorials/addressbook/part2}{添加地å€} + \o \l{tutorials/addressbook/part3}{æµè§ˆåœ°å€ç°¿æ¡ç›®} + \o \l{tutorials/addressbook/part4}{编辑和删除地å€} + \o \l{tutorials/addressbook/part5}{添加查找功能} + \o \l{tutorials/addressbook/part6}{加载和ä¿å­˜} + \o \l{tutorials/addressbook/part7}{附加功能} + \endlist + + 虽然这个å°åž‹åº”用程åºçœ‹èµ·æ¥å¹¶ä¸è±¡ä¸€ä¸ªæˆç†Ÿçš„现代 GUI 应用程åºï¼Œä½†å®ƒä½¿ç”¨å¤šç§ç”¨äºŽæ›´å¤æ‚应用程åºçš„基本技术。在您完æˆå­¦ä¹ ä¹‹åŽï¼Œæˆ‘们建议您查看一下\l{mainwindows/application}{应用程åº}示例,它æä¾›å¸¦æœ‰èœå•ã€å·¥å…·æ ã€çŠ¶æ€æ ç­‰é¡¹ç›®çš„å°åž‹ GUI 应用程åºã€‚ +*/ + +/*! + \page tutorials-addressbook-part1.html + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part2}{第二章} + \example tutorials/addressbook/part1 + \title 地å€ç°¿ 1 — è®¾è®¡ç”¨æˆ·ç•Œé¢ + + 本教程的第一部分讲述了用于地å€ç°¿åº”用程åºçš„åŸºæœ¬å›¾å½¢ç”¨æˆ·ç•Œé¢ (GUI) 的设计。 + + 创建 GUI 程åºçš„第一步就是设计用户界é¢ã€‚在本章中,我们的目标是设置应用基本地å€ç°¿åº”ç”¨ç¨‹åºæ‰€éœ€çš„æ ‡ç­¾å’Œè¾“入字段。下图为期望输出的å±å¹•截图。 + + \image addressbook-tutorial-part1-screenshot.png + + 我们需è¦ä½¿ç”¨ä¸¤ä¸ª QLabel 对象:\c nameLabel å’Œ \c addressLabel,以åŠä¸¤ä¸ªè¾“入字段:QLineEdit 对象 \c nameLine å’Œ QTextEdit + 对象 \c addressText,这样用户æ‰èƒ½è¾“å…¥è”系人的姓å和地å€ã€‚使用的 widget åŠå…¶ä½ç½®å¦‚下图所示。 + + \image addressbook-tutorial-part1-labeled-screenshot.png + + è¦åº”用地å€ç°¿éœ€ä½¿ç”¨ä¸‰ä¸ªæ–‡ä»¶ï¼š + + \list + \o \c{addressbook.h} — AddressBook 类的定义文件, + \o \c{addressbook.cpp} — AddressBook ç±»çš„æ‰§è¡Œæ–‡ä»¶ï¼Œä»¥åŠ + \o \c{main.cpp} — åŒ…å« \c main() 函数并带有 AddressBook 实例的文件。 + \endlist + + \section1 Qt 编程 — 使用å­ç±» + + 在编写 Qt ç¨‹åºæ—¶ï¼Œæˆ‘们通常使用 Qt 对象å­ç±»æ¥æ·»åŠ åŠŸèƒ½ã€‚è¿™æ˜¯åˆ›å»ºå®šåˆ¶ widget 或标准 widget 集åˆçš„基本概念之一。使用å­ç±»æ‰©å±•æˆ–æ”¹å˜ widget çš„æ“作具有以下优势: + + \list + \o 我们å¯ä»¥ç¼–å†™è™šå‡½æ•°æˆ–çº¯è™šå‡½æ•°åº”ç”¨ï¼Œä»¥å¾—åˆ°æˆ‘ä»¬ç¡®åˆ‡æ‰€éœ€çš„åŠŸèƒ½ï¼Œå¹¶åœ¨éœ€è¦æ—¶å†ä½¿ç”¨åŸºæœ¬çš„类应用。 + \o 这样我们就å¯ä»¥åœ¨ç±»ä¸­å°è£…部分用户界é¢ï¼Œåº”用程åºçš„其他部分也就无需了解用户界é¢ä¸­å•独使用的 widget。 + \o å¯ä½¿ç”¨å­ç±»åœ¨åŒä¸€åº”ç”¨ç¨‹åºæˆ–库中创建多个定制 widget,这样å­ç±»çš„代ç å¯åœ¨å…¶ä»–项目é‡å¤ä½¿ç”¨ã€‚ + \endlist + + 由于 Qt 未æä¾›ç‰¹å®šçš„地å€ç°¿ widget,我们在标准的 Qt widget 类中使用å­ç±»ï¼Œç„¶åŽæ·»åŠ åŠŸèƒ½ã€‚æˆ‘ä»¬åœ¨æœ¬æ•™ç¨‹ä¸­åˆ›å»ºçš„ \c AddressBook 类在需è¦ä½¿ç”¨åŸºæœ¬åœ°å€ç°¿ widget 的情况下å¯é‡å¤ä½¿ç”¨ã€‚ + + \section1 定义 AddressBook ç±» + + \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} 文件用于定义 \c AddressBook 类。 + + 我们从定义 \c AddressBook 为 QWidget å­ç±»å’Œå£°æ˜Žæž„造器开始入手。我们还使用 Q_OBJECT å®è¡¨æ˜Žè¯¥ç±»ä½¿ç”¨å›½é™…化功能与 Qt ä¿¡å·å’Œæ§½åŠŸèƒ½ï¼Œå³ä½¿åœ¨æœ¬é˜¶æ®µä¸ä¼šç”¨åˆ°æ‰€æœ‰è¿™äº›åŠŸèƒ½ã€‚ + + \snippet tutorials/addressbook/part1/addressbook.h class definition + + 该类包å«äº† \c nameLine å’Œ \c addressText 的声明ã€ä¸Šæ–‡æåˆ°çš„ QLineEdit å’Œ QTextEdit çš„ç§æœ‰å®žä¾‹ã€‚在以åŽç« èŠ‚ä¸­ï¼Œæ‚¨ä¼šçœ‹åˆ°å‚¨å­˜åœ¨ \c nameLine å’Œ \c addressText 中的数æ®åœ¨åœ°å€ç°¿çš„许多功能中都会用到。 + + 我们ä¸å¿…包å«è¦ä½¿ç”¨çš„ QLabel å¯¹è±¡çš„å£°æ˜Žï¼Œè¿™æ˜¯å› ä¸ºåœ¨åˆ›å»ºè¿™äº›å¯¹è±¡åŽæˆ‘们ä¸å¿…对其进行引用。在下一部分中,我们会说明 Qt 记录对象所属关系的方å¼ã€‚ + + Q_OBJECT 宿œ¬èº«åº”用了部分更高级的 Qt 功能。 我们暂时把 Q_OBJECT å®ç†è§£ä¸ºä½¿ç”¨ \l{QObject::}{tr()} å’Œ \l{QObject::}{connect()} å‡½æ•°çš„å¿«æ·æ–¹å¼ï¼Œè¿™ç§ç†è§£å¯¹æˆ‘们的学习更有用。 + + æˆ‘ä»¬çŽ°å·²å®Œæˆ \c addressbook.h æ–‡ä»¶ï¼ŒæŽ¥ä¸‹æ¥æˆ‘ä»¬æ¥æ‰§è¡Œå¯¹åº”çš„ \c addressbook.cpp 文件。 + + \section1 应用 AddressBook ç±» + + \c AddressBook 的构造器接收 QWidget 傿•° \a parentã€‚æŒ‰æƒ¯ä¾‹ï¼Œæˆ‘ä»¬å°†å‚æ•°ä¼ é€’给基本类的构造器。这ç§çˆ¶é¡¹å¯æœ‰ä¸€ä¸ªæˆ–多个å­é¡¹çš„æ‰€å±žæ¦‚念对 Qt 中的 widget 分组å分有用。例如,如果删除父项,也会删除其所有å­é¡¹ã€‚ + + \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields + + 在该构造器中,我们声明并通过实例æ¥è¡¨ç¤ºä¸¤ä¸ªå±€éƒ¨ QLabel 对象 \c nameLabel å’Œ \c addressLabelï¼Œä»¥åŠ \c nameLine å’Œ \c addressText。如果字符串已进行转æ¢ï¼Œåˆ™ \l{QObject::tr()}{tr()} 函数返回已转æ¢çš„字符串,å¦åˆ™è¿”回字符串本身。我们å¯ä»¥å°†æ­¤å‡½æ•°ç†è§£ \c{} æ ‡è¯†æ¥æ ‡è®°è¦è¿›è¡Œè½¬æ¢ QString 对象。在以åŽç« èŠ‚å’Œ \l{Qt Examples} 中,您会看到åªè¦ä½¿ç”¨äº†å¯è½¬æ¢çš„字符串就是使用该函数。 + + 使用 Qt 编程时,了解布局是如何起作用的会对您很有帮助。Qt æä¾›ä¸‰ä¸ªä¸»è¦å¸ƒå±€ç±» QHBoxLayoutã€QVBoxLayout å’Œ QGridLayout æ¥å¤„ç† widget çš„ä½ç½®ã€‚ + + \image addressbook-tutorial-part1-labeled-layout.png + + 我们使用 QGridLayout ä»¥ç»“æž„åŒ–çš„æ–¹å¼æ”¾ç½®æ ‡ç­¾å’Œè¾“入字段。QGridLayout å°†å¯ç”¨ç©ºé—´åˆ†ä¸ºç½‘格,并将 widget 放置在指定了行列å·çš„å•元格中。上é¢çš„图表显示了布局å•元格和 widget çš„ä½ç½®ã€‚æˆ‘ä»¬é€šè¿‡ä»¥ä¸‹ä»£ç æŒ‡å®šè¿™ç§æŽ’列方å¼ï¼š + + \snippet tutorials/addressbook/part1/addressbook.cpp layout + + 请注æ„,\c addressLabel æ˜¯ä½¿ç”¨ä½œä¸ºé™„åŠ å‚æ•°çš„ Qt::AlignTop æ¥æŽ’æ”¾ä½ç½®ã€‚è¿™å¯ç¡®ä¿å…¶ä¸ä¼šçºµå‘放置在å•元格 (1,0) 中央。有关 Qt 布局的基本简介,请å‚è§\l{Layout Management}{布局类}文档。 + + è¦åœ¨ widget 上安装布局对象,必须调用 widget çš„ \l{QWidget::setLayout()}{setLayout()} 函数: + + \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout + + 最åŽï¼Œæˆ‘们将 widget 标题设置为“简å•地å€ç°¿â€ã€‚ + + \section1 è¿è¡Œåº”ç”¨ç¨‹åº + + \c main() 函数使用å•独的文件 \c main.cpp。在该函数中,我们实例化了 QApplication 对象 \c app。QApplication 负责管ç†å¤šç§åº”用范围的资æºï¼ˆå¦‚默认字体和光标),以åŠè¿è¡Œäº‹ä»¶å¾ªçŽ¯ã€‚å› æ­¤ï¼Œåœ¨æ¯ä¸ªä½¿ç”¨ Qt çš„ GUI 应用程åºä¸­éƒ½ä¼šæœ‰ä¸€ä¸ª QApplication 对象。 + + \snippet tutorials/addressbook/part1/main.cpp main function + + 我们使用 new 关键字在堆中构造一个新的 \c AddressBook widget,然åŽè°ƒç”¨ \l{QWidget::show()}{show()} 函数对其进行显示。ä¸è¿‡ï¼Œè¯¥ widget åªæœ‰åœ¨åº”用程åºäº‹ä»¶å¾ªçŽ¯å¼€å§‹æ—¶æ‰ä¼šæ˜¾ç¤ºã€‚我们通过调用应用程åºçš„ \l{QApplication::}{exec()} 函数开始事件循环。该函数返回的结果作为 \c main() 函数的返回值。 +*/ + +/*! + \page tutorials-addressbook-part2.html + \previouspage 地å€ç°¿ 1 — è®¾è®¡ç”¨æˆ·æŽ¥å£ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part3}{第三章} + \example tutorials/addressbook/part2 + \title 地å€ç°¿ 2 — æ·»åŠ åœ°å€ + + 创建基本地å€ç°¿åº”用程åºçš„下一步是添加少许用户互动æ“作。 + + \image addressbook-tutorial-part2-add-contact.png + + 我们将æä¾›ä¸€ä¸ªæŒ‰é’®ï¼Œç”¨æˆ·å¯ç‚¹å‡»è¯¥æŒ‰é’®æ¥æ·»åŠ æ–°è”系人。此外,还需è¦å¯¹æ•°æ®ç»“构进行é™å®šï¼Œä»¥ä¾¿æœ‰åºåœ°å‚¨å­˜è¿™äº›è”系人。 + + \section1 定义 AddressBook ç±» + + 由于已ç»è®¾ç½®äº†æ ‡ç­¾å’Œè¾“入字段,我们åªéœ€æ·»åŠ æŒ‰é’®å°±å¯å®Œæˆæ·»åŠ è”系人这一步骤。也就是说,在 \c addressbook.h 文件中已ç»å£°æ˜Žäº†ä¸‰ä¸ª QPushButton 对象和三个对应的公共槽。 + + \snippet tutorials/addressbook/part2/addressbook.h slots + + 槽是对特殊信å·è¿›è¡Œå“应的函数。我们将在应用 \c AddressBook 类时进一步详细说明这一概念。如需有关 Qt ä¿¡å·å’Œæ§½æ¦‚念的简介,请å‚è§\l{Signals and Slots}{ä¿¡å·å’Œæ§½}文档。 + + 三个 QPushButton 对象分别是 \c addButtonã€\c submitButton å’Œ \c cancelButton,已与è¦åœ¨ä¸Šä¸€ç« ä¸­è¯´æ˜Žçš„ \c nameLine å’Œ \c addressText 一åŒåŒ…å«åœ¨ç§æœ‰å˜é‡å£°æ˜Žä¸­ã€‚ + + \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration + + 我们需è¦ä¸€ä¸ªå®¹å™¨æ¥å‚¨å­˜åœ°å€ç°¿è”系人,这样æ‰èƒ½æœç´¢å’Œæ˜¾ç¤ºè”系人。QMap 对象 \c contacts å°±å¯å®žçŽ°æ­¤åŠŸèƒ½ï¼Œå› ä¸ºå…¶å¸¦æœ‰ä¸€ä¸ªé”®-值对:è”系人姓å作为键,而è”系人地å€ä½œä¸º\e{值}。 + + \snippet tutorials/addressbook/part2/addressbook.h remaining private variables + + æˆ‘ä»¬è¿˜ä¼šå£°æ˜Žä¸¤ä¸ªç§æœ‰ QString 对象:\c oldName å’Œ \c oldAddress。这些对象用æ¥ä¿ç•™åœ¨ç”¨æˆ·ç‚¹å‡»\gui{添加}æ—¶æœ€åŽæ˜¾ç¤ºçš„è”系人姓å和地å€ã€‚这样,当用户点击\gui{å–æ¶ˆ}时,我们就å¯ä»¥è¿”回至上一个è”系人的详细信æ¯ã€‚ + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook 构造器中,我们将 \c nameLine å’Œ \c addressText 设置为åªè¯»ï¼Œè¿™æ ·å°±å¯ä»…显示而ä¸å¿…编辑现有è”系人的详细信æ¯ã€‚ + + \dots + \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1 + \dots + \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2 + + ç„¶åŽï¼Œæˆ‘们实例化以下按钮:\c addButtonã€\c submitButton å’Œ \c cancelButton。 + + \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration + + 显示 \c addButton 是通过调用 \l{QPushButton::show()}{show()} 函数实现的,而éšè— \c submitButton å’Œ \c cancelButton 则需调用 \l{QPushButton::hide()}{hide()}。这两个按钮仅当用户点击\gui{添加}æ—¶æ‰ä¼šæ˜¾ç¤ºï¼Œè€Œæ­¤æ“作是通过在下文中说明的\c addContact() 函数处ç†çš„。 + + \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots + + 我们将按钮的 \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Žå…¶ç›¸åº”的槽关è”。下é¢çš„图表说明了此过程。 + + \image addressbook-tutorial-part2-signals-and-slots.png + + 接下æ¥ï¼Œæˆ‘们将按钮整é½çš„æŽ’列在地å€ç°¿ widget çš„å³ä¾§ï¼Œä½¿ç”¨ QVBoxLayout å°†å…¶è¿›è¡Œçºµå‘æŽ’åˆ—ã€‚ + + \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout + + \l{QBoxLayout::addStretch()}{addStretch()} 函数用æ¥ç¡®ä¿æŒ‰é’®å¹¶ä¸æ˜¯é‡‡ç”¨å‡åŒ€é—´éš”æŽ’列的,而是更é è¿‘ widget 的顶部。下图显示了是å¦ä½¿ç”¨ \l{QBoxLayout::addStretch()}{addStretch()} 的差别。 + + \image addressbook-tutorial-part2-stretch-effects.png + + ç„¶åŽï¼Œæˆ‘们使用 \l{QGridLayout::addLayout()}{addLayout()} å°† \c buttonLayout1 增加至 \c mainLayout。 这样我们就有了嵌套布局,因为 \c buttonLayout1 现在是 \c mainLayout çš„å­é¡¹ã€‚ + + \snippet tutorials/addressbook/part2/addressbook.cpp grid layout + + å¸ƒå±€åæ ‡æ˜¾ç¤ºå¦‚下: + + \image addressbook-tutorial-part2-labeled-layout.png + + 在 \c addContact() 函数中,我们使用 \c oldName å’Œ \c oldAddress å‚¨å­˜æœ€åŽæ˜¾ç¤ºçš„è”系人详细信æ¯ã€‚ç„¶åŽï¼Œæˆ‘们清空这些输入字段并关闭åªè¯»æ¨¡å¼ã€‚输入焦点设置在 \c nameLine,显示 \c submitButton å’Œ \c cancelButton。 + + \snippet tutorials/addressbook/part2/addressbook.cpp addContact + + \c submitContact() 函数å¯åˆ†ä¸ºä¸‰ä¸ªéƒ¨åˆ†ï¼š + + \list 1 + \o 我们从 \c nameLine å’Œ \c addressText æå–è”系人的详细信æ¯ï¼Œç„¶åŽå°†å…¶å‚¨å­˜åœ¨ QString 对象中。我们还è¦éªŒè¯ç¡®ä¿ç”¨æˆ·æ²¡æœ‰åœ¨è¾“入字段为空时点击\gui{æäº¤},å¦åˆ™ï¼Œä¼šæ˜¾ç¤º QMessageBox æç¤ºç”¨æˆ·è¾“入姓å和地å€ã€‚ + + \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1 + + \o 我们接ç€ç»§ç»­æ£€æŸ¥æ˜¯å¦è”系人已存在。如果ä¸å­˜åœ¨ï¼Œå°†è”系人添加至 \c contactsï¼Œç„¶åŽæ˜¾ç¤º QMessageBox æç¤ºç”¨æˆ·å·²æ·»åŠ è”系人。 + + \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2 + + 如果è”系人已存在,还是会显示 QMessageBox 以æç¤ºç”¨æˆ·ï¼Œä»¥å…添加é‡å¤çš„è”系人。由于 \c contacts 对象是基于姓å地å€çš„é”®-值对,因此è¦ç¡®ä¿é”®å”¯ä¸€ã€‚ + + \o 在处ç†äº†ä¸Šè¿°ä¸¤ç§æƒ…况åŽï¼Œä½¿ç”¨ä»¥ä¸‹ä»£ç å°†æŒ‰é’®æ¢å¤ä¸ºæ­£å¸¸çжæ€ï¼š + + \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3 + + \endlist + + 下é¢çš„å±å¹•截图显示了用于å‘用户显示æç¤ºä¿¡æ¯çš„ QMessageBox 对象。 + + \image addressbook-tutorial-part2-add-successful.png + + \c cancel() 函数æ¢å¤ä¸Šæ¬¡æ˜¾ç¤ºçš„è”系人详细信æ¯ï¼Œå¹¶å¯ç”¨ \c addButton,还会éšè— \c submitButton å’Œ + \c cancelButton。 + + \snippet tutorials/addressbook/part2/addressbook.cpp cancel + + 添加è”ç³»äººçš„æ€»ä½“æ€æƒ³å°±æ˜¯æé«˜ç”¨æˆ·æ“ä½œçš„çµæ´»æ€§ï¼Œå¯åœ¨ä»»ä½•时候点击\gui{æäº¤}或\gui{å–æ¶ˆ}。下é¢çš„æµç¨‹å›¾è¯¦ç»†è¯´æ˜Žäº†æ­¤æ¦‚å¿µï¼š + + \image addressbook-tutorial-part2-add-flowchart.png +*/ + +/*! + \page tutorials-addressbook-part3.html + \previouspage 地å€ç°¿ 2 — æ·»åŠ åœ°å€ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part4}{第四章} + \example tutorials/addressbook/part3 + \title 地å€ç°¿ 3 — æµè§ˆåœ°å€ç°¿æ¡ç›® + + 构建地å€ç°¿åº”用程åºçŽ°å·²è¿›å±•è¿‡åŠã€‚我们需è¦å¢žåŠ ä¸€äº›å‡½æ•°ï¼Œä»¥ä¾¿æµè§ˆè”系人。但首先è¦å†³å®šé‡‡ç”¨ä½•ç§æ•°æ®ç»“æž„æ–¹å¼æ¥å‚¨å­˜è¿™äº›è”系人。 + + 在第二章中,我们使用了 QMap é”®-值对,å³è”系人姓å作为\e{é”®},而è”系人地å€ä½œä¸º\e{值}ã€‚è¿™ç§æ–¹å¼å¾ˆé€‚åˆæˆ‘们的实例。ä¸è¿‡ï¼Œè¦æµè§ˆå’Œæ˜¾ç¤ºæ¯ä¸ªæ¡ç›®ï¼Œè¿˜éœ€è¦è¿›è¡Œä¸€äº›æ”¹è¿›ã€‚ + + 我们改进 QMap çš„æ–¹å¼æ˜¯ï¼Œå°†æ•°æ®ç»“构替æ¢ä¸ºç±»ä¼¼å¾ªçŽ¯é“¾æŽ¥çš„åˆ—è¡¨ï¼Œå…¶ä¸­æ‰€æœ‰å…ƒç´ éƒ½æ˜¯ç›¸äº’å…³è”的,包括第一个元素和最åŽä¸€ä¸ªå…ƒç´ ã€‚下图图解说明了该数æ®ç»“构。 + + \image addressbook-tutorial-part3-linkedlist.png + + \section1 定义 AddressBook ç±» + + è¦ç»™åœ°å€ç°¿åº”用程åºå¢žåŠ æµè§ˆåŠŸèƒ½ï¼Œæˆ‘ä»¬éœ€è¦ä¸º \c AddressBook ç±»å†å¢žåŠ ä¸¤ä¸ªå‡½æ•°ï¼š\c next() å’Œ \c previous()。将这两个函数添加到 \c addressbook.h 文件中: + + \snippet tutorials/addressbook/part3/addressbook.h navigation functions + + 我们还需è¦ä½¿ç”¨å…¶ä»–两个 QPushButton 对象,因此将 \c nextButton å’Œ \c previousButton å£°æ˜Žä¸ºç§æœ‰å˜é‡ï¼š + + \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook çš„ \c addressbook.cpp 构造器中,我们实例化 \c nextButton å’Œ \c previousButton,并且这两项默认为ç¦ç”¨ã€‚这是因为仅当地å€ç°¿ä¸­æœ‰å¤šä¸ªè”系人时æ‰ä¼šå¯ç”¨æµè§ˆåŠŸèƒ½ã€‚ + + \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons + + ç„¶åŽï¼Œæˆ‘们将这两个按钮与其相应的槽关è”: + + \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals + + 下图å³ä¸ºé¢„期的图形用户界é¢ã€‚请注æ„,该用户界é¢å·²å¾ˆæŽ¥è¿‘åº”ç”¨ç¨‹åºæœ€ç»ˆçš„æ ·å­ã€‚ + + \image addressbook-tutorial-part3-screenshot.png + + 我们按照 \c next() å’Œ \c previous() 函数的基本规范,将 \c nextButton 放置在å³ä¾§ï¼Œè€Œ \c previousButton 放置在左侧。为了使布局更加直观,我们使用 QHBoxLayout å°† widget 并排放置: + + \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout + + ç„¶åŽï¼Œå°† QHBoxLayout 对象 \c buttonLayout2 增加至 \c mainLayout。 + + \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout + + 下图显示了 widget 在 \c mainLayout ä¸­çš„åæ ‡ä½ç½®ã€‚ + + \image addressbook-tutorial-part3-labeled-layout.png + + 在 \c addContact() 函数中,我们必须ç¦ç”¨è¿™å‡ ä¸ªæŒ‰é’®ï¼Œè¿™æ ·ç”¨æˆ·å°±ä¸ä¼šåœ¨å¢žåŠ è”系人时å°è¯•进行æµè§ˆã€‚ + + \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation + + 此外,在 \c submitContact() 函数中,我们å¯ç”¨äº†æµè§ˆæŒ‰é’® \c nextButton å’Œ \c previousButton,这å–决于 \c contacts 的多少。如上文所述,æµè§ˆåŠŸèƒ½ä»…åœ¨åœ°å€ç°¿ä¸­æœ‰å¤šä¸ªè”系人时æ‰ä¼šå¯ç”¨ã€‚以下代ç è¡Œè¯´æ˜Žäº†å¦‚何实现此功能: + + \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation + + 我们还在 \c cancel() 函数中加入这几行代ç ã€‚ + + 记得我们曾使用 QMap 对象 \c contacts 模拟了一个循环链接的列表。因此,在 \c next() å‡½æ•°ä¸­ï¼Œæˆ‘ä»¬èŽ·å– \c contacts çš„è¿­ä»£å™¨ï¼Œç„¶åŽæ‰§è¡Œä»¥ä¸‹æ“作: + + \list + \o 如果迭代器未达到 \c contacts 结尾,就会增加一。 + \o 如果迭代器已达到 \c contacts 的结尾,就移至 \c contacts 的起始ä½ç½®ã€‚这给人感觉 QMap å°±åƒæ˜¯ä¸€ä¸ªå¾ªçŽ¯é“¾æŽ¥çš„åˆ—è¡¨ã€‚ + \endlist + + \snippet tutorials/addressbook/part3/addressbook.cpp next() function + + 一旦在 \c contacts 中循环至正确的对象,就会通过 \c nameLine å’Œ \c addressText 显示对象的内容。 + + åŒæ ·ï¼Œåœ¨ \c previous() å‡½æ•°ä¸­ï¼Œæˆ‘ä»¬èŽ·å– \c contacts çš„è¿­ä»£å™¨ï¼Œç„¶åŽæ‰§è¡Œä»¥ä¸‹æ“作: + + \list + \o 如果迭代器达到 \c contacts 的结尾,就清除显示内容,然åŽè¿”回。 + \o 如果迭代器在 \c contacts 的起始ä½ç½®ï¼Œå°±å°†å…¶ç§»è‡³ç»“尾。 + \o ç„¶åŽï¼Œå°†è¿­ä»£å™¨å‡ä¸€ã€‚ + \endlist + + \snippet tutorials/addressbook/part3/addressbook.cpp previous() function + + 接ç€ï¼Œé‡æ–°æ˜¾ç¤º \c contacts 中当å‰å¯¹è±¡çš„内容。 +*/ + +/*! + \page tutorials-addressbook-part4.html + \previouspage 地å€ç°¿ 3 — æµè§ˆåœ°å€ç°¿æ¡ç›® + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part5}{第五章} + \example tutorials/addressbook/part4 + \title 地å€ç°¿ 4 — ç¼–è¾‘å’Œåˆ é™¤åœ°å€ + + 在本章中,我们将了解如何修改储存在地å€ç°¿åº”用程åºä¸­çš„è”系人的内容。 + + \image addressbook-tutorial-screenshot.png + + 现有的地å€ç°¿ä¸ä»…å¯ä»¥äº•井有æ¡åœ°å‚¨å­˜è”系人,还å¯è¿›è¡Œæµè§ˆã€‚冿·»åŠ ä¸Šç¼–è¾‘å’Œåˆ é™¤åŠŸèƒ½ï¼Œä»¥ä¾¿åœ¨éœ€è¦æ—¶æ›´æ”¹è”系人的详细信æ¯ï¼Œè¿™æ ·æ›´æ˜“于使用。ä¸è¿‡ï¼Œè¿˜éœ€ä½¿ç”¨ enum 类型进行一些改进。在å‰å‡ ç« ä¸­ï¼Œæˆ‘ä»¬ä½¿ç”¨ä»¥ä¸‹ä¸¤ç§æ¨¡å¼ï¼š\c{AddingMode} å’Œ \c{NavigationMode}。但是,他们并未定义为 enum。我们是采用手动方å¼å¯ç”¨å’Œç¦ç”¨ç›¸åº”的按钮,这就导致有多行é‡å¤çš„代ç ã€‚ + + 在本章中,我们定义带有以下三ç§ä¸åŒå€¼çš„ \c{Mode} enum 类型: + + \list + \o \c{NavigationMode}〠+ \o \c{AddingMode} å’Œ + \o \c{EditingMode}。 + \endlist + + \section1 定义 AddressBook ç±» + + \c addressbook.h æ–‡ä»¶å·²æ›´æ–°ä¸ºåŒ…å« Mode \c enum 类型: + + \snippet tutorials/addressbook/part4/addressbook.h Mode enum + + 我们还è¦å‘当å‰çš„公有槽列表增加两个新槽:\c editContact() å’Œ \c removeContact()。 + + \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots + + 为了在模å¼é—´åˆ‡æ¢ï¼Œæˆ‘们引入了 \c updateInterface() å‡½æ•°æ¥æŽ§åˆ¶æ‰€æœ‰ QPushButton 对象的å¯ç”¨å’Œç¦ç”¨ã€‚è¦å®žçŽ°ä¸Šæ–‡æåŠçš„编辑和删除功能,我们还è¦å¢žåŠ ä¸¤ä¸ªæ–°æŒ‰é’®ï¼š\c editButton å’Œ \c removeButton。 + + \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration + \dots + \snippet tutorials/addressbook/part4/addressbook.h buttons declaration + \dots + \snippet tutorials/addressbook/part4/addressbook.h mode declaration + + 最åŽï¼Œæˆ‘们声明 \c currentMode æ¥è·Ÿè¸ª enum çš„å½“å‰æ¨¡å¼ã€‚ + + \section1 应用 AddressBook ç±» + + 我们现在必须应用地å€ç°¿åº”用程åºçš„æ¨¡å¼æ›´æ”¹åŠŸèƒ½ã€‚\c editButton å’Œ \c removeButton 已实例化并默认为ç¦ç”¨ï¼Œè¿™æ˜¯å› ä¸ºåœ°å€ç°¿å¯åŠ¨æ—¶åœ¨å†…å­˜ä¸­æ²¡æœ‰è”系人。 + + \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons + + 这些按钮会与其相应的槽 \c editContact() å’Œ \c removeContact() å…³è”ï¼Œç„¶åŽæˆ‘们将其添加至 \c buttonLayout1。 + + \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove + \dots + \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout + + 在将模å¼åˆ‡æ¢åˆ° \c EditingMode 之å‰ï¼Œ\c editContact() 函数使用 \c oldName å’Œ \c oldAddress 储存è”系人旧的详细信æ¯ã€‚ 在该模å¼ä¸‹ï¼Œ\c submitButton å’Œ \c cancelButton å‡å·²å¯ç”¨ï¼Œè¿™æ ·ç”¨æˆ·å°±å¯ä»¥æ›´æ”¹è”系人的详细信æ¯å¹¶å¯ç‚¹å‡»ä»»ä½•一个按钮。 + + \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function + + \c submitContact() 函数已被 \c{if-else} 语å¥åˆ†ä¸ºä¸¤éƒ¨åˆ†ã€‚我们查看 \c currentMode 是å¦åœ¨ \c AddingMode 模å¼ä¸‹ã€‚如果是,我们继续添加æ“作。 + + \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning + \dots + \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1 + + å¦åˆ™ï¼Œæˆ‘们查看 \c currentMode 是å¦åœ¨ \c EditingMode 模å¼ä¸‹ã€‚如果是,我们比较 \c oldName å’Œ \c name。如果姓å已更改,我们从 \c contacts 中删除旧的è”系人并æ’入已更新的è”系人。 + + \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2 + + 如果仅更改了地å€ï¼ˆä¾‹å¦‚ \c oldAddress 与 \c address ä¸åŒï¼‰ï¼Œæˆ‘们就更新è”系人的地å€ã€‚最åŽï¼Œæˆ‘们将 \c currentMode 设置为 \c NavigationMode。这一步至关é‡è¦ï¼Œå› ä¸ºå®ƒä¼šé‡æ–°å¯ç”¨æ‰€æœ‰å·²ç¦ç”¨çš„æŒ‰é’®ã€‚ + + è¦ä»Žåœ°å€ç°¿ä¸­åˆ é™¤è”系人,我们采用 \c removeContact() 函数。该函数查看 \c contacts 中是å¦åŒ…å«è¯¥è”系人。 + + \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function + + 如果有,我们显示 QMessageBox,确认用户的删除æ“作。一旦用户确认æ“作,我们调用 \c previous() ç¡®ä¿ç”¨æˆ·ç•Œé¢æ˜¾ç¤ºå…¶ä»–è”ç³»äººï¼Œç„¶åŽæˆ‘们使用 QMap çš„ \l{QMap::remove()}{remove()} 函数删除已已确认的è”系人。出于好æ„,我们会显示 QMessageBox æç¤ºç”¨æˆ·ã€‚在该函数中使用两ç§ä¿¡æ¯æ¡†æ˜¾ç¤ºå¦‚下: + + \image addressbook-tutorial-part4-remove.png + + \section2 æ›´æ–°ç”¨æˆ·ç•Œé¢ + + 我们在上文æåˆ° \c updateInterface() å‡½æ•°ï¼Œå®ƒå¯æ ¹æ®å½“å‰çš„æ¨¡å¼å¯ç”¨å’Œç¦ç”¨æŒ‰é’®ã€‚该函数会根æ®ä¼ é€’给它的 \c mode 傿•°æ›´æ–°å½“å‰çš„æ¨¡å¼ï¼Œåœ¨æ ¡éªŒå€¼ä¹‹å‰å°†å‚数分é…ç»™ \c currentMode。 + + 这样,æ¯ä¸ªæŒ‰é’®å°±æ ¹æ®å½“å‰çš„æ¨¡å¼è¿›è¡Œå¯ç”¨æˆ–ç¦ç”¨ã€‚\c AddingMode å’Œ \c EditingMode çš„ä»£ç æ˜¾ç¤ºå¦‚下: + + \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1 + + ä¸è¿‡å¯¹äºŽ \c NavigationMode,我们在 QPushButton::setEnabled() å‡½æ•°çš„å‚æ•°ä¸­åŠ å…¥äº†æ¡ä»¶ã€‚这样å¯ç¡®ä¿ \c editButton å’Œ \c removeButton 在地å€ç°¿ä¸­è‡³å°‘有一个è”系人的情况下å¯ç”¨ï¼Œè€Œ \c nextButton å’Œ \c previousButton 仅在地å€ç°¿ä¸­æœ‰å¤šä¸ªè”系人时æ‰å¯ç”¨ã€‚ + + \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2 + + 通过在åŒä¸€å‡½æ•°ä¸­è®¾ç½®æ¨¡å¼å’Œæ›´æ–°ç”¨æˆ·ç•Œé¢ï¼Œæˆ‘们å¯ä»¥é¿å…用户界é¢ä¸Žåº”用程åºå†…部状æ€ä¸åŒæ­¥çš„å¯èƒ½æ€§ã€‚ +*/ + +/*! + \page tutorials-addressbook-part5.html + \previouspage 地å€ç°¿ 4 — ç¼–è¾‘å’Œåˆ é™¤åœ°å€ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part6}{第六章} + \example tutorials/addressbook/part5 + \title 地å€ç°¿ 5 — 添加查找功能 + + 在本章中,我们将了解如何在地å€ç°¿åº”用程åºä¸­å®šä½è”系人和地å€ã€‚ + + \image addressbook-tutorial-part5-screenshot.png + + éšç€æˆ‘们䏿–­ä¸ºåœ°å€ç°¿åº”ç”¨ç¨‹åºæ·»åŠ è”系人,使用下一个和上一个按钮æµè§ˆè”系人就会å˜å¾—很ç¹çã€‚åœ¨è¿™ç§æƒ…况下,使用查找函数查找è”系人就会更加有效。上é¢çš„å±å¹•截图显示了查找按钮åŠå…¶åœ¨æŒ‰é’®é¢æ¿ä¸Šçš„ä½ç½®ã€‚ + + å½“ç”¨æˆ·ç‚¹å‡»æŸ¥æ‰¾æŒ‰é’®æ—¶ï¼Œæœ‰å¿…è¦æ˜¾ç¤ºä¸€ä¸ªå¯¹è¯æ¡†ï¼Œç”¨æˆ·å¯åœ¨å…¶ä¸­è¾“å…¥è”系人的姓å。Qt æä¾›äº† QDialog(我们会在本章中将其用作å­ç±»ï¼‰ï¼Œå¯ä½¿ç”¨ \c FindDialog 类。 + + \section1 定义 FindDialog ç±» + + \image addressbook-tutorial-part5-finddialog.png + + è¦ä½¿ç”¨ QDialog çš„å­ç±»ï¼Œæˆ‘们首先è¦åœ¨ \c finddialog.h 文件中声明 QDialog 的头信æ¯ã€‚此外,我们还使用å‘å‰ (forward) 声明æ¥å£°æ˜Ž QLineEdit å’Œ QPushButtonï¼Œè¿™æ ·æˆ‘ä»¬å°±èƒ½åœ¨å¯¹è¯æ¡†ç±»ä¸­ä½¿ç”¨è¿™äº› widget。 + + 因为在 \c AddressBook 类中,\c FindDialog 类包å«äº† Q_OBJECT å®ï¼Œå¹¶ä¸”其构造器已定义为接收父级 QWidget,å³ä½¿å¯¹è¯æ¡†ä»¥å•ç‹¬çš„çª—å£æ–¹å¼æ‰“开。 + + \snippet tutorials/addressbook/part5/finddialog.h FindDialog header + + 我们定义了公有函数 \c getFindText(),供实例化 \c FindDialog 的类使用,这样这些类å¯ä»¥èŽ·å–用户输入的文本。公有槽 \c findClicked() 定义为在用户点击\gui{查找}æŒ‰é’®æ—¶å¤„ç†æœç´¢å­—符串。 + + 最åŽï¼Œæˆ‘ä»¬å®šä¹‰ç§æœ‰å˜é‡ \c findButtonã€\c lineEdit å’Œ \c findText,分别对应\gui{查找}按钮ã€ç”¨æˆ·è¾“å…¥æœç´¢å­—符串的行编辑框和储存æœç´¢å­—符串供ç¨åŽä½¿ç”¨çš„内部字符串。 + + \section1 应用 FindDialog ç±» + + 在 \c FindDialog çš„æž„é€ å™¨ä¸­ï¼Œæˆ‘ä»¬è®¾ç½®ç§æœ‰å˜é‡ \c lineEditã€\c findButton å’Œ \c findText。使用 QHBoxLayout 放置 widget。 + + \snippet tutorials/addressbook/part5/finddialog.cpp constructor + + æˆ‘ä»¬è®¾å®šå¸ƒå±€å’Œçª—å£æ ‡é¢˜ï¼Œå¹¶å°†ä¿¡å·ä¸Žå…¶å„自的槽关è”。请注æ„,\c findButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·å·²ä¸Ž \c findClicked() å’Œ \l{QDialog::accept()}{accept()} å…³è”。QDialog æä¾›çš„ \l{QDialog::accept()}{accept()} 槽会éšè—å¯¹è¯æ¡†å¹¶å°†ç»“果代ç è®¾ç½®ä¸º \l{QDialog::}{Accepted}。我们使用该函数有助于 \c AddressBook çš„ \c findContact() 函数知晓 \c FindDialog 对象关闭的时间。我们在讨论 \c findContact() 函数时将对该函数åšè¿›ä¸€æ­¥è¯´æ˜Žã€‚ + + \image addressbook-tutorial-part5-signals-and-slots.png + + 在 \c findClicked() ä¸­ï¼Œæˆ‘ä»¬éªŒè¯ \c lineEdit 以确ä¿ç”¨æˆ·æ²¡æœ‰åœ¨å°šæœªè¾“å…¥è”ç³»äººå§“åæ—¶å°±ç‚¹å‡»\gui{查找}按钮。然åŽï¼Œæˆ‘们将 \c findText 设置为从 \c lineEdit æå–çš„æœç´¢å­—符串。之åŽï¼Œæˆ‘们清空 \c lineEdit 的内容并éšè—å¯¹è¯æ¡†ã€‚ + + \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function + + \c findText å˜é‡å·²æœ‰å…¬æœ‰ getter 函数 \c getFindText() 与其相关è”。既然我们仅在构造器和 \c findClicked() 函数中直接设定了 \c findText, 我们就ä¸åœ¨åˆ›å»º \c getFindText() çš„åŒæ—¶å†åˆ›å»º setter 函数。由于 \c getFindText() 是公有的,实例化和使用 \c FindDialog 的类å¯å§‹ç»ˆè¯»å–用户已输入并确认的æœç´¢å­—符串。 + + \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function + + \section1 定义 AddressBook ç±» + + è¦ç¡®ä¿æˆ‘们å¯ä½¿ç”¨ \c AddressBook 类中的 \c FindDialog,我们è¦åœ¨ \c addressbook.h æ–‡ä»¶ä¸­åŒ…å« \c finddialog.h。 + + \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header + + 至此,所有地å€ç°¿åŠŸèƒ½éƒ½æœ‰äº† QPushButton å’Œå¯¹åº”çš„æ§½ã€‚åŒæ ·ï¼Œ\gui{Find} 功能有 \c findButton å’Œ \c findContact()。 + + \c findButton å£°æ˜Žä¸ºç§æœ‰å˜é‡ï¼Œè€Œ \c findContact() 函数声明为公有槽。 + + \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration + \dots + \snippet tutorials/addressbook/part5/addressbook.h findButton declaration + + 最åŽï¼Œæˆ‘ä»¬å£°æ˜Žç§æœ‰å˜é‡ \c dialog,用于引用 \c FindDialog 的实例。 + + \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration + + åœ¨å®žä¾‹åŒ–å¯¹è¯æ¡†åŽï¼Œæˆ‘们å¯èƒ½ä¼šå¯¹å…¶è¿›è¡Œå¤šæ¬¡ä½¿ç”¨ã€‚ä½¿ç”¨ç§æœ‰å˜é‡å¯åœ¨ç±»ä¸­ä¸åŒä½ç½®å¯¹å…¶è¿›è¡Œå¤šæ¬¡å¼•用。 + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook ç±»çš„æž„é€ å™¨ä¸­ï¼Œå®žä¾‹åŒ–ç§æœ‰å¯¹è±¡ \c findButton å’Œ \c findDialog: + + \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton + \dots + \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog + + 接下æ¥ï¼Œå°† \c findButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Ž \c findContact() å…³è”。 + + \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find + + 现在唯一è¦å®Œæˆçš„就是 \c findContact() 函数的编ç ï¼š + + \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function + + 我们从显示 \c FindDialog 的实例 \c dialog 开始入手。这时用户开始输入è”系人姓åè¿›è¡ŒæŸ¥æ‰¾ã€‚ç”¨æˆ·ç‚¹å‡»å¯¹è¯æ¡†çš„ \c findButton åŽï¼Œå¯¹è¯æ¡†ä¼šéšè—,并且结果代ç è®¾ç½®ä¸º QDialog::Accepted.这样就确ä¿äº† \c if 语å¥å§‹ç»ˆä¸ºçœŸã€‚ + + ç„¶åŽï¼Œæˆ‘们就开始使用 \c FindDialog çš„ \c getFindText() 函数æå–æœç´¢å­—符串,这个字符串也就是本例中的 \c contactName。如果地å€ç°¿ä¸­æœ‰è”ç³»äººï¼Œå°±ç«‹å³æ˜¾ç¤ºè¯¥è”系人。å¦åˆ™ï¼Œæ˜¾ç¤ºå¦‚下所示的 QMessageBox 表明æœç´¢å¤±è´¥ã€‚ + + \image addressbook-tutorial-part5-notfound.png +*/ + +/*! + \page tutorials-addressbook-part6.html + \previouspage 地å€ç°¿ 5 — 添加查找功能 + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \nextpage {tutorials/addressbook/part7}{第七章} + \example tutorials/addressbook/part6 + \title 地å€ç°¿ 6 — 加载和ä¿å­˜ + + 本章æè¿°äº†ç”¨äºŽç¼–写地å€ç°¿åº”用程åºçš„加载和ä¿å­˜ç¨‹åºæ‰€ä½¿ç”¨çš„ Qt 文件处ç†åŠŸèƒ½ã€‚ + + \image addressbook-tutorial-part6-screenshot.png + + 虽然æµè§ˆå’Œæœç´¢è”系人是éžå¸¸å®žç”¨çš„åŠŸèƒ½ï¼Œä½†åªæœ‰åœ¨å¯ä»¥ä¿å­˜çŽ°æœ‰è”系人并å¯ä»¥åœ¨ä»¥åŽåŠ è½½çš„å‰æä¸‹åœ°å€ç°¿æ‰çœŸæ­£å®Œå…¨å¯ç”¨ã€‚Qt æä¾›å¤§é‡ç”¨äºŽ\l{Input/Output and Networking}{输入和输出}的类,但我们åªé€‰æ‹©ä¸¤ä¸ªæ˜“于åˆå¹¶ä½¿ç”¨çš„类:QFile å’Œ QDataStream。 + + QFile 对象表示ç£ç›˜ä¸Šå¯è¯»å–和写入的文件。QFile 是代表多ç§ä¸åŒè®¾å¤‡ä¸”应用更广的 QIODevice 类的å­ç±»ã€‚ + + QDataStream å¯¹è±¡ç”¨äºŽæŒ‰é¡ºåºæŽ’åˆ—äºŒè¿›åˆ¶æ•°æ®ï¼Œä»¥ä¾¿å‚¨å­˜åœ¨ QIODevice ä¸­å¹¶ä¾›ä»¥åŽæ£€ç´¢ã€‚è¯»å–æˆ–写入 QIODevice å°±å¦‚åŒæ‰“å¼€æ•°æ®æµï¼Œç„¶åŽè¯»å–或写入一样简å•ï¼Œåªæ˜¯å‚数为ä¸åŒçš„设备。 + + + \section1 定义 AddressBook ç±» + + 我们声明两个公有槽 \c saveToFile() å’Œ \c loadFromFile(),以åŠä¸¤ä¸ª QPushButton 对象 \c loadButton å’Œ \c saveButton。 + + \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration + \dots + \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration + + \section1 应用 AddressBook ç±» + + 在构造器中,我们实例化 \c loadButton å’Œ \c saveButtonã€‚ç†æƒ³æƒ…况下,将按钮标签设置为“从文件加载è”系人â€å’Œâ€œå°†è”系人ä¿å­˜è‡³æ–‡ä»¶â€ä¼šæ›´æ–¹ä¾¿ç”¨æˆ·ä½¿ç”¨ã€‚ä¸è¿‡ï¼Œç”±äºŽå…¶ä»–按钮的大å°é™åˆ¶ï¼Œæˆ‘们将标签设置为\gui{加载...}å’Œ\gui{ä¿å­˜...}。幸è¿çš„æ˜¯ï¼ŒQt æä¾›äº†ä½¿ç”¨ \l{QWidget::setToolTip()}{setToolTip()} æ¥è®¾ç½®å·¥å…·æç¤ºçš„ç®€å•æ–¹å¼ï¼Œæˆ‘们å¯é€šè¿‡å¦‚下方å¼å°†å…¶ç”¨äºŽæŒ‰é’®ï¼š + + \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1 + \dots + \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2 + + 虽然此处没有显示,但与其他应用的功能一样,我们在å³ä¾§çš„å¸ƒå±€é¢æ¿ \c button1Layout 上添加按钮,然åŽå°†æŒ‰é’®çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·ä¸Žå…¶ç›¸åº”的槽关è”。 + + 至于ä¿å­˜åŠŸèƒ½ï¼Œæˆ‘ä»¬é¦–å…ˆä½¿ç”¨ QFileDialog::getSaveFileName() èŽ·å– \c fileName。 这是 QFileDialog æä¾›çš„一个便æ·åŠŸèƒ½ï¼Œå¯å¼¹å‡ºæ ·å¼æ–‡ä»¶å¯¹è¯æ¡†å¹¶å…è®¸ç”¨æˆ·è¾“å…¥æ–‡ä»¶åæˆ–选择现有的 \c{.abk} 文件。\c{.abk} 文件是ä¿å­˜è”系人时创建的地å€ç°¿æ‰©å±•å。 + + \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1 + + å¼¹å‡ºçš„æ–‡ä»¶å¯¹è¯æ¡†å±å¹•截图显示如下: + + \image addressbook-tutorial-part6-save.png + + 如果 \c fileName ä¸ä¸ºç©ºï¼Œæˆ‘们就使用 \c fileName 创建 QFile 对象 \c file。 QFile 与 QDataStream 一åŒä½¿ç”¨ï¼Œè¿™æ˜¯å› ä¸ºQFile 是 QIODevice。 + + 接下æ¥ï¼Œæˆ‘们å°è¯•以 \l{QIODevice::}{WriteOnly} æ¨¡å¼æ‰“开文件。如果未能打开,会显示 QMessageBox æç¤ºç”¨æˆ·ã€‚ + + \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2 + + å¦åˆ™ï¼Œä¼šç”¨å®žä¾‹è¡¨ç¤º QDataStream 对象 \c out,以写入打开的文件。QDataStream è¦æ±‚读写æ“作需使用相åŒç‰ˆæœ¬çš„æ•°æ®æµã€‚åœ¨å°†æ•°æ®æŒ‰é¡ºåºå†™å…¥ \c file 之å‰ï¼Œå°†ä½¿ç”¨çš„版本设置为\l{QDataStream::Qt_4_5}{采用 Qt 4.5 的版本}å°±å¯ç¡®ä¿ç‰ˆæœ¬ç›¸åŒã€‚ + + \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3 + + 至于加载功能,我们也是使用 QFileDialog::getOpenFileName() èŽ·å– \c fileName。该函数与 QFileDialog::getSaveFileName() ç›¸å¯¹åº”ï¼Œä¹Ÿæ˜¯å¼¹å‡ºæ ·å¼æ–‡ä»¶å¯¹è¯æ¡†å¹¶å…è®¸ç”¨æˆ·è¾“å…¥æ–‡ä»¶åæˆ–选择现有的 \c{.abk} 文件加载到地å€ç°¿ä¸­ã€‚ + + \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1 + + 例如,在 Windows ä¸Šï¼Œè¯¥å‡½æ•°å¼¹å‡ºæœ¬åœ°æ–‡ä»¶å¯¹è¯æ¡†ï¼Œå¦‚以下å±å¹•截图所示。 + + \image addressbook-tutorial-part6-load.png + + 如果 \c fileName ä¸ä¸ºç©ºï¼Œè¿˜æ˜¯ä½¿ç”¨ QFile 对象 \c file,然åŽå°è¯•在 \l{QIODevice::}{ReadOnly} 模å¼ä¸‹æ‰“开文件。与 \c saveToFile() 的应用方å¼ç±»ä¼¼ï¼Œå¦‚æžœå°è¯•失败,会显示 QMessageBox æç¤ºç”¨æˆ·ã€‚ + + \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2 + + å¦åˆ™ï¼Œä¼šç”¨å®žä¾‹è¡¨ç¤º QDataStream 对象 \c in,按上文所述设置其版本,然åŽå°†æŒ‰é¡ºåºæŽ’列的数æ®è¯»å…¥ \c contacts æ•°æ®ç»“构。请注æ„,在将数æ®è¯»å…¥ä¹‹å‰æ¸…空 \c contacts å¯ç®€åŒ–文件读å–过程。更高级的方法是将è”系人读å–至临时 QMap 对象,然åŽä»…å¤åˆ¶ \c contacts 中ä¸å­˜åœ¨çš„è”系人。 + + \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3 + + è¦æ˜¾ç¤ºä»Žæ–‡ä»¶ä¸­è¯»å–çš„è”系人,必须è¦å…ˆéªŒè¯èŽ·å–的数æ®ï¼Œä»¥ç¡®ä¿è¯»å–的文件实际包å«åœ°å€ç°¿è”系人。如果为真,显示第一个è”系人,å¦åˆ™æ˜¾ç¤º QMessageBox æç¤ºå‡ºçŽ°é—®é¢˜ã€‚æœ€åŽï¼Œæˆ‘们更新界é¢ä»¥ç›¸åº”地å¯ç”¨å’Œç¦ç”¨æŒ‰é’®ã€‚ +*/ + +/*! + \page tutorials-addressbook-part7.html + \previouspage 地å€ç°¿ 6 — 加载和ä¿å­˜ + \contentspage {地å€ç°¿æ•™ç¨‹}{目录} + \example tutorials/addressbook/part7 + \title 地å€ç°¿ 7 — 附加功能 + + 本章讲述了部分å¯ä½¿åœ°å€ç°¿åº”ç”¨ç¨‹åºæ—¥å¸¸ä½¿ç”¨æ›´åŠ ä¾¿æ·çš„附加功能。 + + \image addressbook-tutorial-part7-screenshot.png + + 虽然地å€ç°¿åº”用程åºå…¶è‡ªèº«åŠŸèƒ½å·²ç»å¾ˆå®žç”¨ï¼Œä½†æ˜¯å¦‚æžœå¯å’Œå…¶ä»–应用程åºäº’æ¢è”系人数æ®å°±ä¼šæ›´åŠ æœ‰ç›Šã€‚vCard æ ¼å¼æ˜¯ä¸€ç§æµè¡Œçš„æ–‡ä»¶æ ¼å¼ï¼Œå°±å¯ç”¨äºŽæ­¤ç›®çš„。在本章中,我们会扩展地å€ç°¿å®¢æˆ·ç«¯ï¼Œå¯å°†è”系人导出到 vCard \c{.vcf} 文件中。 + + \section1 定义 AddressBook ç±» + + 我们在 \c addressbook.h 文件的 \c AddressBook 类中添加 QPushButton 对象 \c exportButton 以åŠå¯¹åº”的公有槽 \c exportAsVCard()。 + + \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration + \dots + \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration + + \section1 应用 AddressBook ç±» + + 在 \c AddressBook 构造器中,我们将 \c exportButton çš„ \l{QPushButton::clicked()}{clicked()} ä¿¡å·è¿žæŽ¥è‡³ \c exportAsVCard()。我们还会将该按钮添加至 \c buttonLayout1,它是负责å³ä¾§æŒ‰é’®é¢æ¿çš„布局类。 + + 在 \c exportAsVCard() 函数中,我们从æå– \c name 中è”系人姓å开始入手。我们声明 \c firstNameã€\c lastName å’Œ \c nameList。接下æ¥ï¼Œæˆ‘们查找 \c name 中第一处空白的索引。如果有空白,就将è”系人的姓å分隔为 \c firstName å’Œ lastName。然åŽï¼Œå°†ç©ºç™½æ›¿æ¢ä¸ºä¸‹åˆ’线 ("_")。或者,如果没有空白,就认定è”ç³»äººåªæœ‰å字。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part1 + + 至于 \c saveToFile() å‡½æ•°ï¼Œä¼šæ‰“å¼€æ–‡ä»¶å¯¹è¯æ¡†ï¼Œè®©ç”¨æˆ·é€‰æ‹©æ–‡ä»¶çš„ä½ç½®ã€‚通过选择的文件å称,我们创建è¦å†™å…¥çš„ QFile 实例。 + + 我们å°è¯•以 \l{QIODevice::}{WriteOnly} æ¨¡å¼æ‰“开文件。如果æ“作失败,会显示 QMessageBox æç¤ºç”¨æˆ·å‡ºçŽ°é—®é¢˜å¹¶è¿”å›žã€‚å¦åˆ™ï¼Œå°†æ–‡ä»¶ä½œä¸ºå‚数传递给 QTextStream 对象 \c out。与 QDataStream 类似,QTextStream ç±»æä¾›äº†è¯»å–纯文本和将其写入到文件的功能。因此,所生æˆçš„ \c{.vcf} 文件å¯ä»¥åœ¨æ–‡æœ¬ç¼–辑器中打开进行编辑。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part2 + + ç„¶åŽï¼Œæˆ‘ä»¬å†™å‡ºä¾æ¬¡å¸¦æœ‰ \c{BEGIN:VCARD} å’Œ \c{VERSION:2.1} 标记的 vCard 文件。è”系人的姓å使用 \c{N:} 标记写入。至于写入 vCard “File asâ€å±žæ€§çš„ FN: æ ‡è®°ï¼Œæˆ‘ä»¬å¿…é¡»è¦æŸ¥çœ‹æ˜¯å¦è”系人带有姓。如果è”系人有姓,就使用 \c nameList 中的详细信æ¯å¡«å…¥è¯¥æ ‡è®°ã€‚å¦åˆ™ï¼Œä»…写入 \c firstName。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part3 + + 我们继续写入è”系人的地å€ã€‚地å€ä¸­çš„分å·ä½¿ç”¨ "\\" 进行转义,新行使用分å·è¿›è¡Œæ›¿æ¢ï¼Œè€Œé€—å·ä½¿ç”¨ç©ºç™½è¿›è¡Œæ›¿æ¢ã€‚最åŽï¼Œæˆ‘们便¬¡å†™å…¥ \c{ADR;HOME:;}ã€\c address å’Œ \c{END:VCARD} 标记。 + + \snippet tutorials/addressbook/part7/addressbook.cpp export function part4 + + 最åŽï¼Œä¼šæ˜¾ç¤º QMessageBox æç¤ºç”¨æˆ·å·²æˆåŠŸå¯¼å‡º vCard。 + + \e{vCard 是 \l{http://www.imc.org}{Internet Mail Consortium} 的商标}。 +*/ diff --git a/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc new file mode 100644 index 0000000..0e90210 --- /dev/null +++ b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** 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 documentation 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$ +** +****************************************************************************/ + +/*! + \page widgets-tutorial.html + \title Widgets 教程 + \brief This tutorial covers basic usage of widgets and layouts, showing how + they are used to build GUI applications. + + \startpage {index.html}{Qt Reference Documentation} + \contentspage Tutorials + \nextpage {Widgets 教程 — 创建窗å£} + + + \section1 简介 + + Widget 是使用 Qt ç¼–å†™çš„å›¾å½¢ç”¨æˆ·ç•Œé¢ (GUI) 应用程åºçš„基本生æˆå—。æ¯ä¸ª GUI ç»„ä»¶ï¼Œå¦‚æŒ‰é’®ã€æ ‡ç­¾æˆ–文本编辑器,都是一个 widget ,并å¯ä»¥æ”¾ç½®åœ¨çŽ°æœ‰çš„ç”¨æˆ·ç•Œé¢ä¸­æˆ–作为å•ç‹¬çš„çª—å£æ˜¾ç¤ºã€‚æ¯ç§ç±»åž‹çš„组件都是由 QWidget 的特殊å­ç±»æä¾›çš„,而 QWidget è‡ªèº«åˆæ˜¯ QObject çš„å­ç±»ã€‚ + + QWidget 䏿˜¯ä¸€ä¸ªæŠ½è±¡ç±»ï¼›å®ƒå¯ç”¨ä½œå…¶ä»– widget 的容器,并很容易作为å­ç±»ä½¿ç”¨æ¥åˆ›å»ºå®šåˆ¶ widget。它ç»å¸¸ç”¨æ¥åˆ›å»ºæ”¾ç½®å…¶ä»– widget 的窗å£ã€‚ + + 至于 QObject,å¯ä½¿ç”¨çˆ¶å¯¹è±¡åˆ›å»º widget 以表明其所属关系,这å¯ç¡®ä¿åˆ é™¤ä¸å†ä½¿ç”¨çš„对象。使用 widget,这些父å­å…³ç³»å°±æœ‰äº†æ›´å¤šçš„æ„ä¹‰ï¼šæ¯ä¸ªå­ç±»éƒ½æ˜¾ç¤ºåœ¨å…¶çˆ¶çº§æ‰€æ‹¥æœ‰çš„å±å¹•åŒºåŸŸå†…ã€‚ä¹Ÿå°±æ˜¯è¯´ï¼Œå½“åˆ é™¤çª—å£æ—¶ï¼Œå…¶åŒ…å«çš„æ‰€æœ‰ widget 也都自动删除。 + + \section1 Writing a main Function + + Many of the GUI examples in Qt follow the pattern of having a \c{main.cpp} + file containing code to initialize the application, and a number of other + source and header files containing the application logic and custom GUI + components. + + A typical \c main() function, written in \c{main.cpp}, looks like this: + + \snippet doc/src/snippets/widgets-tutorial/template.cpp main.cpp body + + We first construct a QApplication object which is configured using any + arguments passed in from the command line. After any widgets have been + created and shown, we call QApplication::exec() to start Qt's event loop. + Control passes to Qt until this function returns, at which point we return + the value we obtain from this function. + + In each part of this tutorial, we provide an example that is written + entirely within a \c main() function. In more sophisticated examples, the + code to set up widgets and layouts is written in other parts of the + example. For example, the GUI for a main window may be set up in the + constructor of a QMainWindow subclass. + + The \l{Widgets examples} are a good place to look for + more complex and complete examples and applications. + + \section1 Building Examples and Tutorials + + If you obtained a binary package of Qt or compiled it yourself, the + examples described in this tutorial should already be ready to run. + However, if you may wish to modify them and recompile them, you need to + perform the following steps: + + \list 1 + \o At the command line, enter the directory containing the example you + wish to recompile. + \o Type \c qmake and press \key{Return}. If this doesn't work, make sure + that the executable is on your path, or enter its full location. + \o On Linux/Unix and Mac OS X, type \c make and press \key{Return}; + on Windows with Visual Studio, type \c nmake and press \key{Return}. + \endlist + + An executable file should have been created within the current directory. + On Windows, this file may be located within a \c debug or \c release + subdirectory. You can run this file to see the example code at work. +*/ + +/*! + \page widgets-tutorial-toplevel.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程} + \nextpage {Widgets 教程 — Child Widgets} + \example tutorials/widgets/toplevel + \title Widgets 教程 — åˆ›å»ºçª—å£ + + 如果 widget æœªä½¿ç”¨çˆ¶çº§è¿›è¡Œåˆ›å»ºï¼Œåˆ™åœ¨æ˜¾ç¤ºæ—¶è§†ä¸ºçª—å£æˆ–\e{顶层 widget}。由于顶层 widget 没有父级对象类æ¥ç¡®ä¿åœ¨å…¶ä¸å†ä½¿ç”¨æ—¶å°±åˆ é™¤ï¼Œå› æ­¤éœ€è¦å¼€å‘人员在应用程åºä¸­å¯¹å…¶è¿›è¡Œè·Ÿè¸ªã€‚ + + 在下例中,我们使用 QWidget 创建和显示具有默认大å°çš„窗å£ï¼š + + \raw HTML + + +
    + \endraw + \snippet tutorials/widgets/toplevel/main.cpp main program + \raw HTML + + \endraw + \inlineimage widgets-tutorial-toplevel.png + \raw HTML +
    + \endraw + + To create a real GUI, we need to place widgets inside the window. To do + this, we pass a QWidget instance to a widget's constructor, as we will + demonstrate in the next part of this tutorial. +*/ + +/*! + \page widgets-tutorial-childwidget.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程 — 创建窗å£} + \nextpage {Widgets 教程 — 使用布局} + \example tutorials/widgets/childwidget + \title Widgets 教程 — Child Widgets + + 我们å¯ä»¥é€šè¿‡å°† \c window 作为父级传递给其构造器æ¥å‘çª—å£æ·»åŠ å­ widgetã€‚åœ¨è¿™ç§æƒ…况下,我们å‘çª—å£æ·»åŠ æŒ‰é’®å¹¶å°†å…¶æ”¾ç½®åœ¨ç‰¹å®šä½ç½®ï¼š + + \raw HTML + + +
    + \endraw + \snippet tutorials/widgets/childwidget/main.cpp main program + \raw HTML + + \endraw + \inlineimage widgets-tutorial-childwidget.png + \raw HTML +
    + \endraw + + 该按钮现在为窗å£çš„å­é¡¹ï¼Œå¹¶åœ¨åˆ é™¤çª—壿—¶ä¸€åŒåˆ é™¤ã€‚请注æ„,éšè—或关闭窗å£ä¸ä¼šè‡ªåŠ¨åˆ é™¤è¯¥æŒ‰é’®ã€‚ +*/ + +/*! + \page widgets-tutorial-windowlayout.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程 — Child Widgets} + \nextpage {Widgets 教程 — Nested Layouts} + \example tutorials/widgets/windowlayout + \title Widgets 教程 — 使用布局 + + é€šå¸¸ï¼Œå­ widget 是通过使用布局对象在窗å£ä¸­è¿›è¡ŒæŽ’åˆ—ï¼Œè€Œä¸æ˜¯é€šè¿‡æŒ‡å®šä½ç½®å’Œå¤§å°è¿›è¡ŒæŽ’列。在此处,我们构造è¦å¹¶æŽ’排列的标签和行编辑框 widget。 + + \raw HTML + + +
    + \endraw + \snippet tutorials/widgets/windowlayout/main.cpp main program + \raw HTML + + \endraw + \inlineimage widgets-tutorial-windowlayout.png + \raw HTML +
    + \endraw + + 我们构造的布局对象管ç†é€šè¿‡ \l{QHBoxLayout::}{addWidget()} 函数æä¾›çš„ widget çš„ä½ç½®å’Œå¤§å°ã€‚布局本身是通过调用 \l{QWidget::}{setLayout()} æä¾›ç»™çª—å£çš„。布局仅å¯é€šè¿‡å…¶å¯¹æ‰€ç®¡ç†çš„ widget(和其他布局)的效果æ‰å¯æ˜¾ç¤ºã€‚ + + 在上文示例中,æ¯ä¸ª widget çš„æ‰€å±žå…³ç³»å¹¶ä¸æ˜Žæ˜¾ã€‚由于我们未使用父级对象构造 widget 和布局,我们会看到一个空窗å£å’Œä¸¤ä¸ªåŒ…å«äº†æ ‡ç­¾ä¸Žè¡Œç¼–辑框的窗å£ã€‚ä¸è¿‡ï¼Œå¦‚果我们告知布局æ¥ç®¡ç†æ ‡ç­¾å’Œè¡Œç¼–辑框,并在窗å£ä¸­è®¾ç½®å¸ƒå±€ï¼Œä¸¤ä¸ª widget 与布局本身就都会æˆä¸ºçª—å£çš„å­é¡¹ã€‚ +*/ + +/*! + \page widgets-tutorial-nestedlayouts.html + \contentspage {Widgets 教程}{目录} + \previouspage {Widgets 教程 — 使用布局} + \example tutorials/widgets/nestedlayouts + \title Widgets 教程 - Nested Layouts + + 由于 widget å¯åŒ…å«å…¶ä»– widget,布局å¯ç”¨æ¥æä¾›æŒ‰ä¸åŒå±‚次分组的 widget。这里,我们è¦åœ¨æ˜¾ç¤ºæŸ¥è¯¢ç»“果的表视图上方ã€çª—å£é¡¶éƒ¨çš„行编辑框æ—,显示一个标签。 + + We achieve this by creating two layouts: \c{queryLayout} is a QHBoxLayout + that contains QLabel and QLineEdit widgets placed side-by-side; + \c{mainLayout} is a QVBoxLayout that contains \c{queryLayout} and a + QTableView arranged vertically. + + \raw HTML + + +
    + \endraw + \snippet tutorials/widgets/nestedlayouts/main.cpp first part + \snippet tutorials/widgets/nestedlayouts/main.cpp last part + \raw HTML + + \endraw + \inlineimage widgets-tutorial-nestedlayouts.png + \raw HTML +
    + \endraw + + Note that we call the \c{mainLayout}'s \l{QBoxLayout::}{addLayout()} + function to insert the \c{queryLayout} above the \c{resultView} table. + + We have omitted the code that sets up the model containing the data shown + by the QTableView widget, \c resultView. For completeness, we show this below. + + 除了 QHBoxLayout å’Œ QVBoxLayout,Qt 还æä¾›äº† QGridLayout å’Œ QFormLayout ç±»æ¥ååŠ©å®žçŽ°æ›´å¤æ‚的用户界é¢ã€‚ + These can be seen if you run \l{Qt Designer}. + + \section1 Setting up the Model + + In the code above, we did not show where the table's data came from + because we wanted to concentrate on the use of layouts. Here, we see + that the model holds a number of items corresponding to rows, each of + which is set up to contain data for two columns. + + \snippet tutorials/widgets/nestedlayouts/main.cpp set up the model + + The use of models and views is covered in the + \l{Item Views Examples} and in the \l{Model/View Programming} overview. +*/ diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp index f62ec24..acb1576 100644 --- a/tools/qdoc3/config.cpp +++ b/tools/qdoc3/config.cpp @@ -671,7 +671,9 @@ void Config::load(Location location, const QString& fileName) location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString())); } - QString text = fin.readAll(); + QTextStream stream(&fin); + stream.setCodec("UTF-8"); + QString text = stream.readAll(); text += QLatin1String("\n\n"); text += QChar('\0'); fin.close(); -- cgit v0.12 From 10888061f86eef9a73fff548b6dc325471cbb809 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:02:11 +1000 Subject: Round off volume when converting from real to int. And return a volume of 0 if there's no player control. --- src/multimedia/qml/qmlmediabase.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp index 0f0f1e4..e2a1832 100644 --- a/src/multimedia/qml/qmlmediabase.cpp +++ b/src/multimedia/qml/qmlmediabase.cpp @@ -78,7 +78,7 @@ public: qint64 duration() const { return 0; } qint64 position() const { return 0; } void setPosition(qint64) {} - int volume() const { return 100; } + int volume() const { return 0; } void setVolume(int) {} bool isMuted() const { return false; } void setMuted(bool) {} @@ -267,6 +267,8 @@ void QmlMediaBase::setObject(QObject *object) m_animation = new QmlMediaBaseAnimation(this); } else { + m_error = QMediaPlayer::ServiceMissingError; + m_playerControl = new QmlMediaBasePlayerControl(object); } @@ -337,7 +339,7 @@ qreal QmlMediaBase::volume() const void QmlMediaBase::setVolume(qreal volume) { - m_playerControl->setVolume(volume * 100); + m_playerControl->setVolume(qRound(volume * 100)); } bool QmlMediaBase::isMuted() const -- cgit v0.12 From 275d642215388013247e07d4b351be88422bff41 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:09:07 +1000 Subject: Connect changed signals from QMediaPlayerControl to media QML elements. --- src/multimedia/qml/qmlmediabase.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp index e2a1832..4b42058 100644 --- a/src/multimedia/qml/qmlmediabase.cpp +++ b/src/multimedia/qml/qmlmediabase.cpp @@ -264,6 +264,12 @@ void QmlMediaBase::setObject(QObject *object) object, SIGNAL(volumeChanged())); QObject::connect(m_playerControl, SIGNAL(mutedChanged(bool)), object, SIGNAL(mutedChanged())); + QObject::connect(m_playerControl, SIGNAL(bufferStatusChanged(int)), + object, SIGNAL(bufferProgressChanged())); + QObject::connect(m_playerControl, SIGNAL(seekableChanged(bool)), + object, SIGNAL(seekableChanged())); + QObject::connect(m_playerControl, SIGNAL(playbackRateChanged(qreal)), + object, SIGNAL(playbackRateChanged())); m_animation = new QmlMediaBaseAnimation(this); } else { -- cgit v0.12 From e6c91eacfefcaf9cab83f5cb82d1487b8a870117 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:11:29 +1000 Subject: Propagate error signals from QMediaPlayerControl to media QML elements. --- src/multimedia/qml/qmlaudio.cpp | 4 ++-- src/multimedia/qml/qmlaudio_p.h | 4 ++-- src/multimedia/qml/qmlgraphicsvideo.cpp | 4 ++-- src/multimedia/qml/qmlgraphicsvideo_p.h | 4 ++-- src/multimedia/qml/qmlmediabase.cpp | 9 +++++++++ src/multimedia/qml/qmlmediabase_p.h | 4 +++- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/multimedia/qml/qmlaudio.cpp b/src/multimedia/qml/qmlaudio.cpp index 713e36a..adff49b 100644 --- a/src/multimedia/qml/qmlaudio.cpp +++ b/src/multimedia/qml/qmlaudio.cpp @@ -58,9 +58,9 @@ QML_DEFINE_TYPE(Qt,4,6,Audio,QmlAudio); \brief The QmlAudio class provides a audio item that you can add to a QmlView. */ -void QmlAudio::_q_error(QMediaPlayer::Error errorCode, const QString &errorString) +void QmlAudio::_q_error(int errorCode, const QString &errorString) { - m_error = errorCode; + m_error = QMediaPlayer::Error(errorCode); m_errorString = errorString; emit error(Error(errorCode), errorString); diff --git a/src/multimedia/qml/qmlaudio_p.h b/src/multimedia/qml/qmlaudio_p.h index c6ab53d..f034518 100644 --- a/src/multimedia/qml/qmlaudio_p.h +++ b/src/multimedia/qml/qmlaudio_p.h @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QTimerEvent; -class QmlAudio : public QObject, public QmlMediaBase, public QmlParserStatus +class Q_AUTOTEST_EXPORT QmlAudio : public QObject, public QmlMediaBase, public QmlParserStatus { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -142,7 +142,7 @@ Q_SIGNALS: void error(QmlAudio::Error error, const QString &errorString); private Q_SLOTS: - void _q_error(QMediaPlayer::Error, const QString &); + void _q_error(int, const QString &); private: Q_DISABLE_COPY(QmlAudio) diff --git a/src/multimedia/qml/qmlgraphicsvideo.cpp b/src/multimedia/qml/qmlgraphicsvideo.cpp index c96f7e9..784c7b6 100644 --- a/src/multimedia/qml/qmlgraphicsvideo.cpp +++ b/src/multimedia/qml/qmlgraphicsvideo.cpp @@ -59,9 +59,9 @@ void QmlGraphicsVideo::_q_nativeSizeChanged(const QSizeF &size) setImplicitHeight(size.height()); } -void QmlGraphicsVideo::_q_error(QMediaPlayer::Error errorCode, const QString &errorString) +void QmlGraphicsVideo::_q_error(int errorCode, const QString &errorString) { - m_error = errorCode; + m_error = QMediaPlayer::Error(errorCode); m_errorString = errorString; emit error(Error(errorCode), errorString); diff --git a/src/multimedia/qml/qmlgraphicsvideo_p.h b/src/multimedia/qml/qmlgraphicsvideo_p.h index d89de8c..4592e31 100644 --- a/src/multimedia/qml/qmlgraphicsvideo_p.h +++ b/src/multimedia/qml/qmlgraphicsvideo_p.h @@ -58,7 +58,7 @@ class QTimerEvent; class QVideoSurfaceFormat; -class QmlGraphicsVideo : public QmlGraphicsItem, public QmlMediaBase +class Q_AUTOTEST_EXPORT QmlGraphicsVideo : public QmlGraphicsItem, public QmlMediaBase { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -170,7 +170,7 @@ protected: private Q_SLOTS: void _q_nativeSizeChanged(const QSizeF &size); - void _q_error(QMediaPlayer::Error, const QString &); + void _q_error(int, const QString &); private: Q_DISABLE_COPY(QmlGraphicsVideo) diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp index 4b42058..17ec8a6 100644 --- a/src/multimedia/qml/qmlmediabase.cpp +++ b/src/multimedia/qml/qmlmediabase.cpp @@ -270,6 +270,8 @@ void QmlMediaBase::setObject(QObject *object) object, SIGNAL(seekableChanged())); QObject::connect(m_playerControl, SIGNAL(playbackRateChanged(qreal)), object, SIGNAL(playbackRateChanged())); + QObject::connect(m_playerControl, SIGNAL(error(int,QString)), + object, SLOT(_q_error(int,QString))); m_animation = new QmlMediaBaseAnimation(this); } else { @@ -293,6 +295,13 @@ QUrl QmlMediaBase::source() const void QmlMediaBase::setSource(const QUrl &url) { + if (m_error != QMediaPlayer::ServiceMissingError && m_error != QMediaPlayer::NoError) { + m_error = QMediaPlayer::NoError; + m_errorString = QString(); + + emit errorChanged(); + } + m_playerControl->setMedia(QMediaContent(url), 0); } diff --git a/src/multimedia/qml/qmlmediabase_p.h b/src/multimedia/qml/qmlmediabase_p.h index 3b5c398..d6c0a00 100644 --- a/src/multimedia/qml/qmlmediabase_p.h +++ b/src/multimedia/qml/qmlmediabase_p.h @@ -57,7 +57,7 @@ class QMetaDataControl; class QMetaDataControlMetaObject; class QmlMediaBaseAnimation; -class QmlMediaBase +class Q_AUTOTEST_EXPORT QmlMediaBase { public: QmlMediaBase(); @@ -131,6 +131,8 @@ protected: virtual void seekableChanged() = 0; virtual void playbackRateChanged() = 0; + virtual void errorChanged() = 0; + QMediaService *m_mediaService; QMediaPlayerControl *m_playerControl; -- cgit v0.12 From 5fae580d87add7fab16a9bda20bcc5e42df02879 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:13:24 +1000 Subject: Don't emit the metaDataChanged signal twice on a meta-data write. The QMetaDataControl implementation will emeit the changed signal when appropriate, so it's not necessary to emit it in QMetaDataControlMetaObject as well. --- src/multimedia/qml/qmetadatacontrolmetaobject.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp index 6b0164b..c4b2b42 100644 --- a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp +++ b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp @@ -213,8 +213,8 @@ namespace QMetaDataControlMetaObject::QMetaDataControlMetaObject(QMetaDataControl *control, QObject *object) : m_control(control) , m_object(object) - , m_data(0) , m_string(0) + , m_data(0) , m_propertyOffset(0) , m_signalOffset(0) { @@ -343,8 +343,6 @@ int QMetaDataControlMetaObject::metaCall(QMetaObject::Call c, int id, void **a) m_control->setMetaData(qt_metaDataKeys[propId].key, *reinterpret_cast(a[0])); - activate(m_object, m_signalOffset, 0); - return -1; } else { return m_object->qt_metacall(c, id, a); -- cgit v0.12 From 1b9b3fc62da13adc667890a84c61cc873fb941c0 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:16:31 +1000 Subject: Make the paused property of the QML media elements indepent of playing. --- src/multimedia/qml/qmlaudio.cpp | 17 ++++++++- src/multimedia/qml/qmlgraphicsvideo.cpp | 15 ++++++++ src/multimedia/qml/qmlmediabase.cpp | 65 +++++++++++++++++++++------------ src/multimedia/qml/qmlmediabase_p.h | 1 + 4 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/multimedia/qml/qmlaudio.cpp b/src/multimedia/qml/qmlaudio.cpp index adff49b..f56b6c3 100644 --- a/src/multimedia/qml/qmlaudio.cpp +++ b/src/multimedia/qml/qmlaudio.cpp @@ -86,8 +86,13 @@ QmlAudio::~QmlAudio() */ void QmlAudio::play() -{ +{ m_playerControl->play(); + + if (m_paused) { + m_paused = false; + emit pausedChanged(); + } } /*! @@ -99,6 +104,11 @@ void QmlAudio::play() void QmlAudio::pause() { m_playerControl->pause(); + + if (!m_paused && m_state == QMediaPlayer::PausedState) { + m_paused = true; + emit pausedChanged(); + } } /*! @@ -110,6 +120,11 @@ void QmlAudio::pause() void QmlAudio::stop() { m_playerControl->stop(); + + if (m_paused) { + m_paused = false; + emit pausedChanged(); + } } /*! diff --git a/src/multimedia/qml/qmlgraphicsvideo.cpp b/src/multimedia/qml/qmlgraphicsvideo.cpp index 784c7b6..2889793 100644 --- a/src/multimedia/qml/qmlgraphicsvideo.cpp +++ b/src/multimedia/qml/qmlgraphicsvideo.cpp @@ -338,6 +338,11 @@ void QmlGraphicsVideo::setFillMode(FillMode mode) void QmlGraphicsVideo::play() { m_playerControl->play(); + + if (m_paused) { + m_paused = false; + emit pausedChanged(); + } } /*! @@ -349,6 +354,11 @@ void QmlGraphicsVideo::play() void QmlGraphicsVideo::pause() { m_playerControl->pause(); + + if (!m_paused && m_state == QMediaPlayer::PausedState) { + m_paused = true; + emit pausedChanged(); + } } /*! @@ -360,6 +370,11 @@ void QmlGraphicsVideo::pause() void QmlGraphicsVideo::stop() { m_playerControl->stop(); + + if (m_paused) { + m_paused = false; + emit pausedChanged(); + } } void QmlGraphicsVideo::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp index 17ec8a6..17be240 100644 --- a/src/multimedia/qml/qmlmediabase.cpp +++ b/src/multimedia/qml/qmlmediabase.cpp @@ -132,28 +132,33 @@ private: void QmlMediaBase::_q_stateChanged(QMediaPlayer::State state) { if (state != m_state) { - QMediaPlayer::State oldState = state; + QMediaPlayer::State oldState = m_state; m_state = state; - switch (state) { - case QMediaPlayer::PlayingState: - if (oldState == QMediaPlayer::StoppedState) - emit started(); - else if (oldState == QMediaPlayer::PausedState) - emit resumed(); - break; - case QMediaPlayer::PausedState: - emit paused(); - case QMediaPlayer::StoppedState: + if (state == QMediaPlayer::StoppedState) { emit stopped(); - break; - default: - break; + emit playingChanged(); + } else if (oldState == QMediaPlayer::StoppedState) { + emit started(); + emit playingChanged(); + } else if (oldState == QMediaPlayer::PausedState) { + m_paused = false; + + emit resumed(); + emit pausedChanged(); } - emit playingChanged(); - emit pausedChanged(); + if (state == m_state && state == QMediaPlayer::PausedState) { + bool wasPaused = m_paused; + + m_paused = true; + + emit paused(); + + if (!wasPaused) + emit pausedChanged(); + } if (m_state == QMediaPlayer::PlayingState || m_status == QMediaPlayer::BufferingMedia @@ -218,6 +223,7 @@ QmlMediaBase::QmlMediaBase() , m_state(QMediaPlayer::StoppedState) , m_status(QMediaPlayer::NoMedia) , m_error(QMediaPlayer::NoError) + , m_paused(false) { } @@ -312,23 +318,34 @@ bool QmlMediaBase::isPlaying() const void QmlMediaBase::setPlaying(bool playing) { - if (playing && m_state == QMediaPlayer::StoppedState) - m_playerControl->play(); - else if (!playing) + if (playing && m_state == QMediaPlayer::StoppedState) { + if (m_paused) + m_playerControl->pause(); + else + m_playerControl->play(); + } else if (!playing) { m_playerControl->stop(); + } } bool QmlMediaBase::isPaused() const { - return m_state == QMediaPlayer::PausedState; + return m_paused; } void QmlMediaBase::setPaused(bool paused) { - if (paused && m_state == QMediaPlayer::PlayingState) - m_playerControl->pause(); - if (!paused && m_state == QMediaPlayer::PausedState) - m_playerControl->play(); + if (m_paused != paused) { + if (paused && m_state == QMediaPlayer::PlayingState) { + m_playerControl->pause(); + } else if (!paused && m_state == QMediaPlayer::PausedState) { + m_playerControl->play(); + } else { + m_paused = paused; + + emit pausedChanged(); + } + } } int QmlMediaBase::duration() const diff --git a/src/multimedia/qml/qmlmediabase_p.h b/src/multimedia/qml/qmlmediabase_p.h index d6c0a00..873e4c3 100644 --- a/src/multimedia/qml/qmlmediabase_p.h +++ b/src/multimedia/qml/qmlmediabase_p.h @@ -145,6 +145,7 @@ protected: QMediaPlayer::State m_state; QMediaPlayer::MediaStatus m_status; QMediaPlayer::Error m_error; + bool m_paused; QString m_errorString; friend class QmlMediaBaseAnimation; -- cgit v0.12 From 49797723461c812ebe2f53da0583323d0314d02a Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:20:06 +1000 Subject: Remove deprecated enum and member variables from video graphics items. --- src/multimedia/base/qgraphicsvideoitem.h | 7 ------- src/multimedia/qml/qmlgraphicsvideo.cpp | 1 - src/multimedia/qml/qmlgraphicsvideo_p.h | 4 ---- 3 files changed, 12 deletions(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.h b/src/multimedia/base/qgraphicsvideoitem.h index ac215ea..f8cffdc 100644 --- a/src/multimedia/base/qgraphicsvideoitem.h +++ b/src/multimedia/base/qgraphicsvideoitem.h @@ -63,13 +63,6 @@ class Q_MULTIMEDIA_EXPORT QGraphicsVideoItem : public QGraphicsObject Q_PROPERTY(QSizeF size READ size WRITE setSize) Q_PROPERTY(QSizeF nativeSize READ nativeSize NOTIFY nativeSizeChanged) public: - enum FillMode - { - Stretch, - PreserveAspectFit, - PreserveAspectCrop - }; - QGraphicsVideoItem(QGraphicsItem *parent = 0); ~QGraphicsVideoItem(); diff --git a/src/multimedia/qml/qmlgraphicsvideo.cpp b/src/multimedia/qml/qmlgraphicsvideo.cpp index 2889793..f6a5eff 100644 --- a/src/multimedia/qml/qmlgraphicsvideo.cpp +++ b/src/multimedia/qml/qmlgraphicsvideo.cpp @@ -84,7 +84,6 @@ void QmlGraphicsVideo::_q_error(int errorCode, const QString &errorString) QmlGraphicsVideo::QmlGraphicsVideo(QmlGraphicsItem *parent) : QmlGraphicsItem(parent) , m_graphicsItem(0) - , m_fillMode(QmlGraphicsVideo::PreserveAspectFit) { m_graphicsItem = new QGraphicsVideoItem(this); diff --git a/src/multimedia/qml/qmlgraphicsvideo_p.h b/src/multimedia/qml/qmlgraphicsvideo_p.h index 4592e31..a4f8e32 100644 --- a/src/multimedia/qml/qmlgraphicsvideo_p.h +++ b/src/multimedia/qml/qmlgraphicsvideo_p.h @@ -177,10 +177,6 @@ private: QGraphicsVideoItem *m_graphicsItem; - FillMode m_fillMode; - QRectF m_scaledRect; - bool m_updatePaintDevice; - Q_PRIVATE_SLOT(mediaBase(), void _q_stateChanged(QMediaPlayer::State)) Q_PRIVATE_SLOT(mediaBase(), void _q_mediaStatusChanged(QMediaPlayer::MediaStatus)) Q_PRIVATE_SLOT(mediaBase(), void _q_metaDataChanged()) -- cgit v0.12 From f4646f4810983536cbf0084cd1e5c6dc9a5b2a5d Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:22:59 +1000 Subject: Add an internal function for setting the default media servie provider. This allows auto tests to override the default service provider. --- src/multimedia/base/qmediaserviceprovider.cpp | 23 +++++++++++++++++++++++ src/multimedia/base/qmediaserviceprovider.h | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/src/multimedia/base/qmediaserviceprovider.cpp b/src/multimedia/base/qmediaserviceprovider.cpp index f7c4e1f..3b8dd2c 100644 --- a/src/multimedia/base/qmediaserviceprovider.cpp +++ b/src/multimedia/base/qmediaserviceprovider.cpp @@ -563,12 +563,35 @@ QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, return QString(); } + +#ifdef QT_BUILD_INTERNAL + +static QMediaServiceProvider *qt_defaultMediaServiceProvider = 0; + +/*! + Sets a media service \a provider as the default. + + \internal +*/ +void QMediaServiceProvider::setDefaultServiceProvider(QMediaServiceProvider *provider) +{ + qt_defaultMediaServiceProvider = provider; +} + +#endif + /*! Returns a default provider of media services. */ QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider() { +#ifdef QT_BUILD_INTERNAL + return qt_defaultMediaServiceProvider != 0 + ? qt_defaultMediaServiceProvider + : static_cast(pluginProvider()); +#else return pluginProvider(); +#endif } /*! diff --git a/src/multimedia/base/qmediaserviceprovider.h b/src/multimedia/base/qmediaserviceprovider.h index 46f63b5..f108d32 100644 --- a/src/multimedia/base/qmediaserviceprovider.h +++ b/src/multimedia/base/qmediaserviceprovider.h @@ -115,6 +115,10 @@ public: virtual QString deviceDescription(const QByteArray &serviceType, const QByteArray &device); static QMediaServiceProvider* defaultServiceProvider(); + +#ifdef QT_BUILD_INTERNAL + static void setDefaultServiceProvider(QMediaServiceProvider *provider); +#endif }; /*! -- cgit v0.12 From 3d4297d5ea3006a135d07e0634be4a186f06ced4 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:35:00 +1000 Subject: Fix license headers. --- src/multimedia/qml/qmlmediabase_p.h | 4 ++-- tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/multimedia/qml/qmlmediabase_p.h b/src/multimedia/qml/qmlmediabase_p.h index 873e4c3..948a0e8 100644 --- a/src/multimedia/qml/qmlmediabase_p.h +++ b/src/multimedia/qml/qmlmediabase_p.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp index 19433e4..2427d64 100644 --- a/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp +++ b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage -- cgit v0.12 From 6fea41c4deb23b6c0f43d05e9b4fd958d06be584 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 5 Feb 2010 11:36:22 +1000 Subject: Add tests for QML media elements. --- tests/auto/qmlaudio/qmlaudio.pro | 6 + tests/auto/qmlaudio/tst_qmlaudio.cpp | 1200 ++++++++++++++++++++ tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro | 6 + .../auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp | 911 +++++++++++++++ 4 files changed, 2123 insertions(+) create mode 100644 tests/auto/qmlaudio/qmlaudio.pro create mode 100644 tests/auto/qmlaudio/tst_qmlaudio.cpp create mode 100644 tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro create mode 100644 tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp diff --git a/tests/auto/qmlaudio/qmlaudio.pro b/tests/auto/qmlaudio/qmlaudio.pro new file mode 100644 index 0000000..4581e80 --- /dev/null +++ b/tests/auto/qmlaudio/qmlaudio.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qmlaudio.cpp + +QT += multimedia +requires(contains(QT_CONFIG, multimedia)) +requires(contains(QT_CONFIG, declarative)) diff --git a/tests/auto/qmlaudio/tst_qmlaudio.cpp b/tests/auto/qmlaudio/tst_qmlaudio.cpp new file mode 100644 index 0000000..cb205ac --- /dev/null +++ b/tests/auto/qmlaudio/tst_qmlaudio.cpp @@ -0,0 +1,1200 @@ +/**************************************************************************** +** +** 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 + +#include + +#include +#include +#include +#include + + +class tst_QmlAudio : public QObject +{ + Q_OBJECT +public slots: + void initTestCase(); + +private slots: + void nullPlayerControl(); + void nullMetaDataControl(); + void nullService(); + + void source(); + void playing(); + void paused(); + void duration(); + void position(); + void volume(); + void muted(); + void bufferProgress(); + void seekable(); + void playbackRate(); + void status(); + void metaData_data(); + void metaData(); + void error(); +}; + +Q_DECLARE_METATYPE(QtMedia::MetaData); +Q_DECLARE_METATYPE(QmlAudio::Error); + +class QtTestMediaPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + QtTestMediaPlayerControl(QObject *parent = 0) + : QMediaPlayerControl(parent) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_duration(0) + , m_position(0) + , m_playbackRate(1.0) + , m_volume(50) + , m_bufferStatus(0) + , m_muted(false) + , m_audioAvailable(false) + , m_videoAvailable(false) + , m_seekable(false) + { + } + + QMediaPlayer::State state() const { return m_state; } + void updateState(QMediaPlayer::State state) { emit stateChanged(m_state = state); } + + QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; } + void updateMediaStatus(QMediaPlayer::MediaStatus status) { + emit mediaStatusChanged(m_mediaStatus = status); } + void updateMediaStatus(QMediaPlayer::MediaStatus status, QMediaPlayer::State state) + { + m_mediaStatus = status; + m_state = state; + + emit mediaStatusChanged(m_mediaStatus); + emit stateChanged(m_state); + } + + qint64 duration() const { return m_duration; } + void setDuration(qint64 duration) { emit durationChanged(m_duration = duration); } + + qint64 position() const { return m_position; } + void setPosition(qint64 position) { emit positionChanged(m_position = position); } + + int volume() const { return m_volume; } + void setVolume(int volume) { emit volumeChanged(m_volume = volume); } + + bool isMuted() const { return m_muted; } + void setMuted(bool muted) { emit mutedChanged(m_muted = muted); } + + int bufferStatus() const { return m_bufferStatus; } + void setBufferStatus(int status) { emit bufferStatusChanged(m_bufferStatus = status); } + + bool isAudioAvailable() const { return m_audioAvailable; } + void setAudioAvailable(bool available) { + emit audioAvailableChanged(m_audioAvailable = available); } + bool isVideoAvailable() const { return m_videoAvailable; } + void setVideoAvailable(bool available) { + emit videoAvailableChanged(m_videoAvailable = available); } + + bool isSeekable() const { return m_seekable; } + void setSeekable(bool seekable) { emit seekableChanged(m_seekable = seekable); } + + QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); } + + qreal playbackRate() const { return m_playbackRate; } + void setPlaybackRate(qreal rate) { emit playbackRateChanged(m_playbackRate = rate); } + + QMediaContent media() const { return m_media; } + const QIODevice *mediaStream() const { return 0; } + void setMedia(const QMediaContent &media, QIODevice *) + { + m_media = media; + + m_mediaStatus = m_media.isNull() + ? QMediaPlayer::NoMedia + : QMediaPlayer::LoadingMedia; + + emit mediaChanged(m_media); + emit mediaStatusChanged(m_mediaStatus); + } + + void play() { emit stateChanged(m_state = QMediaPlayer::PlayingState); } + void pause() { emit stateChanged(m_state = QMediaPlayer::PausedState); } + void stop() { emit stateChanged(m_state = QMediaPlayer::StoppedState); } + + void emitError(QMediaPlayer::Error err, const QString &errorString) { + emit error(err, errorString); } + +private: + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + qint64 m_duration; + qint64 m_position; + qreal m_playbackRate; + int m_volume; + int m_bufferStatus; + bool m_muted; + bool m_audioAvailable; + bool m_videoAvailable; + bool m_seekable; + QMediaContent m_media; +}; + +class QtTestMetaDataControl : public QMetaDataControl +{ + Q_OBJECT +public: + QtTestMetaDataControl(QObject *parent = 0) + : QMetaDataControl(parent) + { + } + + bool isWritable() const { return true; } + bool isMetaDataAvailable() const { return true; } + + QVariant metaData(QtMedia::MetaData key) const { return m_metaData.value(key); } + void setMetaData(QtMedia::MetaData key, const QVariant &value) { + m_metaData.insert(key, value); emit metaDataChanged(); } + void setMetaData(const QMap &metaData) { + m_metaData = metaData; emit metaDataChanged(); } + + QList availableMetaData() const { return m_metaData.keys(); } + + QVariant extendedMetaData(const QString &) const { return QVariant(); } + void setExtendedMetaData(const QString &, const QVariant &) {} + QStringList availableExtendedMetaData() const { return QStringList(); } + +private: + QMap m_metaData; +}; + +class QtTestMediaService : public QMediaService +{ + Q_OBJECT +public: + QtTestMediaService( + QtTestMediaPlayerControl *playerControl, + QtTestMetaDataControl *metaDataControl, + QObject *parent) + : QMediaService(parent) + , playerControl(playerControl) + , metaDataControl(metaDataControl) + { + } + + QMediaControl *control(const char *name) const + { + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return playerControl; + else if (qstrcmp(name, QMetaDataControl_iid) == 0) + return metaDataControl; + else + return 0; + } + + QtTestMediaPlayerControl *playerControl; + QtTestMetaDataControl *metaDataControl; +}; + +class QtTestMediaServiceProvider : public QMediaServiceProvider +{ + Q_OBJECT +public: + QtTestMediaServiceProvider() + : service(new QtTestMediaService( + new QtTestMediaPlayerControl(this), new QtTestMetaDataControl(this), this)) + { + setDefaultServiceProvider(this); + } + + QtTestMediaServiceProvider(QtTestMediaService *service) + : service(service) + { + setDefaultServiceProvider(this); + } + + QtTestMediaServiceProvider( + QtTestMediaPlayerControl *playerControl, QtTestMetaDataControl *metaDataControl) + : service(new QtTestMediaService(playerControl, metaDataControl, this)) + { + setDefaultServiceProvider(this); + } + + ~QtTestMediaServiceProvider() + { + setDefaultServiceProvider(0); + } + + QMediaService *requestService( + const QByteArray &type, + const QMediaServiceProviderHint & = QMediaServiceProviderHint()) + { + requestedService = type; + + return service; + } + + void releaseService(QMediaService *) {} + + inline QtTestMediaPlayerControl *playerControl() { return service->playerControl; } + inline QtTestMetaDataControl *metaDataControl() { return service->metaDataControl; } + + QtTestMediaService *service; + QByteArray requestedService; +}; + + +void tst_QmlAudio::initTestCase() +{ + qRegisterMetaType(); +} + +void tst_QmlAudio::nullPlayerControl() +{ + QtTestMetaDataControl metaDataControl; + QtTestMediaServiceProvider provider(0, &metaDataControl); + + QmlAudio audio; + + QCOMPARE(audio.source(), QUrl()); + audio.setSource(QUrl("http://example.com")); + QCOMPARE(audio.source(), QUrl()); + + QCOMPARE(audio.isPlaying(), false); + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), false); + audio.play(); + QCOMPARE(audio.isPlaying(), false); + + QCOMPARE(audio.isPaused(), false); + audio.pause(); + QCOMPARE(audio.isPaused(), false); + audio.setPaused(true); + QCOMPARE(audio.isPaused(), true); + + QCOMPARE(audio.duration(), 0); + + QCOMPARE(audio.position(), 0); + audio.setPosition(10000); + QCOMPARE(audio.position(), 0); + + QCOMPARE(audio.volume(), qreal(0)); + audio.setVolume(50); + QCOMPARE(audio.volume(), qreal(0)); + + QCOMPARE(audio.isMuted(), false); + audio.setMuted(true); + QCOMPARE(audio.isMuted(), false); + + QCOMPARE(audio.bufferProgress(), qreal(0)); + + QCOMPARE(audio.isSeekable(), false); + + QCOMPARE(audio.playbackRate(), qreal(1.0)); + + QCOMPARE(audio.status(), QmlAudio::NoMedia); + + QCOMPARE(audio.error(), QmlAudio::ServiceMissing); +} + +void tst_QmlAudio::nullMetaDataControl() +{ + QtTestMediaPlayerControl playerControl; + QtTestMediaServiceProvider provider(&playerControl, 0); + + QmlAudio audio; + + QCOMPARE(audio.metaObject()->indexOfProperty("title"), -1); + QCOMPARE(audio.metaObject()->indexOfProperty("genre"), -1); + QCOMPARE(audio.metaObject()->indexOfProperty("description"), -1); +} + +void tst_QmlAudio::nullService() +{ + QtTestMediaServiceProvider provider(0); + + QmlAudio audio; + + QCOMPARE(audio.source(), QUrl()); + audio.setSource(QUrl("http://example.com")); + QCOMPARE(audio.source(), QUrl()); + + QCOMPARE(audio.isPlaying(), false); + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), false); + audio.play(); + QCOMPARE(audio.isPlaying(), false); + + QCOMPARE(audio.isPaused(), false); + audio.pause(); + QCOMPARE(audio.isPaused(), false); + audio.setPaused(true); + QCOMPARE(audio.isPaused(), true); + + QCOMPARE(audio.duration(), 0); + + QCOMPARE(audio.position(), 0); + audio.setPosition(10000); + QCOMPARE(audio.position(), 0); + + QCOMPARE(audio.volume(), qreal(0)); + audio.setVolume(50); + QCOMPARE(audio.volume(), qreal(0)); + + QCOMPARE(audio.isMuted(), false); + audio.setMuted(true); + QCOMPARE(audio.isMuted(), false); + + QCOMPARE(audio.bufferProgress(), qreal(0)); + + QCOMPARE(audio.isSeekable(), false); + + QCOMPARE(audio.playbackRate(), qreal(1.0)); + + QCOMPARE(audio.status(), QmlAudio::NoMedia); + + QCOMPARE(audio.error(), QmlAudio::ServiceMissing); + + QCOMPARE(audio.metaObject()->indexOfProperty("title"), -1); + QCOMPARE(audio.metaObject()->indexOfProperty("genre"), -1); + QCOMPARE(audio.metaObject()->indexOfProperty("description"), -1); +} + +void tst_QmlAudio::source() +{ + const QUrl url1("http://example.com"); + const QUrl url2("file:///local/path"); + const QUrl url3; + + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(sourceChanged())); + + audio.setSource(url1); + QCOMPARE(audio.source(), url1); + QCOMPARE(provider.playerControl()->media().canonicalUrl(), url1); + QCOMPARE(spy.count(), 1); + + audio.setSource(url2); + QCOMPARE(audio.source(), url2); + QCOMPARE(provider.playerControl()->media().canonicalUrl(), url2); + QCOMPARE(spy.count(), 2); + + audio.setSource(url3); + QCOMPARE(audio.source(), url3); + QCOMPARE(provider.playerControl()->media().canonicalUrl(), url3); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlAudio::playing() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy playingChangedSpy(&audio, SIGNAL(playingChanged())); + QSignalSpy startedSpy(&audio, SIGNAL(started())); + QSignalSpy stoppedSpy(&audio, SIGNAL(stopped())); + + int playingChanged = 0; + int started = 0; + int stopped = 0; + + QCOMPARE(audio.isPlaying(), false); + + // setPlaying(true) when stopped. + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when playing. + audio.setPlaying(false); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // play() when stopped. + audio.play(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(stoppedSpy.count(), stopped); + + // stop() when playing. + audio.stop(); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // stop() when stopped. + audio.stop(); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when stopped. + audio.setPlaying(false); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); + + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(true) when playing. + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); + + // play() when playing. + audio.play(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); +} + +void tst_QmlAudio::paused() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy playingChangedSpy(&audio, SIGNAL(playingChanged())); + QSignalSpy pausedChangedSpy(&audio, SIGNAL(pausedChanged())); + QSignalSpy startedSpy(&audio, SIGNAL(started())); + QSignalSpy pausedSpy(&audio, SIGNAL(paused())); + QSignalSpy resumedSpy(&audio, SIGNAL(resumed())); + QSignalSpy stoppedSpy(&audio, SIGNAL(stopped())); + + int playingChanged = 0; + int pausedChanged = 0; + int started = 0; + int paused = 0; + int resumed = 0; + int stopped = 0; + + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), false); + + // setPlaying(true) when stopped. + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when playing. + audio.setPaused(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when paused. + audio.setPaused(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // pause() when paused. + audio.pause(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(false) when paused. + audio.setPaused(false); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), ++resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(false) when playing. + audio.setPaused(false); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // pause() when playing. + audio.pause(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when paused. + audio.setPlaying(false); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // setPaused(true) when stopped and paused. + audio.setPaused(true); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(false) when stopped and paused. + audio.setPaused(false); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when stopped. + audio.setPaused(true); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(true) when stopped and paused. + audio.setPlaying(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // play() when paused. + audio.play(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), ++resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when playing. + audio.setPaused(true); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // stop() when paused. + audio.stop(); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // setPaused(true) when stopped. + audio.setPaused(true); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // stop() when stopped and paused. + audio.stop(); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // pause() when stopped. + audio.pause(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when paused. + audio.setPlaying(false); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // pause() when stopped and paused. + audio.pause(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when paused. + audio.setPlaying(false); + QCOMPARE(audio.isPlaying(), false); + QCOMPARE(audio.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // play() when stopped and paused. + audio.play(); + QCOMPARE(audio.isPlaying(), true); + QCOMPARE(audio.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); +} + +void tst_QmlAudio::duration() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(durationChanged())); + + QCOMPARE(audio.duration(), 0); + + provider.playerControl()->setDuration(4040); + QCOMPARE(audio.duration(), 4040); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setDuration(-129); + QCOMPARE(audio.duration(), -129); + QCOMPARE(spy.count(), 2); + + provider.playerControl()->setDuration(0); + QCOMPARE(audio.duration(), 0); + QCOMPARE(spy.count(), 3); + + // Unnecessary duration changed signals aren't filtered. + provider.playerControl()->setDuration(0); + QCOMPARE(audio.duration(), 0); + QCOMPARE(spy.count(), 4); +} + +void tst_QmlAudio::position() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(positionChanged())); + + QCOMPARE(audio.position(), 0); + + // QmlAudio won't bound set positions to the duration. A media service may though. + QCOMPARE(audio.duration(), 0); + + audio.setPosition(450); + QCOMPARE(audio.position(), 450); + QCOMPARE(provider.playerControl()->position(), qint64(450)); + QCOMPARE(spy.count(), 1); + + audio.setPosition(-5403); + QCOMPARE(audio.position(), -5403); + QCOMPARE(provider.playerControl()->position(), qint64(-5403)); + QCOMPARE(spy.count(), 2); + + audio.setPosition(-5403); + QCOMPARE(audio.position(), -5403); + QCOMPARE(provider.playerControl()->position(), qint64(-5403)); + QCOMPARE(spy.count(), 3); + + // Check the signal change signal is emitted if the change originates from the media service. + provider.playerControl()->setPosition(0); + QCOMPARE(audio.position(), 0); + QCOMPARE(spy.count(), 4); + + connect(&audio, SIGNAL(positionChanged()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + provider.playerControl()->updateState(QMediaPlayer::PlayingState); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(spy.count() > 4 && spy.count() < 7); // 5 or 6 + + provider.playerControl()->updateState(QMediaPlayer::PausedState); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(spy.count() < 7); +} + +void tst_QmlAudio::volume() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(volumeChanged())); + + QCOMPARE(audio.volume(), qreal(0.5)); + + audio.setVolume(0.7); + QCOMPARE(audio.volume(), qreal(0.7)); + QCOMPARE(provider.playerControl()->volume(), 70); + QCOMPARE(spy.count(), 1); + + audio.setVolume(0.7); + QCOMPARE(audio.volume(), qreal(0.7)); + QCOMPARE(provider.playerControl()->volume(), 70); + QCOMPARE(spy.count(), 2); + + provider.playerControl()->setVolume(30); + QCOMPARE(audio.volume(), qreal(0.3)); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlAudio::muted() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(mutedChanged())); + + QCOMPARE(audio.isMuted(), false); + + audio.setMuted(true); + QCOMPARE(audio.isMuted(), true); + QCOMPARE(provider.playerControl()->isMuted(), true); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setMuted(false); + QCOMPARE(audio.isMuted(), false); + QCOMPARE(spy.count(), 2); + + audio.setMuted(false); + QCOMPARE(audio.isMuted(), false); + QCOMPARE(provider.playerControl()->isMuted(), false); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlAudio::bufferProgress() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(bufferProgressChanged())); + + QCOMPARE(audio.bufferProgress(), qreal(0.0)); + + provider.playerControl()->setBufferStatus(20); + QCOMPARE(audio.bufferProgress(), qreal(0.2)); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setBufferStatus(20); + QCOMPARE(audio.bufferProgress(), qreal(0.2)); + QCOMPARE(spy.count(), 2); + + provider.playerControl()->setBufferStatus(40); + QCOMPARE(audio.bufferProgress(), qreal(0.4)); + QCOMPARE(spy.count(), 3); + + connect(&audio, SIGNAL(positionChanged()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + provider.playerControl()->updateMediaStatus( + QMediaPlayer::BufferingMedia, QMediaPlayer::PlayingState); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(spy.count() > 3 && spy.count() < 6); // 4 or 5 + + provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferedMedia); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(spy.count() < 6); +} + +void tst_QmlAudio::seekable() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(seekableChanged())); + + QCOMPARE(audio.isSeekable(), false); + + provider.playerControl()->setSeekable(true); + QCOMPARE(audio.isSeekable(), true); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setSeekable(true); + QCOMPARE(audio.isSeekable(), true); + QCOMPARE(spy.count(), 2); + + provider.playerControl()->setSeekable(false); + QCOMPARE(audio.isSeekable(), false); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlAudio::playbackRate() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(playbackRateChanged())); + + QCOMPARE(audio.playbackRate(), qreal(1.0)); + + audio.setPlaybackRate(0.5); + QCOMPARE(audio.playbackRate(), qreal(0.5)); + QCOMPARE(provider.playerControl()->playbackRate(), qreal(0.5)); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setPlaybackRate(2.0); + QCOMPARE(provider.playerControl()->playbackRate(), qreal(2.0)); + QCOMPARE(spy.count(), 2); + + audio.setPlaybackRate(2.0); + QCOMPARE(audio.playbackRate(), qreal(2.0)); + QCOMPARE(provider.playerControl()->playbackRate(), qreal(2.0)); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlAudio::status() +{ + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy statusChangedSpy(&audio, SIGNAL(statusChanged())); + QSignalSpy loadedSpy(&audio, SIGNAL(loaded())); + QSignalSpy bufferingSpy(&audio, SIGNAL(buffering())); + QSignalSpy stalledSpy(&audio, SIGNAL(stalled())); + QSignalSpy bufferedSpy(&audio, SIGNAL(buffered())); + QSignalSpy endOfMediaSpy(&audio, SIGNAL(endOfMedia())); + + QCOMPARE(audio.status(), QmlAudio::NoMedia); + + // Set media, start loading. + provider.playerControl()->updateMediaStatus(QMediaPlayer::LoadingMedia); + QCOMPARE(audio.status(), QmlAudio::Loading); + QCOMPARE(statusChangedSpy.count(), 1); + QCOMPARE(loadedSpy.count(), 0); + QCOMPARE(bufferingSpy.count(), 0); + QCOMPARE(stalledSpy.count(), 0); + QCOMPARE(bufferedSpy.count(), 0); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Finish loading. + provider.playerControl()->updateMediaStatus(QMediaPlayer::LoadedMedia); + QCOMPARE(audio.status(), QmlAudio::Loaded); + QCOMPARE(statusChangedSpy.count(), 2); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 0); + QCOMPARE(stalledSpy.count(), 0); + QCOMPARE(bufferedSpy.count(), 0); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Play, start buffering. + provider.playerControl()->updateMediaStatus( + QMediaPlayer::StalledMedia, QMediaPlayer::PlayingState); + QCOMPARE(audio.status(), QmlAudio::Stalled); + QCOMPARE(statusChangedSpy.count(), 3); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 0); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 0); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Enough data buffered to proceed. + provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferingMedia); + QCOMPARE(audio.status(), QmlAudio::Buffering); + QCOMPARE(statusChangedSpy.count(), 4); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 1); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 0); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Errant second buffering status changed. + provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferingMedia); + QCOMPARE(audio.status(), QmlAudio::Buffering); + QCOMPARE(statusChangedSpy.count(), 4); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 1); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 0); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Buffer full. + provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferedMedia); + QCOMPARE(audio.status(), QmlAudio::Buffered); + QCOMPARE(statusChangedSpy.count(), 5); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 1); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 1); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Buffer getting low. + provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferingMedia); + QCOMPARE(audio.status(), QmlAudio::Buffering); + QCOMPARE(statusChangedSpy.count(), 6); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 2); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 1); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Buffer full. + provider.playerControl()->updateMediaStatus(QMediaPlayer::BufferedMedia); + QCOMPARE(audio.status(), QmlAudio::Buffered); + QCOMPARE(statusChangedSpy.count(), 7); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 2); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 2); + QCOMPARE(endOfMediaSpy.count(), 0); + + // Finished. + provider.playerControl()->updateMediaStatus( + QMediaPlayer::EndOfMedia, QMediaPlayer::StoppedState); + QCOMPARE(audio.status(), QmlAudio::EndOfMedia); + QCOMPARE(statusChangedSpy.count(), 8); + QCOMPARE(loadedSpy.count(), 1); + QCOMPARE(bufferingSpy.count(), 2); + QCOMPARE(stalledSpy.count(), 1); + QCOMPARE(bufferedSpy.count(), 2); + QCOMPARE(endOfMediaSpy.count(), 1); +} + +void tst_QmlAudio::metaData_data() +{ + QTest::addColumn("propertyName"); + QTest::addColumn("propertyKey"); + QTest::addColumn("value1"); + QTest::addColumn("value2"); + + QTest::newRow("title") + << QByteArray("title") + << QtMedia::Title + << QVariant(QString::fromLatin1("This is a title")) + << QVariant(QString::fromLatin1("This is another title")); + + QTest::newRow("genre") + << QByteArray("genre") + << QtMedia::Genre + << QVariant(QString::fromLatin1("rock")) + << QVariant(QString::fromLatin1("pop")); + + QTest::newRow("trackNumber") + << QByteArray("trackNumber") + << QtMedia::TrackNumber + << QVariant(8) + << QVariant(12); +} + +void tst_QmlAudio::metaData() +{ + QFETCH(QByteArray, propertyName); + QFETCH(QtMedia::MetaData, propertyKey); + QFETCH(QVariant, value1); + QFETCH(QVariant, value2); + + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy spy(&audio, SIGNAL(__metaDataChanged())); + + const int index = audio.metaObject()->indexOfProperty(propertyName.constData()); + QVERIFY(index != -1); + + QMetaProperty property = audio.metaObject()->property(index); + QCOMPARE(property.read(&audio), QVariant()); + + property.write(&audio, value1); + QCOMPARE(property.read(&audio), value1); + QCOMPARE(provider.metaDataControl()->metaData(propertyKey), value1); + QCOMPARE(spy.count(), 1); + + provider.metaDataControl()->setMetaData(propertyKey, value2); + QCOMPARE(property.read(&audio), value2); + QCOMPARE(spy.count(), 2); +} + +void tst_QmlAudio::error() +{ + const QString errorString = QLatin1String("Failed to open device."); + + QtTestMediaServiceProvider provider; + QmlAudio audio; + + QSignalSpy errorSpy(&audio, SIGNAL(error(QmlAudio::Error,QString))); + QSignalSpy errorChangedSpy(&audio, SIGNAL(errorChanged())); + + QCOMPARE(audio.error(), QmlAudio::NoError); + QCOMPARE(audio.errorString(), QString()); + + provider.playerControl()->emitError(QMediaPlayer::ResourceError, errorString); + + QCOMPARE(audio.error(), QmlAudio::ResourceError); + QCOMPARE(audio.errorString(), errorString); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorChangedSpy.count(), 1); + + // Changing the source resets the error properties. + audio.setSource(QUrl("http://example.com")); + QCOMPARE(audio.error(), QmlAudio::NoError); + QCOMPARE(audio.errorString(), QString()); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorChangedSpy.count(), 2); + + // But isn't noisy. + audio.setSource(QUrl("file:///file/path")); + QCOMPARE(audio.error(), QmlAudio::NoError); + QCOMPARE(audio.errorString(), QString()); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorChangedSpy.count(), 2); +} + + +QTEST_MAIN(tst_QmlAudio) + +#include "tst_qmlaudio.moc" diff --git a/tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro b/tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro new file mode 100644 index 0000000..994b8fe --- /dev/null +++ b/tests/auto/qmlgraphicsvideo/qmlgraphicsvideo.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qmlgraphicsvideo.cpp + +QT += multimedia +requires(contains(QT_CONFIG, multimedia)) +requires(contains(QT_CONFIG, declarative)) diff --git a/tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp b/tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp new file mode 100644 index 0000000..a09a6a2 --- /dev/null +++ b/tests/auto/qmlgraphicsvideo/tst_qmlgraphicsvideo.cpp @@ -0,0 +1,911 @@ +/**************************************************************************** +** +** 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +class tst_QmlGraphicsVideo : public QObject +{ + Q_OBJECT +public slots: + void initTestCase(); + +private slots: + void nullPlayerControl(); + void nullService(); + + void playing(); + void paused(); + void error(); + + void hasAudio(); + void hasVideo(); + void fillMode(); + void geometry(); +}; + +Q_DECLARE_METATYPE(QtMedia::MetaData); +Q_DECLARE_METATYPE(QmlGraphicsVideo::Error); + +class QtTestMediaPlayerControl : public QMediaPlayerControl +{ + Q_OBJECT +public: + QtTestMediaPlayerControl(QObject *parent = 0) + : QMediaPlayerControl(parent) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_duration(0) + , m_position(0) + , m_playbackRate(1.0) + , m_volume(50) + , m_bufferStatus(0) + , m_muted(false) + , m_audioAvailable(false) + , m_videoAvailable(false) + , m_seekable(false) + { + } + + QMediaPlayer::State state() const { return m_state; } + void updateState(QMediaPlayer::State state) { emit stateChanged(m_state = state); } + + QMediaPlayer::MediaStatus mediaStatus() const { return m_mediaStatus; } + void updateMediaStatus(QMediaPlayer::MediaStatus status) { + emit mediaStatusChanged(m_mediaStatus = status); } + void updateMediaStatus(QMediaPlayer::MediaStatus status, QMediaPlayer::State state) + { + m_mediaStatus = status; + m_state = state; + + emit mediaStatusChanged(m_mediaStatus); + emit stateChanged(m_state); + } + + qint64 duration() const { return m_duration; } + void setDuration(qint64 duration) { emit durationChanged(m_duration = duration); } + + qint64 position() const { return m_position; } + void setPosition(qint64 position) { emit positionChanged(m_position = position); } + + int volume() const { return m_volume; } + void setVolume(int volume) { emit volumeChanged(m_volume = volume); } + + bool isMuted() const { return m_muted; } + void setMuted(bool muted) { emit mutedChanged(m_muted = muted); } + + int bufferStatus() const { return m_bufferStatus; } + void setBufferStatus(int status) { emit bufferStatusChanged(m_bufferStatus = status); } + + bool isAudioAvailable() const { return m_audioAvailable; } + void setAudioAvailable(bool available) { + emit audioAvailableChanged(m_audioAvailable = available); } + bool isVideoAvailable() const { return m_videoAvailable; } + void setVideoAvailable(bool available) { + emit videoAvailableChanged(m_videoAvailable = available); } + + bool isSeekable() const { return m_seekable; } + void setSeekable(bool seekable) { emit seekableChanged(m_seekable = seekable); } + + QMediaTimeRange availablePlaybackRanges() const { return QMediaTimeRange(); } + + qreal playbackRate() const { return m_playbackRate; } + void setPlaybackRate(qreal rate) { emit playbackRateChanged(m_playbackRate = rate); } + + QMediaContent media() const { return m_media; } + const QIODevice *mediaStream() const { return 0; } + void setMedia(const QMediaContent &media, QIODevice *) + { + m_media = media; + + m_mediaStatus = m_media.isNull() + ? QMediaPlayer::NoMedia + : QMediaPlayer::LoadingMedia; + + emit mediaChanged(m_media); + emit mediaStatusChanged(m_mediaStatus); + } + + void play() { emit stateChanged(m_state = QMediaPlayer::PlayingState); } + void pause() { emit stateChanged(m_state = QMediaPlayer::PausedState); } + void stop() { emit stateChanged(m_state = QMediaPlayer::StoppedState); } + + void emitError(QMediaPlayer::Error err, const QString &errorString) { + emit error(err, errorString); } + +private: + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + qint64 m_duration; + qint64 m_position; + qreal m_playbackRate; + int m_volume; + int m_bufferStatus; + bool m_muted; + bool m_audioAvailable; + bool m_videoAvailable; + bool m_seekable; + QMediaContent m_media; +}; + +class QtTestOutputControl : public QVideoOutputControl +{ +public: + QtTestOutputControl(QObject *parent) : QVideoOutputControl(parent), m_output(NoOutput) {} + + QList availableOutputs() const { return m_outputs; } + void setAvailableOutputs(const QList outputs) { m_outputs = outputs; } + + Output output() const { return m_output; } + virtual void setOutput(Output output) { m_output = output; } + +private: + Output m_output; + QList m_outputs; +}; + +class QtTestRendererControl : public QVideoRendererControl +{ +public: + QtTestRendererControl(QObject *parent ) : QVideoRendererControl(parent), m_surface(0) {} + + QAbstractVideoSurface *surface() const { return m_surface; } + void setSurface(QAbstractVideoSurface *surface) { m_surface = surface; } + +private: + QAbstractVideoSurface *m_surface; +}; + +class QtTestMediaService : public QMediaService +{ + Q_OBJECT +public: + QtTestMediaService( + QtTestMediaPlayerControl *playerControl, + QtTestOutputControl *outputControl, + QtTestRendererControl *rendererControl, + QObject *parent) + : QMediaService(parent) + , playerControl(playerControl) + , outputControl(outputControl) + , rendererControl(rendererControl) + { + } + + QMediaControl *control(const char *name) const + { + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return playerControl; + else if (qstrcmp(name, QVideoOutputControl_iid) == 0) + return outputControl; + else if (qstrcmp(name, QVideoRendererControl_iid) == 0) + return rendererControl; + else + return 0; + } + + QtTestMediaPlayerControl *playerControl; + QtTestOutputControl *outputControl; + QtTestRendererControl *rendererControl; +}; + +class QtTestMediaServiceProvider : public QMediaServiceProvider +{ + Q_OBJECT +public: + QtTestMediaServiceProvider() + : service(new QtTestMediaService( + new QtTestMediaPlayerControl(this), + new QtTestOutputControl(this), + new QtTestRendererControl(this), + this)) + { + setDefaultServiceProvider(this); + } + + QtTestMediaServiceProvider(QtTestMediaService *service) + : service(service) + { + setDefaultServiceProvider(this); + } + + QtTestMediaServiceProvider( + QtTestMediaPlayerControl *playerControl, + QtTestOutputControl *outputControl, + QtTestRendererControl *rendererControl) + : service(new QtTestMediaService(playerControl, outputControl, rendererControl, this)) + { + setDefaultServiceProvider(this); + } + + ~QtTestMediaServiceProvider() + { + setDefaultServiceProvider(0); + } + + QMediaService *requestService( + const QByteArray &type, + const QMediaServiceProviderHint & = QMediaServiceProviderHint()) + { + requestedService = type; + + return service; + } + + void releaseService(QMediaService *) {} + + inline QtTestMediaPlayerControl *playerControl() { return service->playerControl; } + inline QtTestRendererControl *rendererControl() { return service->rendererControl; } + + QtTestMediaService *service; + QByteArray requestedService; +}; + + +void tst_QmlGraphicsVideo::initTestCase() +{ + qRegisterMetaType(); +} + +void tst_QmlGraphicsVideo::nullPlayerControl() +{ + QtTestMediaServiceProvider provider(0, 0, 0); + + QmlGraphicsVideo video; + + QCOMPARE(video.source(), QUrl()); + video.setSource(QUrl("http://example.com")); + QCOMPARE(video.source(), QUrl()); + + QCOMPARE(video.isPlaying(), false); + video.setPlaying(true); + QCOMPARE(video.isPlaying(), false); + video.play(); + QCOMPARE(video.isPlaying(), false); + + QCOMPARE(video.isPaused(), false); + video.pause(); + QCOMPARE(video.isPaused(), false); + video.setPaused(true); + QCOMPARE(video.isPaused(), true); + + QCOMPARE(video.duration(), 0); + + QCOMPARE(video.position(), 0); + video.setPosition(10000); + QCOMPARE(video.position(), 0); + + QCOMPARE(video.volume(), qreal(0)); + video.setVolume(50); + QCOMPARE(video.volume(), qreal(0)); + + QCOMPARE(video.isMuted(), false); + video.setMuted(true); + QCOMPARE(video.isMuted(), false); + + QCOMPARE(video.bufferProgress(), qreal(0)); + + QCOMPARE(video.isSeekable(), false); + + QCOMPARE(video.playbackRate(), qreal(1.0)); + + QCOMPARE(video.hasAudio(), false); + QCOMPARE(video.hasVideo(), false); + + QCOMPARE(video.status(), QmlGraphicsVideo::NoMedia); + + QCOMPARE(video.error(), QmlGraphicsVideo::ServiceMissing); +} + +void tst_QmlGraphicsVideo::nullService() +{ + QtTestMediaServiceProvider provider(0); + + QmlGraphicsVideo video; + + QCOMPARE(video.source(), QUrl()); + video.setSource(QUrl("http://example.com")); + QCOMPARE(video.source(), QUrl()); + + QCOMPARE(video.isPlaying(), false); + video.setPlaying(true); + QCOMPARE(video.isPlaying(), false); + video.play(); + QCOMPARE(video.isPlaying(), false); + + QCOMPARE(video.isPaused(), false); + video.pause(); + QCOMPARE(video.isPaused(), false); + video.setPaused(true); + QCOMPARE(video.isPaused(), true); + + QCOMPARE(video.duration(), 0); + + QCOMPARE(video.position(), 0); + video.setPosition(10000); + QCOMPARE(video.position(), 0); + + QCOMPARE(video.volume(), qreal(0)); + video.setVolume(50); + QCOMPARE(video.volume(), qreal(0)); + + QCOMPARE(video.isMuted(), false); + video.setMuted(true); + QCOMPARE(video.isMuted(), false); + + QCOMPARE(video.bufferProgress(), qreal(0)); + + QCOMPARE(video.isSeekable(), false); + + QCOMPARE(video.playbackRate(), qreal(1.0)); + + QCOMPARE(video.hasAudio(), false); + QCOMPARE(video.hasVideo(), false); + + QCOMPARE(video.status(), QmlGraphicsVideo::NoMedia); + + QCOMPARE(video.error(), QmlGraphicsVideo::ServiceMissing); + + QCOMPARE(video.metaObject()->indexOfProperty("title"), -1); + QCOMPARE(video.metaObject()->indexOfProperty("genre"), -1); + QCOMPARE(video.metaObject()->indexOfProperty("description"), -1); +} + +void tst_QmlGraphicsVideo::playing() +{ + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QSignalSpy playingChangedSpy(&video, SIGNAL(playingChanged())); + QSignalSpy startedSpy(&video, SIGNAL(started())); + QSignalSpy stoppedSpy(&video, SIGNAL(stopped())); + + int playingChanged = 0; + int started = 0; + int stopped = 0; + + QCOMPARE(video.isPlaying(), false); + + // setPlaying(true) when stopped. + video.setPlaying(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when playing. + video.setPlaying(false); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // play() when stopped. + video.play(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(stoppedSpy.count(), stopped); + + // stop() when playing. + video.stop(); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // stop() when stopped. + video.stop(); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when stopped. + video.setPlaying(false); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); + + video.setPlaying(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(true) when playing. + video.setPlaying(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); + + // play() when playing. + video.play(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(stoppedSpy.count(), stopped); +} + +void tst_QmlGraphicsVideo::paused() +{ + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QSignalSpy playingChangedSpy(&video, SIGNAL(playingChanged())); + QSignalSpy pausedChangedSpy(&video, SIGNAL(pausedChanged())); + QSignalSpy startedSpy(&video, SIGNAL(started())); + QSignalSpy pausedSpy(&video, SIGNAL(paused())); + QSignalSpy resumedSpy(&video, SIGNAL(resumed())); + QSignalSpy stoppedSpy(&video, SIGNAL(stopped())); + + int playingChanged = 0; + int pausedChanged = 0; + int started = 0; + int paused = 0; + int resumed = 0; + int stopped = 0; + + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), false); + + // setPlaying(true) when stopped. + video.setPlaying(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when playing. + video.setPaused(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when paused. + video.setPaused(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // pause() when paused. + video.pause(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(false) when paused. + video.setPaused(false); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), ++resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(false) when playing. + video.setPaused(false); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // pause() when playing. + video.pause(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when paused. + video.setPlaying(false); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // setPaused(true) when stopped and paused. + video.setPaused(true); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(false) when stopped and paused. + video.setPaused(false); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when stopped. + video.setPaused(true); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(true) when stopped and paused. + video.setPlaying(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // play() when paused. + video.play(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), ++resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPaused(true) when playing. + video.setPaused(true); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // stop() when paused. + video.stop(); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // setPaused(true) when stopped. + video.setPaused(true); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // stop() when stopped and paused. + video.stop(); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // pause() when stopped. + video.pause(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when paused. + video.setPlaying(false); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // pause() when stopped and paused. + video.pause(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PausedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), ++paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); + + // setPlaying(false) when paused. + video.setPlaying(false); + QCOMPARE(video.isPlaying(), false); + QCOMPARE(video.isPaused(), true); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::StoppedState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), pausedChanged); + QCOMPARE(startedSpy.count(), started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), ++stopped); + + // play() when stopped and paused. + video.play(); + QCOMPARE(video.isPlaying(), true); + QCOMPARE(video.isPaused(), false); + QCOMPARE(provider.playerControl()->state(), QMediaPlayer::PlayingState); + QCOMPARE(playingChangedSpy.count(), ++playingChanged); + QCOMPARE(pausedChangedSpy.count(), ++pausedChanged); + QCOMPARE(startedSpy.count(), ++started); + QCOMPARE(pausedSpy.count(), paused); + QCOMPARE(resumedSpy.count(), resumed); + QCOMPARE(stoppedSpy.count(), stopped); +} + +void tst_QmlGraphicsVideo::error() +{ + const QString errorString = QLatin1String("Failed to open device."); + + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QSignalSpy errorSpy(&video, SIGNAL(error(QmlGraphicsVideo::Error,QString))); + QSignalSpy errorChangedSpy(&video, SIGNAL(errorChanged())); + + QCOMPARE(video.error(), QmlGraphicsVideo::NoError); + QCOMPARE(video.errorString(), QString()); + + provider.playerControl()->emitError(QMediaPlayer::ResourceError, errorString); + + QCOMPARE(video.error(), QmlGraphicsVideo::ResourceError); + QCOMPARE(video.errorString(), errorString); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorChangedSpy.count(), 1); + + // Changing the source resets the error properties. + video.setSource(QUrl("http://example.com")); + QCOMPARE(video.error(), QmlGraphicsVideo::NoError); + QCOMPARE(video.errorString(), QString()); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorChangedSpy.count(), 2); + + // But isn't noisy. + video.setSource(QUrl("file:///file/path")); + QCOMPARE(video.error(), QmlGraphicsVideo::NoError); + QCOMPARE(video.errorString(), QString()); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorChangedSpy.count(), 2); +} + + +void tst_QmlGraphicsVideo::hasAudio() +{ + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QSignalSpy spy(&video, SIGNAL(hasAudioChanged())); + + QCOMPARE(video.hasAudio(), false); + + provider.playerControl()->setAudioAvailable(true); + QCOMPARE(video.hasAudio(), true); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setAudioAvailable(true); + QCOMPARE(video.hasAudio(), true); + QCOMPARE(spy.count(), 2); + + provider.playerControl()->setAudioAvailable(false); + QCOMPARE(video.hasAudio(), false); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlGraphicsVideo::hasVideo() +{ + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QSignalSpy spy(&video, SIGNAL(hasVideoChanged())); + + QCOMPARE(video.hasVideo(), false); + + provider.playerControl()->setVideoAvailable(true); + QCOMPARE(video.hasVideo(), true); + QCOMPARE(spy.count(), 1); + + provider.playerControl()->setVideoAvailable(true); + QCOMPARE(video.hasVideo(), true); + QCOMPARE(spy.count(), 2); + + provider.playerControl()->setVideoAvailable(false); + QCOMPARE(video.hasVideo(), false); + QCOMPARE(spy.count(), 3); +} + +void tst_QmlGraphicsVideo::fillMode() +{ + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QList children = video.childItems(); + QCOMPARE(children.count(), 1); + QGraphicsVideoItem *videoItem = qgraphicsitem_cast(children.first()); + QVERIFY(videoItem != 0); + + QCOMPARE(video.fillMode(), QmlGraphicsVideo::PreserveAspectFit); + + video.setFillMode(QmlGraphicsVideo::PreserveAspectCrop); + QCOMPARE(video.fillMode(), QmlGraphicsVideo::PreserveAspectCrop); + QCOMPARE(videoItem->aspectRatioMode(), Qt::KeepAspectRatioByExpanding); + + video.setFillMode(QmlGraphicsVideo::Stretch); + QCOMPARE(video.fillMode(), QmlGraphicsVideo::Stretch); + QCOMPARE(videoItem->aspectRatioMode(), Qt::IgnoreAspectRatio); + + video.setFillMode(QmlGraphicsVideo::PreserveAspectFit); + QCOMPARE(video.fillMode(), QmlGraphicsVideo::PreserveAspectFit); + QCOMPARE(videoItem->aspectRatioMode(), Qt::KeepAspectRatio); +} + +void tst_QmlGraphicsVideo::geometry() +{ + QtTestMediaServiceProvider provider; + QmlGraphicsVideo video; + + QAbstractVideoSurface *surface = provider.rendererControl()->surface(); + QVERIFY(surface != 0); + + QList children = video.childItems(); + QCOMPARE(children.count(), 1); + QGraphicsVideoItem *videoItem = qgraphicsitem_cast(children.first()); + QVERIFY(videoItem != 0); + + QVideoSurfaceFormat format(QSize(640, 480), QVideoFrame::Format_RGB32); + + QVERIFY(surface->start(format)); + + QCOMPARE(video.implicitWidth(), qreal(640)); + QCOMPARE(video.implicitHeight(), qreal(480)); + + video.setWidth(560); + video.setHeight(328); + + QCOMPARE(videoItem->size().width(), qreal(560)); + QCOMPARE(videoItem->size().height(), qreal(328)); +} + +QTEST_MAIN(tst_QmlGraphicsVideo) + +#include "tst_qmlgraphicsvideo.moc" -- cgit v0.12 From 5f1c9dd14e1a6f6fc479dc8103a1166c71b61746 Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Fri, 5 Feb 2010 11:55:41 +1000 Subject: Added support for XvImage shm based video frames to gstreamer backend. Gstreamer backend will use XvShmPutImage without copying frames data if possible with overlay video output, and provide XvImage based video frames to renderer video output surface. --- .../mediaservices/gstreamer/qgstvideobuffer.cpp | 12 + .../mediaservices/gstreamer/qgstvideobuffer.h | 5 + .../mediaservices/gstreamer/qgstxvimagebuffer.cpp | 276 ++++++++++++++++++++ .../mediaservices/gstreamer/qgstxvimagebuffer.h | 131 ++++++++++ .../gstreamer/qvideosurfacegstsink.cpp | 280 +++++++++++++++------ .../mediaservices/gstreamer/qvideosurfacegstsink.h | 18 +- .../mediaservices/gstreamer/qx11videosurface.cpp | 81 ++++-- 7 files changed, 709 insertions(+), 94 deletions(-) create mode 100644 src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp create mode 100644 src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp index 384bdff..9519db6 100644 --- a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp +++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.cpp @@ -51,6 +51,18 @@ QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine) gst_buffer_ref(m_buffer); } +QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine, + QGstVideoBuffer::HandleType handleType, + const QVariant &handle) + : QAbstractVideoBuffer(handleType) + , m_buffer(buffer) + , m_bytesPerLine(bytesPerLine) + , m_mode(NotMapped) + , m_handle(handle) +{ + gst_buffer_ref(m_buffer); +} + QGstVideoBuffer::~QGstVideoBuffer() { gst_buffer_unref(m_buffer); diff --git a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h index 36b7c08..5133e2e 100644 --- a/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h +++ b/src/plugins/mediaservices/gstreamer/qgstvideobuffer.h @@ -43,6 +43,7 @@ #define QGSTVIDEOBUFFER_H #include +#include #include @@ -55,6 +56,8 @@ class QGstVideoBuffer : public QAbstractVideoBuffer { public: QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine); + QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine, + HandleType handleType, const QVariant &handle); ~QGstVideoBuffer(); MapMode mapMode() const; @@ -62,10 +65,12 @@ public: uchar *map(MapMode mode, int *numBytes, int *bytesPerLine); void unmap(); + QVariant handle() const { return m_handle; } private: GstBuffer *m_buffer; int m_bytesPerLine; MapMode m_mode; + QVariant m_handle; }; QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp new file mode 100644 index 0000000..0e47c98 --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 +#include +#include +#include + +#include "qgstxvimagebuffer.h" +#include "qvideosurfacegstsink.h" + +GstBufferClass *QGstXvImageBuffer::parent_class = NULL; + +GType QGstXvImageBuffer::get_type(void) +{ + static GType buffer_type = 0; + + if (buffer_type == 0) { + static const GTypeInfo buffer_info = { + sizeof (GstBufferClass), + NULL, + NULL, + QGstXvImageBuffer::class_init, + NULL, + NULL, + sizeof(QGstXvImageBuffer), + 0, + (GInstanceInitFunc)QGstXvImageBuffer::buffer_init, + NULL + }; + buffer_type = g_type_register_static(GST_TYPE_BUFFER, + "QGstXvImageBuffer", &buffer_info, GTypeFlags(0)); + } + return buffer_type; +} + +void QGstXvImageBuffer::class_init(gpointer g_class, gpointer class_data) +{ + Q_UNUSED(class_data); + GST_MINI_OBJECT_CLASS(g_class)->finalize = + (GstMiniObjectFinalizeFunction)buffer_finalize; + parent_class = (GstBufferClass*)g_type_class_peek_parent(g_class); +} + +void QGstXvImageBuffer::buffer_init(QGstXvImageBuffer *xvImage, gpointer g_class) +{ + Q_UNUSED(g_class); + xvImage->pool = 0; + xvImage->shmInfo.shmaddr = ((char *) -1); + xvImage->shmInfo.shmid = -1; + xvImage->markedForDeletion = false; +} + +void QGstXvImageBuffer::buffer_finalize(QGstXvImageBuffer * xvImage) +{ + if (xvImage->pool) { + if (xvImage->markedForDeletion) + xvImage->pool->destroyBuffer(xvImage); + else + xvImage->pool->recycleBuffer(xvImage); + } +} + + +QGstXvImageBufferPool::QGstXvImageBufferPool(QObject *parent) + :QObject(parent) +{ +} + +QGstXvImageBufferPool::~QGstXvImageBufferPool() +{ +} + +bool QGstXvImageBufferPool::isFormatSupported(const QVideoSurfaceFormat &surfaceFormat) +{ + bool ok = true; + surfaceFormat.property("portId").toULongLong(&ok); + if (!ok) + return false; + + int xvFormatId = surfaceFormat.property("xvFormatId").toInt(&ok); + if (!ok || xvFormatId < 0) + return false; + + int dataSize = surfaceFormat.property("dataSize").toInt(&ok); + if (!ok || dataSize<=0) + return false; + + return true; +} + +QGstXvImageBuffer *QGstXvImageBufferPool::takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps) +{ + m_poolMutex.lock(); + + m_caps = caps; + if (format != m_format) { + doClear(); + m_format = format; + } + + + if (m_pool.isEmpty()) { + //qDebug() << "QGstXvImageBufferPool::takeBuffer: no buffer available, allocate the new one"; + if (QThread::currentThread() == thread()) { + m_poolMutex.unlock(); + queuedAlloc(); + m_poolMutex.lock(); + } else { + QMetaObject::invokeMethod(this, "queuedAlloc", Qt::QueuedConnection); + m_allocWaitCondition.wait(&m_poolMutex, 300); + } + } + QGstXvImageBuffer *res = 0; + + if (!m_pool.isEmpty()) { + res = m_pool.takeLast(); + } + + m_poolMutex.unlock(); + + return res; +} + +void QGstXvImageBufferPool::queuedAlloc() +{ + QMutexLocker lock(&m_poolMutex); + + Q_ASSERT(QThread::currentThread() == thread()); + + QGstXvImageBuffer *xvBuffer = (QGstXvImageBuffer *)gst_mini_object_new(QGstXvImageBuffer::get_type()); + + quint64 portId = m_format.property("portId").toULongLong(); + int xvFormatId = m_format.property("xvFormatId").toInt(); + + xvBuffer->xvImage = XvShmCreateImage( + QX11Info::display(), + portId, + xvFormatId, + 0, + m_format.frameWidth(), + m_format.frameHeight(), + &xvBuffer->shmInfo + ); + + if (!xvBuffer->xvImage) { + qDebug() << "QGstXvImageBufferPool: XvShmCreateImage failed"; + m_allocWaitCondition.wakeOne(); + return; + } + + xvBuffer->shmInfo.shmid = shmget(IPC_PRIVATE, xvBuffer->xvImage->data_size, IPC_CREAT | 0777); + xvBuffer->shmInfo.shmaddr = xvBuffer->xvImage->data = (char*)shmat(xvBuffer->shmInfo.shmid, 0, 0); + xvBuffer->shmInfo.readOnly = False; + + if (!XShmAttach(QX11Info::display(), &xvBuffer->shmInfo)) { + qDebug() << "QGstXvImageBufferPool: XShmAttach failed"; + m_allocWaitCondition.wakeOne(); + return; + } + + shmctl (xvBuffer->shmInfo.shmid, IPC_RMID, NULL); + + xvBuffer->pool = this; + GST_MINI_OBJECT_CAST(xvBuffer)->flags = 0; + gst_buffer_set_caps(GST_BUFFER_CAST(xvBuffer), m_caps); + GST_BUFFER_DATA(xvBuffer) = (uchar*)xvBuffer->xvImage->data; + GST_BUFFER_SIZE(xvBuffer) = xvBuffer->xvImage->data_size; + + m_allBuffers.append(xvBuffer); + m_pool.append(xvBuffer); + + m_allocWaitCondition.wakeOne(); +} + + +void QGstXvImageBufferPool::clear() +{ + QMutexLocker lock(&m_poolMutex); + doClear(); +} + +void QGstXvImageBufferPool::doClear() +{ + foreach (QGstXvImageBuffer *xvBuffer, m_allBuffers) { + xvBuffer->markedForDeletion = true; + } + m_allBuffers.clear(); + + foreach (QGstXvImageBuffer *xvBuffer, m_pool) { + gst_buffer_unref(GST_BUFFER(xvBuffer)); + } + m_pool.clear(); + + m_format = QVideoSurfaceFormat(); +} + +void QGstXvImageBufferPool::queuedDestroy() +{ + QMutexLocker lock(&m_destroyMutex); + + foreach(XvShmImage xvImage, m_imagesToDestroy) { + if (xvImage.shmInfo.shmaddr != ((void *) -1)) { + XShmDetach(QX11Info::display(), &xvImage.shmInfo); + XSync(QX11Info::display(), false); + + shmdt(xvImage.shmInfo.shmaddr); + } + + if (xvImage.xvImage) + XFree(xvImage.xvImage); + } + + m_imagesToDestroy.clear(); + + XSync(QX11Info::display(), false); +} + +void QGstXvImageBufferPool::recycleBuffer(QGstXvImageBuffer *xvBuffer) +{ + QMutexLocker lock(&m_poolMutex); + gst_buffer_ref(GST_BUFFER_CAST(xvBuffer)); + m_pool.append(xvBuffer); +} + +void QGstXvImageBufferPool::destroyBuffer(QGstXvImageBuffer *xvBuffer) +{ + XvShmImage imageToDestroy; + imageToDestroy.xvImage = xvBuffer->xvImage; + imageToDestroy.shmInfo = xvBuffer->shmInfo; + + m_destroyMutex.lock(); + m_imagesToDestroy.append(imageToDestroy); + m_destroyMutex.unlock(); + + if (m_imagesToDestroy.size() == 1) + QMetaObject::invokeMethod(this, "queuedDestroy", Qt::QueuedConnection); +} diff --git a/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h new file mode 100644 index 0000000..beeb01f --- /dev/null +++ b/src/plugins/mediaservices/gstreamer/qgstxvimagebuffer.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins 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 QGSTXVIMAGEBUFFER_H +#define QGSTXVIMAGEBUFFER_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QGstXvImageBufferPool; + +struct QGstXvImageBuffer { + GstBuffer buffer; + QGstXvImageBufferPool *pool; + XvImage *xvImage; + XShmSegmentInfo shmInfo; + bool markedForDeletion; + + static GType get_type(void); + static void class_init(gpointer g_class, gpointer class_data); + static void buffer_init(QGstXvImageBuffer *xvimage, gpointer g_class); + static void buffer_finalize(QGstXvImageBuffer * xvimage); + static GstBufferClass *parent_class; +}; + +const QAbstractVideoBuffer::HandleType XvHandleType = QAbstractVideoBuffer::HandleType(4); + +Q_DECLARE_METATYPE(XvImage*) + + +class QGstXvImageBufferPool : public QObject { +Q_OBJECT +friend class QGstXvImageBuffer; +public: + QGstXvImageBufferPool(QObject *parent = 0); + virtual ~QGstXvImageBufferPool(); + + bool isFormatSupported(const QVideoSurfaceFormat &format); + + QGstXvImageBuffer *takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps); + void clear(); + +private slots: + void queuedAlloc(); + void queuedDestroy(); + + void doClear(); + + void recycleBuffer(QGstXvImageBuffer *); + void destroyBuffer(QGstXvImageBuffer *); + +private: + struct XvShmImage { + XvImage *xvImage; + XShmSegmentInfo shmInfo; + }; + + QMutex m_poolMutex; + QMutex m_allocMutex; + QWaitCondition m_allocWaitCondition; + QMutex m_destroyMutex; + QVideoSurfaceFormat m_format; + GstCaps *m_caps; + QList m_pool; + QList m_allBuffers; + QList m_imagesToDestroy; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp index 41e3f77..ca91522 100644 --- a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp @@ -39,16 +39,19 @@ ** ****************************************************************************/ -#include "qvideosurfacegstsink.h" - -#include "qgstvideobuffer.h" - #include #include #include #include #include #include +#include + +#include "qvideosurfacegstsink.h" + +#include "qgstvideobuffer.h" +#include "qgstxvimagebuffer.h" + Q_DECLARE_METATYPE(QVideoSurfaceFormat) @@ -62,11 +65,20 @@ QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QAbstractVideoSurface *surfac connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged())); } -QList QVideoSurfaceGstDelegate::supportedPixelFormats() const +QList QVideoSurfaceGstDelegate::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const { QMutexLocker locker(const_cast(&m_mutex)); - return m_supportedPixelFormats; + if (handleType == QAbstractVideoBuffer::NoHandle) + return m_supportedPixelFormats; + else + return m_surface->supportedPixelFormats(handleType); +} + +QVideoSurfaceFormat QVideoSurfaceGstDelegate::surfaceFormat() const +{ + QMutexLocker locker(const_cast(&m_mutex)); + return m_format; } bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int bytesPerLine) @@ -84,6 +96,8 @@ bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int byte m_setupCondition.wait(&m_mutex); } + m_format = m_surface->surfaceFormat(); + return m_started; } @@ -103,12 +117,27 @@ void QVideoSurfaceGstDelegate::stop() m_started = false; } +bool QVideoSurfaceGstDelegate::isActive() +{ + QMutexLocker locker(&m_mutex); + return m_surface->isActive(); +} + GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) { QMutexLocker locker(&m_mutex); + QGstVideoBuffer *videoBuffer = 0; + + if (G_TYPE_CHECK_INSTANCE_TYPE(buffer, QGstXvImageBuffer::get_type())) { + QGstXvImageBuffer *xvBuffer = reinterpret_cast(buffer); + QVariant handle = QVariant::fromValue(xvBuffer->xvImage); + videoBuffer = new QGstVideoBuffer(buffer, m_bytesPerLine, XvHandleType, handle); + } else + videoBuffer = new QGstVideoBuffer(buffer, m_bytesPerLine); + m_frame = QVideoFrame( - new QGstVideoBuffer(buffer, m_bytesPerLine), + videoBuffer, m_format.frameSize(), m_format.pixelFormat()); @@ -134,7 +163,6 @@ GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) } } - void QVideoSurfaceGstDelegate::queuedStart() { QMutexLocker locker(&m_mutex); @@ -196,8 +224,8 @@ static const YuvFormat qt_yuvColorLookup[] = { { QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 }, { QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 }, - { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 8 }, - { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','V'), 8 }, + { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 16 }, + { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','V'), 16 }, { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 8 }, { QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 }, { QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 } @@ -210,16 +238,18 @@ static int indexOfYuvColor(QVideoFrame::PixelFormat format) for (int i = 0; i < count; ++i) if (qt_yuvColorLookup[i].pixelFormat == format) return i; + return -1; } static int indexOfYuvColor(guint32 fourcc) { - const int count = sizeof(YuvFormat) / sizeof(YuvFormat); + const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat); for (int i = 0; i < count; ++i) if (qt_yuvColorLookup[i].fourcc == fourcc) return i; + return -1; } @@ -313,7 +343,7 @@ void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data) GstBaseSinkClass *base_sink_class = reinterpret_cast(g_class); base_sink_class->get_caps = QVideoSurfaceGstSink::get_caps; base_sink_class->set_caps = QVideoSurfaceGstSink::set_caps; - // base_sink_class->buffer_alloc = QVideoSurfaceGstSink::buffer_alloc; // Not implemented. + base_sink_class->buffer_alloc = QVideoSurfaceGstSink::buffer_alloc; base_sink_class->start = QVideoSurfaceGstSink::start; base_sink_class->stop = QVideoSurfaceGstSink::stop; // base_sink_class->unlock = QVideoSurfaceGstSink::unlock; // Not implemented. @@ -352,11 +382,27 @@ void QVideoSurfaceGstSink::instance_init(GTypeInstance *instance, gpointer g_cla Q_UNUSED(g_class); sink->delegate = 0; + sink->pool = new QGstXvImageBufferPool(); + sink->lastRequestedCaps = 0; + sink->lastBufferCaps = 0; + sink->lastSurfaceFormat = new QVideoSurfaceFormat; } void QVideoSurfaceGstSink::finalize(GObject *object) { - Q_UNUSED(object); + VO_SINK(object); + delete sink->pool; + sink->pool = 0; + delete sink->lastSurfaceFormat; + sink->lastSurfaceFormat = 0; + + if (sink->lastBufferCaps) + gst_caps_unref(sink->lastBufferCaps); + sink->lastBufferCaps = 0; + + if (sink->lastRequestedCaps) + gst_caps_unref(sink->lastRequestedCaps); + sink->lastRequestedCaps = 0; } GstStateChangeReturn QVideoSurfaceGstSink::change_state( @@ -421,92 +467,184 @@ gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps) { VO_SINK(base); + //qDebug() << "set_caps"; + //qDebug() << gst_caps_to_string(caps); + if (!caps) { sink->delegate->stop(); return TRUE; } else { - const GstStructure *structure = gst_caps_get_structure(caps, 0); + int bytesPerLine = 0; + QVideoSurfaceFormat format = formatForCaps(caps, &bytesPerLine); - //qDebug() << gst_caps_to_string(caps); + if (sink->delegate->isActive()) { + QVideoSurfaceFormat surfaceFormst = sink->delegate->surfaceFormat(); - QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid; - int bitsPerPixel = 0; + if (format.pixelFormat() == surfaceFormst.pixelFormat() && + format.frameSize() == surfaceFormst.frameSize()) + return TRUE; + else + sink->delegate->stop(); + } - QSize size; - gst_structure_get_int(structure, "width", &size.rwidth()); - gst_structure_get_int(structure, "height", &size.rheight()); + if (sink->lastRequestedCaps) + gst_caps_unref(sink->lastRequestedCaps); + sink->lastRequestedCaps = 0; - if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { - guint32 fourcc = 0; - gst_structure_get_fourcc(structure, "format", &fourcc); + //qDebug() << "Staring video surface:"; + //qDebug() << format; + //qDebug() << bytesPerLine; - int index = indexOfYuvColor(fourcc); - if (index != -1) { - pixelFormat = qt_yuvColorLookup[index].pixelFormat; - bitsPerPixel = qt_yuvColorLookup[index].bitsPerPixel; - } - } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { - int depth = 0; - int endianness = 0; - int red = 0; - int green = 0; - int blue = 0; - int alpha = 0; - - gst_structure_get_int(structure, "bpp", &bitsPerPixel); - gst_structure_get_int(structure, "depth", &depth); - gst_structure_get_int(structure, "endianness", &endianness); - gst_structure_get_int(structure, "red_mask", &red); - gst_structure_get_int(structure, "green_mask", &green); - gst_structure_get_int(structure, "blue_mask", &blue); - gst_structure_get_int(structure, "alpha_mask", &alpha); - - int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha); - - if (index != -1) - pixelFormat = qt_rgbColorLookup[index].pixelFormat; - } + if (sink->delegate->start(format, bytesPerLine)) + return TRUE; - if (pixelFormat != QVideoFrame::Format_Invalid) { - QVideoSurfaceFormat format(size, pixelFormat); + } - QPair rate; - gst_structure_get_fraction(structure, "framerate", &rate.first, &rate.second); + return FALSE; +} - if (rate.second) - format.setFrameRate(qreal(rate.first)/rate.second); +QVideoSurfaceFormat QVideoSurfaceGstSink::formatForCaps(GstCaps *caps, int *bytesPerLine) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); - gint aspectNum = 0; - gint aspectDenum = 0; - if (gst_structure_get_fraction( - structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { - if (aspectDenum > 0) - format.setPixelAspectRatio(aspectNum, aspectDenum); - } + QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid; + int bitsPerPixel = 0; - int bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3; + QSize size; + gst_structure_get_int(structure, "width", &size.rwidth()); + gst_structure_get_int(structure, "height", &size.rheight()); - if (sink->delegate->start(format, bytesPerLine)) - return TRUE; + if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { + guint32 fourcc = 0; + gst_structure_get_fourcc(structure, "format", &fourcc); + + int index = indexOfYuvColor(fourcc); + if (index != -1) { + pixelFormat = qt_yuvColorLookup[index].pixelFormat; + bitsPerPixel = qt_yuvColorLookup[index].bitsPerPixel; } + } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { + int depth = 0; + int endianness = 0; + int red = 0; + int green = 0; + int blue = 0; + int alpha = 0; + + gst_structure_get_int(structure, "bpp", &bitsPerPixel); + gst_structure_get_int(structure, "depth", &depth); + gst_structure_get_int(structure, "endianness", &endianness); + gst_structure_get_int(structure, "red_mask", &red); + gst_structure_get_int(structure, "green_mask", &green); + gst_structure_get_int(structure, "blue_mask", &blue); + gst_structure_get_int(structure, "alpha_mask", &alpha); + + int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha); + + if (index != -1) + pixelFormat = qt_rgbColorLookup[index].pixelFormat; + } + + if (pixelFormat != QVideoFrame::Format_Invalid) { + QVideoSurfaceFormat format(size, pixelFormat); + + QPair rate; + gst_structure_get_fraction(structure, "framerate", &rate.first, &rate.second); + + if (rate.second) + format.setFrameRate(qreal(rate.first)/rate.second); + + gint aspectNum = 0; + gint aspectDenum = 0; + if (gst_structure_get_fraction( + structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { + if (aspectDenum > 0) + format.setPixelAspectRatio(aspectNum, aspectDenum); + } + + if (bytesPerLine) + *bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3; + return format; } - return FALSE; + return QVideoSurfaceFormat(); } + GstFlowReturn QVideoSurfaceGstSink::buffer_alloc( GstBaseSink *base, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer) { - // Should implement this when the buffer pool situation is sorted. - Q_UNUSED(base); + VO_SINK(base); + Q_UNUSED(offset); Q_UNUSED(size); - Q_UNUSED(caps); - Q_UNUSED(buffer); - return GST_FLOW_NOT_SUPPORTED; + *buffer = 0; + + if (sink->lastRequestedCaps && gst_caps_is_equal(sink->lastRequestedCaps, caps)) { + //qDebug() << "reusing last caps"; + *buffer = GST_BUFFER(sink->pool->takeBuffer(*sink->lastSurfaceFormat, sink->lastBufferCaps)); + return GST_FLOW_OK; + } + + if (sink->delegate->supportedPixelFormats(XvHandleType).isEmpty()) { + //qDebug() << "sink doesn't support Xv buffers, skip buffers allocation"; + return GST_FLOW_OK; + } + + GstCaps *intersection = gst_caps_intersect(get_caps(GST_BASE_SINK(sink)), caps); + + if (gst_caps_is_empty (intersection)) { + gst_caps_unref(intersection); + return GST_FLOW_NOT_NEGOTIATED; + } + + if (sink->delegate->isActive()) { + //if format was changed, restart the surface + QVideoSurfaceFormat format = formatForCaps(intersection); + QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat(); + + if (format.pixelFormat() != surfaceFormat.pixelFormat() || + format.frameSize() != surfaceFormat.frameSize()) { + //qDebug() << "new format requested, restart video surface"; + sink->delegate->stop(); + } + } + + if (!sink->delegate->isActive()) { + int bytesPerLine = 0; + QVideoSurfaceFormat format = formatForCaps(intersection, &bytesPerLine); + + if (!sink->delegate->start(format, bytesPerLine)) { + qDebug() << "failed to start video surface"; + return GST_FLOW_NOT_NEGOTIATED; + } + } + + QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat(); + + if (!sink->pool->isFormatSupported(surfaceFormat)) { + //qDebug() << "sink doesn't provide Xv buffer details, skip buffers allocation"; + return GST_FLOW_OK; + } + + if (sink->lastRequestedCaps) + gst_caps_unref(sink->lastRequestedCaps); + sink->lastRequestedCaps = caps; + gst_caps_ref(sink->lastRequestedCaps); + + if (sink->lastBufferCaps) + gst_caps_unref(sink->lastBufferCaps); + sink->lastBufferCaps = intersection; + gst_caps_ref(sink->lastBufferCaps); + + *sink->lastSurfaceFormat = surfaceFormat; + + *buffer = GST_BUFFER(sink->pool->takeBuffer(surfaceFormat, intersection)); + + return GST_FLOW_OK; } gboolean QVideoSurfaceGstSink::start(GstBaseSink *base) diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h index f02f9a5..f59a43c 100644 --- a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.h @@ -50,6 +50,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -58,17 +59,27 @@ QT_BEGIN_NAMESPACE class QAbstractVideoSurface; +class QGstXvImageBuffer; +class QGstXvImageBufferPool; + + class QVideoSurfaceGstDelegate : public QObject { Q_OBJECT public: QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface); - QList supportedPixelFormats() const; + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + QVideoSurfaceFormat surfaceFormat() const; + bool start(const QVideoSurfaceFormat &format, int bytesPerLine); void stop(); + bool isActive(); + GstFlowReturn render(GstBuffer *buffer); private slots: @@ -97,6 +108,7 @@ public: GstVideoSink parent; static QVideoSurfaceGstSink *createSink(QAbstractVideoSurface *surface); + static QVideoSurfaceFormat formatForCaps(GstCaps *caps, int *bytesPerLine = 0); private: static GType get_type(); @@ -125,6 +137,10 @@ private: private: QVideoSurfaceGstDelegate *delegate; + QGstXvImageBufferPool *pool; + GstCaps *lastRequestedCaps; + GstCaps *lastBufferCaps; + QVideoSurfaceFormat *lastSurfaceFormat; }; diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp index 30b7e55..7a98384 100644 --- a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp +++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp @@ -39,11 +39,17 @@ ** ****************************************************************************/ +#include +#include #include #include #include "qx11videosurface.h" +Q_DECLARE_METATYPE(XvImage*); + +static QAbstractVideoBuffer::HandleType XvHandleType = QAbstractVideoBuffer::HandleType(4); + struct XvFormatRgb { QVideoFrame::PixelFormat pixelFormat; @@ -284,7 +290,7 @@ int QX11VideoSurface::redistribute( QList QX11VideoSurface::supportedPixelFormats( QAbstractVideoBuffer::HandleType handleType) const { - return handleType == QAbstractVideoBuffer::NoHandle + return handleType == QAbstractVideoBuffer::NoHandle || handleType == XvHandleType ? m_supportedPixelFormats : QList(); } @@ -319,7 +325,12 @@ bool QX11VideoSurface::start(const QVideoSurfaceFormat &format) m_viewport = format.viewport(); m_image = image; - return QAbstractVideoSurface::start(format); + QVideoSurfaceFormat newFormat = format; + newFormat.setProperty("portId", QVariant(quint64(m_portId))); + newFormat.setProperty("xvFormatId", xvFormatId); + newFormat.setProperty("dataSize", image->data_size); + + return QAbstractVideoSurface::start(newFormat); } } @@ -359,31 +370,57 @@ bool QX11VideoSurface::present(const QVideoFrame &frame) } else { bool presented = false; - if (m_image->data_size > frame.mappedBytes()) { + if (frame.handleType() != XvHandleType && + m_image->data_size > frame.mappedBytes()) { qWarning("Insufficient frame buffer size"); setError(IncorrectFormatError); - } else if (m_image->num_planes > 0 && m_image->pitches[0] != frame.bytesPerLine()) { + } else if (frame.handleType() != XvHandleType && + m_image->num_planes > 0 && + m_image->pitches[0] != frame.bytesPerLine()) { qWarning("Incompatible frame pitches"); setError(IncorrectFormatError); } else { - m_image->data = reinterpret_cast(frameCopy.bits()); - - XvPutImage( - QX11Info::display(), - m_portId, - m_winId, - m_gc, - m_image, - m_viewport.x(), - m_viewport.y(), - m_viewport.width(), - m_viewport.height(), - m_displayRect.x(), - m_displayRect.y(), - m_displayRect.width(), - m_displayRect.height()); - - m_image->data = 0; + if (frame.handleType() != XvHandleType) { + m_image->data = reinterpret_cast(frameCopy.bits()); + + //qDebug() << "copy frame"; + XvPutImage( + QX11Info::display(), + m_portId, + m_winId, + m_gc, + m_image, + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height()); + + m_image->data = 0; + } else { + XvImage *img = frame.handle().value(); + + //qDebug() << "render directly"; + if (img) + XvShmPutImage( + QX11Info::display(), + m_portId, + m_winId, + m_gc, + img, + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + m_displayRect.x(), + m_displayRect.y(), + m_displayRect.width(), + m_displayRect.height(), + false); + } presented = true; } -- cgit v0.12 From 229154b202c26a809e2f502eb9acb99f6307fbb9 Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Fri, 5 Feb 2010 13:15:15 +1000 Subject: Gstreamer and XVideo use YUY2 fourcc, not YUYV. --- src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp | 3 +-- src/plugins/mediaservices/gstreamer/qx11videosurface.cpp | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp index ca91522..8c61846 100644 --- a/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp +++ b/src/plugins/mediaservices/gstreamer/qvideosurfacegstsink.cpp @@ -225,8 +225,7 @@ static const YuvFormat qt_yuvColorLookup[] = { QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 }, { QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 }, { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 16 }, - { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','V'), 16 }, - { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 8 }, + { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 16 }, { QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 }, { QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 } }; diff --git a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp index 7a98384..6e282ff 100644 --- a/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp +++ b/src/plugins/mediaservices/gstreamer/qx11videosurface.cpp @@ -130,6 +130,7 @@ static const XvFormatYuv qt_xvYuvLookup[] = { QVideoFrame::Format_YUV420P, 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, { QVideoFrame::Format_YV12 , 12, XvPlanar, 3, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, { QVideoFrame::Format_UYVY , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "UYVY" }, + { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUY2" }, { QVideoFrame::Format_YUYV , 16, XvPacked, 1, 8, 8, 8, 1, 2, 2, 1, 1, 1, "YUYV" }, { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YUV" }, { QVideoFrame::Format_NV12 , 12, XvPlanar, 2, 8, 8, 8, 1, 2, 2, 1, 2, 2, "YVU" }, -- cgit v0.12 From abf04def344aeb14dbb8539ba73fb5de26237bcc Mon Sep 17 00:00:00 2001 From: Kurt Korbatits Date: Fri, 5 Feb 2010 14:08:30 +1000 Subject: Added Q_WS_MAEMO_5 to mkspec file. --- mkspecs/linux-g++-maemo/qmake.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkspecs/linux-g++-maemo/qmake.conf b/mkspecs/linux-g++-maemo/qmake.conf index 38c26a6..e586ed0 100644 --- a/mkspecs/linux-g++-maemo/qmake.conf +++ b/mkspecs/linux-g++-maemo/qmake.conf @@ -32,4 +32,6 @@ DEFINES += QT_GL_NO_SCISSOR_TEST # Work round SGX 1.4 driver bug (text corrupted), modify glyph cache width: DEFINES += QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH=1024 +DEFINES += Q_WS_MAEMO_5 + load(qt_config) -- cgit v0.12 From f14e3b86e6b7b496017ddd462821325bdb40c779 Mon Sep 17 00:00:00 2001 From: Kurt Korbatits Date: Fri, 5 Feb 2010 14:12:04 +1000 Subject: qmlsound changed to soundeffect element. --- src/multimedia/qml/qml.pri | 24 +- src/multimedia/qml/qmlsound.cpp | 168 --------- src/multimedia/qml/qmlsound_p.h | 126 ------- src/multimedia/qml/qsoundeffect.cpp | 253 ++++++++++++++ src/multimedia/qml/qsoundeffect_p.h | 116 +++++++ src/multimedia/qml/qsoundeffect_pulse_p.cpp | 502 +++++++++++++++++++++++++++ src/multimedia/qml/qsoundeffect_pulse_p.h | 134 +++++++ src/multimedia/qml/qsoundeffect_qmedia_p.cpp | 163 +++++++++ src/multimedia/qml/qsoundeffect_qmedia_p.h | 105 ++++++ src/multimedia/qml/qsoundeffect_qsound_p.cpp | 223 ++++++++++++ src/multimedia/qml/qsoundeffect_qsound_p.h | 124 +++++++ src/multimedia/qml/wavedecoder_p.cpp | 136 ++++++++ src/multimedia/qml/wavedecoder_p.h | 113 ++++++ 13 files changed, 1889 insertions(+), 298 deletions(-) delete mode 100644 src/multimedia/qml/qmlsound.cpp delete mode 100644 src/multimedia/qml/qmlsound_p.h create mode 100644 src/multimedia/qml/qsoundeffect.cpp create mode 100644 src/multimedia/qml/qsoundeffect_p.h create mode 100644 src/multimedia/qml/qsoundeffect_pulse_p.cpp create mode 100644 src/multimedia/qml/qsoundeffect_pulse_p.h create mode 100644 src/multimedia/qml/qsoundeffect_qmedia_p.cpp create mode 100644 src/multimedia/qml/qsoundeffect_qmedia_p.h create mode 100644 src/multimedia/qml/qsoundeffect_qsound_p.cpp create mode 100644 src/multimedia/qml/qsoundeffect_qsound_p.h create mode 100644 src/multimedia/qml/wavedecoder_p.cpp create mode 100644 src/multimedia/qml/wavedecoder_p.h diff --git a/src/multimedia/qml/qml.pri b/src/multimedia/qml/qml.pri index 6b44e0c..a30c3ad 100644 --- a/src/multimedia/qml/qml.pri +++ b/src/multimedia/qml/qml.pri @@ -2,18 +2,34 @@ contains(QT_CONFIG, declarative) { QT += declarative + system(pkg-config --exists \'libpulse >= 0.9.10\') { + DEFINES += QT_MULTIMEDIA_PULSEAUDIO + HEADERS += qsoundeffect_pulse_p.h + SOURCES += qsoundeffect_pulse_p.cpp + LIBS += -lpulse + } else:x11 { + DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER + HEADERS += qsoundeffect_qmedia_p.h + SOURCES += qsoundeffect_qmedia_p.cpp + } else { + HEADERS += qsoundeffect_qsound_p.h + SOURCES += qsoundeffect_qsound_p.cpp + } + HEADERS += \ - $$PWD/qmlsound_p.h \ $$PWD/qmetadatacontrolmetaobject_p.h \ $$PWD/qmlaudio_p.h \ $$PWD/qmlgraphicsvideo_p.h \ - $$PWD/qmlmediabase_p.h + $$PWD/qmlmediabase_p.h \ + $$PWD/qsoundeffect_p.h \ + $$PWD/wavedecoder_p.h SOURCES += \ - $$PWD/qmlsound.cpp \ $$PWD/qmetadatacontrolmetaobject.cpp \ $$PWD/qmlaudio.cpp \ $$PWD/qmlgraphicsvideo.cpp \ - $$PWD/qmlmediabase.cpp + $$PWD/qmlmediabase.cpp \ + $$PWD/qsoundeffect.cpp \ + $$PWD/wavedecoder_p.cpp } diff --git a/src/multimedia/qml/qmlsound.cpp b/src/multimedia/qml/qmlsound.cpp deleted file mode 100644 index b0693b7..0000000 --- a/src/multimedia/qml/qmlsound.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/**************************************************************************** -** -** 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 QtMultimedia module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 "qmlsound_p.h" - -#include - - -QT_BEGIN_NAMESPACE - -QML_DEFINE_TYPE(Qt,4,6,Sound,QmlSound) - -QmlSound::QmlSound(QObject *parent) : - QObject(parent), - m_loopCount(1), - m_volume(100), - m_muted(false), - m_runningCount(0), - m_player(0) -{ -} - -QmlSound::~QmlSound() -{ - delete m_player; -} - -QUrl QmlSound::source() const -{ - return m_player != 0 ? m_player->media().canonicalUrl() : QUrl(); -} - -void QmlSound::setSource(const QUrl &url) -{ - if (m_player != 0 && m_player->media().canonicalUrl() == url) - return; - - if (m_player == 0) { - m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency); - m_player->setVolume(m_volume); - m_player->setMuted(m_muted); - - connect(m_player, SIGNAL(volumeChanged()), SIGNAL(volumeChanged())); - connect(m_player, SIGNAL(mutedChanged()), SIGNAL(mutedChanged())); - connect(m_player, SIGNAL(durationChanged()), SIGNAL(durationChanged())); - connect(m_player, SIGNAL(stateChanged()), SLOT(repeat())); - } - - m_player->setMedia(url); - if (url.isEmpty()) - return; - - emit sourceChanged(); -} - -int QmlSound::loopCount() const -{ - return m_loopCount; -} - -void QmlSound::setLoopCount(int loopCount) -{ - if (m_loopCount == loopCount) - return; - - m_loopCount = loopCount; - emit loopCountChanged(); -} - -int QmlSound::volume() const -{ - return m_player != 0 ? m_player->volume() : m_volume; -} - -void QmlSound::setVolume(int volume) -{ - if (m_volume == volume) - return; - - m_volume = volume; - if (m_player != 0) - m_player->setVolume(volume); - else - emit volumeChanged(); -} - -bool QmlSound::isMuted() const -{ - return m_player != 0 ? m_player->isMuted() : m_muted; -} - -void QmlSound::setMuted(bool muted) -{ - if (m_muted == muted) - return; - - m_muted = muted; - if (m_player != 0) - m_player->setMuted(muted); - else - emit mutedChanged(); -} - -int QmlSound::duration() const -{ - return m_player != 0 ? m_player->duration() : 0; -} - -void QmlSound::play() -{ - m_runningCount = 0; - if (m_player != 0) - m_player->play(); -} - -void QmlSound::stop() -{ - if (m_player != 0) - m_player->stop(); -} - -void QmlSound::repeat() -{ - if (m_player->state() == QMediaPlayer::StoppedState) { - if (++m_runningCount < m_loopCount) - m_player->play(); - } -} - -QT_END_NAMESPACE diff --git a/src/multimedia/qml/qmlsound_p.h b/src/multimedia/qml/qmlsound_p.h deleted file mode 100644 index 0a149c0..0000000 --- a/src/multimedia/qml/qmlsound_p.h +++ /dev/null @@ -1,126 +0,0 @@ -/**************************************************************************** -** -** 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 QtMultimedia module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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 QMLSOUND_H -#define QMLSOUND_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - - -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Multimedia) - -class QMediaPlayer; - -class QmlSound : public QObject -{ - Q_OBJECT - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) - Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) - Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) - Q_PROPERTY(int duration READ duration NOTIFY durationChanged) - -public: - explicit QmlSound(QObject *parent = 0); - ~QmlSound(); - - QUrl source() const; - void setSource(const QUrl &url); - - int loopCount() const; - void setLoopCount(int loopCount); - - int volume() const; - void setVolume(int volume); - - bool isMuted() const; - void setMuted(bool muted); - - int duration() const; - -signals: - void sourceChanged(); - void loopCountChanged(); - void volumeChanged(); - void mutedChanged(); - void durationChanged(); - -public slots: - void play(); - void stop(); - -private slots: - void repeat(); - -private: - Q_DISABLE_COPY(QmlSound) - - int m_loopCount; - int m_volume; - bool m_muted; - int m_runningCount; - QMediaPlayer *m_player; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -QML_DECLARE_TYPE(QmlSound) - -#endif // QMLSOUND_H diff --git a/src/multimedia/qml/qsoundeffect.cpp b/src/multimedia/qml/qsoundeffect.cpp new file mode 100644 index 0000000..9692c89 --- /dev/null +++ b/src/multimedia/qml/qsoundeffect.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "qmediacontent.h" +#include "qmediaplayer.h" + +#include "qsoundeffect_p.h" + +#if defined(QT_MULTIMEDIA_PULSEAUDIO) +#include "qsoundeffect_pulse_p.h" +#elif(QT_MULTIMEDIA_QMEDIAPLAYER) +#include "qsoundeffect_qmedia_p.h" +#else +#include "qsoundeffect_qsound_p.h" +#endif + +QML_DEFINE_TYPE(Qt,4,6,SoundEffect,QSoundEffect) + +/*! + \qmlclass QSoundEffect + \brief The SoundEffect element provides a way to play sound effects in qml. + + The following example plays a wav file on mouse click. + + \qml + SoundEffect { + id: playSound + source: "test.wav" + } + MouseRegion { + id: playArea + anchors.fill: parent + onPressed: { + playSound.play() + } + } + \endeml + + \sa SoundEffect +*/ + +/*! + \qmlproperty QUrl SoundEffect::source + + This property provides a way to control the sound to play. +*/ + +/*! + \qmlproperty int SoundEffect::loopCount + + This property provides a way to control the number of times to repeat the sound on each play(). +*/ + +/*! + \qmlproperty int SoundEffect::volume + + This property provides a way to control the volume for playback. +*/ + +/*! + \qmlproperty bool SoundEffect::muted + + This property provides a way to control muting. +*/ + +/*! + \qmlproperty int SoundEffect::duration + + This property holds the duration in milliseconds of the current source audio. +*/ + +/*! + \qmlsignal SoundEffect::sourceChanged() + + This handler is called when the source has changed. +*/ + +/*! + \qmlsignal SoundEffect::loopCountChanged() + + This handler is called when the number of loops has changes. +*/ + +/*! + \qmlsignal SoundEffect::volumeChanged() + + This handler is called when the volume has changed. +*/ + +/*! + \qmlsignal SoundEffect::mutedChanged() + + This handler is called when the mute state has changed. +*/ + +/*! + \qmlsignal SoundEffect::durationChanged() + + This handler is called when the duration has changed. +*/ + +QSoundEffect::QSoundEffect(QObject *parent) : + QObject(parent), + m_loopCount(1), + m_volume(100), + m_muted(false), + m_runningCount(0) +{ + d = new QSoundEffectPrivate(this); + connect(d, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged())); + connect(d, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged())); + connect(d, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged())); + connect(d, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(repeat())); +} + +QSoundEffect::~QSoundEffect() +{ + delete d; +} + +QUrl QSoundEffect::source() const +{ + return d != 0 ? d->media().canonicalUrl() : QUrl(); +} + +void QSoundEffect::setSource(const QUrl &url) +{ + if (d != 0 && d->media().canonicalUrl() == url) + return; + + d->setVolume(m_volume); + d->setMuted(m_muted); + d->setMedia(url); + + if (url.isEmpty()) + return; + + emit sourceChanged(); +} + +int QSoundEffect::loopCount() const +{ + return m_loopCount; +} + +void QSoundEffect::setLoopCount(int loopCount) +{ + if (m_loopCount == loopCount) + return; + + m_loopCount = loopCount; + emit loopCountChanged(); +} + +int QSoundEffect::volume() const +{ + return d != 0 ? d->volume() : m_volume; +} + +void QSoundEffect::setVolume(int volume) +{ + if (m_volume == volume) + return; + + m_volume = volume; + if (d != 0) + d->setVolume(volume); + else + emit volumeChanged(); +} + +bool QSoundEffect::isMuted() const +{ + return d != 0 ? d->isMuted() : m_muted; +} + +void QSoundEffect::setMuted(bool muted) +{ + if (m_muted == muted) + return; + + m_muted = muted; + if (d != 0) + d->setMuted(muted); + else + emit mutedChanged(); +} + +int QSoundEffect::duration() const +{ + return d != 0 ? d->duration() : 0; +} + +void QSoundEffect::play() +{ + m_runningCount = 0; + + if (d != 0) + d->play(); +} + +void QSoundEffect::stop() +{ + if (d != 0) + d->stop(); +} + +void QSoundEffect::repeat() +{ + if (d->state() == QMediaPlayer::StoppedState) { + if (++m_runningCount < m_loopCount) + d->play(); + } +} + diff --git a/src/multimedia/qml/qsoundeffect_p.h b/src/multimedia/qml/qsoundeffect_p.h new file mode 100644 index 0000000..de7070e --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QSOUNDEFFECT_H +#define QSOUNDEFFECT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include +#include + +class QSoundEffectPrivate; +class QSoundEffect : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount NOTIFY loopCountChanged) + Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(int duration READ duration NOTIFY durationChanged) + +public: + explicit QSoundEffect(QObject *parent = 0); + ~QSoundEffect(); + + QUrl source() const; + void setSource(const QUrl &url); + + int loopCount() const; + void setLoopCount(int loopCount); + + int volume() const; + void setVolume(int volume); + + bool isMuted() const; + void setMuted(bool muted); + + int duration() const; + +signals: + void sourceChanged(); + void loopCountChanged(); + void volumeChanged(); + void mutedChanged(); + void durationChanged(); + +public slots: + void play(); + void stop(); + +private slots: + void repeat(); + +private: + Q_DISABLE_COPY(QSoundEffect) + + int m_loopCount; + int m_volume; + bool m_muted; + int m_runningCount; + + QSoundEffectPrivate* d; +}; + +QML_DECLARE_TYPE(QSoundEffect) + +#endif // QSOUNDEFFECT_H diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.cpp b/src/multimedia/qml/qsoundeffect_pulse_p.cpp new file mode 100644 index 0000000..fa2119d --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_pulse_p.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +#include "qmediacontent.h" +#include "qmediaplayer.h" +#include "qsoundeffect_p.h" + +#include "wavedecoder_p.h" + +#include "qsoundeffect_pulse_p.h" + +#if(Q_WS_MAEMO_5) +#include +#endif + +// Less than ideal +#define PA_SCACHE_ENTRY_SIZE_MAX (1024*1024*16) + +namespace +{ +inline pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format) +{ + pa_sample_spec spec; + + spec.rate = format.frequency(); + spec.channels = format.channels(); + + if (format.sampleSize() == 8) + spec.format = PA_SAMPLE_U8; + else if (format.sampleSize() == 16) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break; + } + } + else if (format.sampleSize() == 32) { + switch (format.byteOrder()) { + case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S32BE; break; + case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S32LE; break; + } + } + + return spec; +} + +class PulseDaemon +{ +public: + PulseDaemon():m_prepared(false) + { + prepare(); + } + + ~PulseDaemon() + { + if (m_prepared) + release(); + } + + inline void lock() + { + pa_threaded_mainloop_lock(m_mainLoop); + } + + inline void unlock() + { + pa_threaded_mainloop_unlock(m_mainLoop); + } + + inline pa_context *context() const + { + return m_context; + } + + int volume() + { + return m_volume; + } + +private: + void prepare() + { + m_volume = 100; + + m_mainLoop = pa_threaded_mainloop_new(); + if (m_mainLoop == 0) { + qWarning("PulseAudioService: unable to create pulseaudio mainloop"); + return; + } + + if (pa_threaded_mainloop_start(m_mainLoop) != 0) { + qWarning("PulseAudioService: unable to start pulseaudio mainloop"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + m_mainLoopApi = pa_threaded_mainloop_get_api(m_mainLoop); + + lock(); + m_context = pa_context_new(m_mainLoopApi, QString("QtPulseAudio:%1").arg(::getpid()).toAscii().constData()); + +#if(Q_WS_MAEMO_5) + pa_context_set_state_callback(m_context, context_state_callback, this); +#endif + if (m_context == 0) { + qWarning("PulseAudioService: Unable to create new pulseaudio context"); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + + if (pa_context_connect(m_context, NULL, (pa_context_flags_t)0, NULL) < 0) { + qWarning("PulseAudioService: pa_context_connect() failed"); + pa_context_unref(m_context); + pa_threaded_mainloop_free(m_mainLoop); + return; + } + unlock(); + + m_prepared = true; + } + + void release() + { + if (!m_prepared) return; + pa_threaded_mainloop_stop(m_mainLoop); + pa_threaded_mainloop_free(m_mainLoop); + m_prepared = false; + } + +#if(QWS_MAEMO_5) + static void context_state_callback(pa_context *c, void *userdata) + { + PulseDaemon *self = reinterpret_cast(userdata); + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + case PA_CONTEXT_READY: + pa_ext_stream_restore_set_subscribe_cb(c, &stream_restore_monitor_callback, self); + pa_ext_stream_restore_subscribe(c, 1, NULL, self); + break; + default: + break; + } + } + static void stream_restore_monitor_callback(pa_context *c, void *userdata) + { + PulseDaemon *self = reinterpret_cast(userdata); + pa_ext_stream_restore2_read(c, &stream_restore_info_callback, self); + } + static void stream_restore_info_callback(pa_context *c, const pa_ext_stream_restore2_info *info, + int eol, void *userdata) + { + Q_UNUSED(c) + + PulseDaemon *self = reinterpret_cast(userdata); + + if (!eol) { + if (QString(info->name).startsWith(QLatin1String("sink-input-by-media-role:x-maemo"))) { + const unsigned str_length = 256; + char str[str_length]; + pa_cvolume_snprint(str, str_length, &info->volume); + self->m_volume = QString(str).replace(" ","").replace("%","").mid(2).toInt(); + } + } + } +#endif + + int m_volume; + bool m_prepared; + pa_context *m_context; + pa_threaded_mainloop *m_mainLoop; + pa_mainloop_api *m_mainLoopApi; +}; +} + +Q_GLOBAL_STATIC(PulseDaemon, daemon) + + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_muted(false), + m_playQueued(false), + m_volume(100), + m_duration(0), + m_dataUploaded(0), + m_state(QMediaPlayer::StoppedState), + m_status(QMediaPlayer::NoMedia), + m_reply(0), + m_stream(0), + m_networkAccessManager(0) +{ +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ + delete m_reply; + unloadSample(); +} + +qint64 QSoundEffectPrivate::duration() const +{ + return m_duration; +} + +int QSoundEffectPrivate::volume() const +{ + return m_volume; +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_muted; +} + +QMediaContent QSoundEffectPrivate::media() const +{ + return m_media; +} + +QMediaPlayer::State QSoundEffectPrivate::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const +{ + return m_status; +} + +void QSoundEffectPrivate::play() +{ + if (m_status == QMediaPlayer::LoadingMedia) { + m_playQueued = true; + return; + } + + if (m_status != QMediaPlayer::BufferedMedia || + m_state == QMediaPlayer::PlayingState) + return; + + pa_volume_t m_vol = PA_VOLUME_NORM; + + daemon()->lock(); +#if(Q_WS_MAEMO_5) + m_vol = PA_VOLUME_NORM/100*((daemon()->volume()+m_volume)/2); +#endif + pa_operation_unref( + pa_context_play_sample(daemon()->context(), + m_name.constData(), + 0, + m_vol, + play_callback, + this) + ); + daemon()->unlock(); + + m_playbackTime.start(); + + emit stateChanged(m_state = QMediaPlayer::PlayingState); +} + +void QSoundEffectPrivate::stop() +{ + emit stateChanged(m_state = QMediaPlayer::StoppedState); +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + m_volume = volume; +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; +} + +void QSoundEffectPrivate::setMedia(const QMediaContent &media) +{ + if (media.isNull()) { + m_media = QMediaContent(); + unloadSample(); + return; + } + if (m_media == media) + return; + m_media = media; + + if (m_networkAccessManager == 0) + m_networkAccessManager = new QNetworkAccessManager(this); + + m_stream = m_networkAccessManager->get(QNetworkRequest(m_media.canonicalUrl())); + + unloadSample(); + loadSample(); + + emit mediaChanged(m_media); +} + +void QSoundEffectPrivate::decoderReady() +{ + if (m_waveDecoder->size() >= PA_SCACHE_ENTRY_SIZE_MAX) { + m_status = QMediaPlayer::InvalidMedia; + emit mediaStatusChanged(m_status); + qWarning("QtPulseAudio: attempting to load to large a sample"); + return; + } + + if (m_name.isNull()) + m_name = QString("QtPulseSample-%1-%2").arg(::getpid()).arg(int(this)).toUtf8(); + + pa_sample_spec spec = audioFormatToSampleSpec(m_waveDecoder->audioFormat()); + + daemon()->lock(); + pa_stream *stream = pa_stream_new(daemon()->context(), m_name.constData(), &spec, 0); + pa_stream_set_state_callback(stream, stream_state_callback, this); + pa_stream_set_write_callback(stream, stream_write_callback, this); + pa_stream_connect_upload(stream, (size_t)m_waveDecoder->size()); + daemon()->unlock(); +} + +void QSoundEffectPrivate::decoderError() +{ + emit mediaStatusChanged(m_status = QMediaPlayer::InvalidMedia); +} + +void QSoundEffectPrivate::checkPlayTime() +{ + int elapsed = m_playbackTime.elapsed(); + + if (elapsed >= m_duration) { + m_state = QMediaPlayer::StoppedState; + emit stateChanged(m_state); + } + else + startTimer(m_duration - elapsed); +} + +void QSoundEffectPrivate::loadSample() +{ + m_waveDecoder = new WaveDecoder(m_stream); + connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady())); + connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError())); + + m_status = QMediaPlayer::LoadingMedia; + emit mediaStatusChanged(m_status); +} + +void QSoundEffectPrivate::unloadSample() +{ + if (m_status != QMediaPlayer::BufferedMedia) + return; + + m_status = QMediaPlayer::NoMedia; + + daemon()->lock(); + pa_context_remove_sample(daemon()->context(), m_name.constData(), NULL, NULL); + daemon()->unlock(); + + m_duration = 0; + m_dataUploaded = 0; +} + +void QSoundEffectPrivate::timerEvent(QTimerEvent *event) +{ + if (m_state == QMediaPlayer::PlayingState) { + m_state = QMediaPlayer::StoppedState; + emit stateChanged(m_state); + } + + killTimer(event->timerId()); +} + +void QSoundEffectPrivate::stream_write_callback(pa_stream *s, size_t length, void *userdata) +{ + Q_UNUSED(length); + + QSoundEffectPrivate *self = reinterpret_cast(userdata); + + size_t bufferSize = qMin(pa_stream_writable_size(s), + size_t(self->m_waveDecoder->bytesAvailable())); + char buffer[bufferSize]; + + size_t len = 0; + while (len < length) { + qint64 read = self->m_waveDecoder->read(buffer, qMin(bufferSize, length -len)); + if (read > 0) { + if (pa_stream_write(s, buffer, size_t(read), 0, 0, PA_SEEK_RELATIVE) == 0) + len += size_t(read); + else + break; + } + } + self->m_dataUploaded += len; + + if (self->m_waveDecoder->size() == self->m_dataUploaded) { + pa_stream_finish_upload(s); + + self->m_duration = self->m_waveDecoder->duration(); + emit self->durationChanged(self->m_duration); + + self->m_status = QMediaPlayer::BufferedMedia; + emit self->mediaStatusChanged(self->m_status); + + self->m_waveDecoder->deleteLater(); + if (!self->m_media.isNull()) + self->m_stream->deleteLater(); + + if (self->m_playQueued) { + self->m_playQueued = false; + QMetaObject::invokeMethod(self, "play"); + } + } +} + +void QSoundEffectPrivate::stream_state_callback(pa_stream *s, void *userdata) +{ + QSoundEffectPrivate *self = reinterpret_cast(userdata); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_READY: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_FAILED: + default: + self->m_status = QMediaPlayer::InvalidMedia; + emit self->mediaStatusChanged(self->m_status); + break; + } +} + +void QSoundEffectPrivate::play_callback(pa_context *c, int success, void *userdata) +{ + Q_UNUSED(c); + + QSoundEffectPrivate *self = reinterpret_cast(userdata); + + if (success == 1) + QMetaObject::invokeMethod(self, "checkPlayTime", Qt::QueuedConnection); + else { + self->m_state = QMediaPlayer::StoppedState; + emit self->stateChanged(self->m_state); + } +} + diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.h b/src/multimedia/qml/qsoundeffect_pulse_p.h new file mode 100644 index 0000000..05728d0 --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_pulse_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QSOUNDEFFECT_PULSE_H +#define QSOUNDEFFECT_PULSE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include + +#include + +#include + +#include "qsoundeffect_p.h" + +#include + +QTM_USE_NAMESPACE + +class QNetworkReply; +class QNetworkAccessManager; +class WaveDecoder; + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + qint64 duration() const; + int volume() const; + bool isMuted() const; + QMediaContent media() const; + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + +public Q_SLOTS: + void play(); + void stop(); + void setVolume(int volume); + void setMuted(bool muted); + void setMedia(const QMediaContent &media); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void stateChanged(QMediaPlayer::State newState); + void durationChanged(qint64 duration); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QMediaPlayer::Error error); + +private slots: + void decoderReady(); + void decoderError(); + void checkPlayTime(); + +private: + void loadSample(); + void unloadSample(); + + void timerEvent(QTimerEvent *event); + + static void stream_write_callback(pa_stream *s, size_t length, void *userdata); + static void stream_state_callback(pa_stream *s, void *userdata); + static void play_callback(pa_context *c, int success, void *userdata); + + bool m_muted; + bool m_playQueued; + int m_volume; + int m_duration; + int m_dataUploaded; + QTime m_playbackTime; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_status; + QByteArray m_name; + QMediaContent m_media; + QNetworkReply *m_reply; + WaveDecoder *m_waveDecoder; + QIODevice *m_stream; + QNetworkAccessManager *m_networkAccessManager; +}; + +#endif // QSOUNDEFFECT_PULSE_H diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.cpp b/src/multimedia/qml/qsoundeffect_qmedia_p.cpp new file mode 100644 index 0000000..26354a5 --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_qmedia_p.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include "qmediacontent.h" +#include "qmediaplayer.h" + +#include "qsoundeffect_p.h" +#include "qsoundeffect_qmedia_p.h" + + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_muted(false), + m_volume(100), + m_player(0) +{ +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ + if (m_player) delete m_player; +} + +qint64 QSoundEffectPrivate::duration() const +{ + if (m_player) return m_player->duration(); + + return 0; +} + +int QSoundEffectPrivate::volume() const +{ + if (m_player) return m_player->volume(); + + return m_volume; +} + +bool QSoundEffectPrivate::isMuted() const +{ + if (m_player) return m_player->isMuted(); + + return m_muted; +} + +QMediaContent QSoundEffectPrivate::media() const +{ + if (m_player) return m_player->media(); + + return QMediaContent(); +} + +QMediaPlayer::State QSoundEffectPrivate::state() const +{ + if (m_player) return m_player->state(); + + return QMediaPlayer::StoppedState; +} + +QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const +{ + if (m_player) return m_player->mediaStatus(); + + return QMediaPlayer::UnknownMediaStatus; +} + +void QSoundEffectPrivate::play() +{ + if (m_player && !m_player->isMuted()) + m_player->play(); +} + +void QSoundEffectPrivate::stop() +{ + if (m_player) + m_player->stop(); +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + m_volume = volume; + + if (m_player) + m_player->setVolume(volume); +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; + + if (m_player) + m_player->setMuted(muted); +} + +void QSoundEffectPrivate::setMedia(const QMediaContent &media) +{ + if (media.isNull()) + return; + + if (m_player == 0) { + m_player = new QMediaPlayer(this, QMediaPlayer::LowLatency); + m_player->setVolume(m_volume); + m_player->setMuted(m_muted); + + connect(m_player, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int))); + connect(m_player, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(m_player, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(m_player, SIGNAL(stateChanged(QMediaPlayer::State)), SIGNAL(stateChanged(QMediaPlayer::State))); + } + + m_player->setMedia(media.canonicalUrl()); +} + diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.h b/src/multimedia/qml/qsoundeffect_qmedia_p.h new file mode 100644 index 0000000..8b3165a --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_qmedia_p.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QSOUNDEFFECT_QMEDIA_H +#define QSOUNDEFFECT_QMEDIA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include + +#include +#include + +#include "qsoundeffect_p.h" + +QTM_USE_NAMESPACE + +class WaveDecoder; + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + qint64 duration() const; + int volume() const; + bool isMuted() const; + QMediaContent media() const; + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + +public Q_SLOTS: + void play(); + void stop(); + void setVolume(int volume); + void setMuted(bool muted); + void setMedia(const QMediaContent &media); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void stateChanged(QMediaPlayer::State newState); + void durationChanged(qint64 duration); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QMediaPlayer::Error error); + +private: + bool m_muted; + int m_volume; + QMediaPlayer *m_player; +}; + +#endif // QSOUNDEFFECT_QMEDIA_H diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.cpp b/src/multimedia/qml/qsoundeffect_qsound_p.cpp new file mode 100644 index 0000000..fd40a05 --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_qsound_p.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +#include "qmediacontent.h" +#include "qmediaplayer.h" +#include "qsoundeffect_p.h" + +#include "wavedecoder_p.h" + +#include "qsoundeffect_qsound_p.h" + + +QSoundEffectPrivate::QSoundEffectPrivate(QObject* parent): + QObject(parent), + m_queued(false), + m_muted(false), + m_state(QMediaPlayer::StoppedState), + m_status(QMediaPlayer::NoMedia), + m_file(0), + m_sound(0) +{ + m_timer = new QTimer(this); + connect(m_timer,SIGNAL(timeout()),SLOT(checkPlayTime())); + m_media = QMediaContent(); +} + +QSoundEffectPrivate::~QSoundEffectPrivate() +{ + if (m_sound) delete m_sound; + if (m_waveDecoder) delete m_waveDecoder; + m_file->close(); +} + +qint64 QSoundEffectPrivate::duration() const +{ + if (m_waveDecoder) + return m_waveDecoder->size(); + + return 0; +} + +int QSoundEffectPrivate::volume() const +{ + return 100; +} + +bool QSoundEffectPrivate::isMuted() const +{ + return m_muted; +} + +QMediaContent QSoundEffectPrivate::media() const +{ + return m_media; +} + +QMediaPlayer::State QSoundEffectPrivate::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QSoundEffectPrivate::mediaStatus() const +{ + return m_status; +} + +void QSoundEffectPrivate::play() +{ + if (m_sound && !m_muted) { + m_queued = false; + m_timer->start(20); + m_playbackTime.start(); + m_sound->play(); + emit stateChanged(m_state = QMediaPlayer::PlayingState); + } else if (m_status == QMediaPlayer::LoadingMedia) + m_queued = true; +} + +void QSoundEffectPrivate::stop() +{ + m_timer->stop(); + + if (m_sound) { + m_sound->stop(); + emit stateChanged(m_state = QMediaPlayer::StoppedState); + } +} + +void QSoundEffectPrivate::setVolume(int volume) +{ + Q_UNUSED(volume) +} + +void QSoundEffectPrivate::setMuted(bool muted) +{ + m_muted = muted; +} + +void QSoundEffectPrivate::setMedia(const QMediaContent &media) +{ + m_queued = false; + + if (media.isNull() || media.canonicalUrl().scheme() != "file") { + m_media = QMediaContent(); + return; + } + if (m_media == media) + return; + + m_media = media; + m_file = new QFile(m_media.canonicalUrl().toLocalFile()); + m_file->open(QIODevice::ReadOnly|QIODevice::Unbuffered); + + unloadSample(); + loadSample(); + + emit mediaChanged(m_media); +} + +void QSoundEffectPrivate::decoderReady() +{ + m_file->close(); + m_sound = new QSound(m_media.canonicalUrl().toLocalFile()); + emit mediaStatusChanged(m_status = QMediaPlayer::LoadedMedia); + + if (m_queued) + play(); +} + +void QSoundEffectPrivate::decoderError() +{ + m_file->close(); + emit mediaStatusChanged(m_status = QMediaPlayer::InvalidMedia); +} + +void QSoundEffectPrivate::checkPlayTime() +{ + if (m_sound->isFinished()) { + m_timer->stop(); + m_state = QMediaPlayer::StoppedState; + emit stateChanged(m_state); + } +} + +void QSoundEffectPrivate::loadSample() +{ + m_waveDecoder = new WaveDecoder(m_file); + connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady())); + connect(m_waveDecoder, SIGNAL(invalidFormat()), SLOT(decoderError())); + + m_status = QMediaPlayer::LoadingMedia; + emit mediaStatusChanged(m_status); +} + +void QSoundEffectPrivate::unloadSample() +{ + if (m_sound == 0) + return; + + m_status = QMediaPlayer::NoMedia; + + if (m_sound) + delete m_sound; + + m_sound = 0; +} + diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.h b/src/multimedia/qml/qsoundeffect_qsound_p.h new file mode 100644 index 0000000..ac47e8f --- /dev/null +++ b/src/multimedia/qml/qsoundeffect_qsound_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 QSOUNDEFFECT_QSOUND_H +#define QSOUNDEFFECT_QSOUND_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include + +#include + +#include "qsoundeffect_p.h" + + +QTM_USE_NAMESPACE + +class QTimer; +class QSound; +class QFile; +class WaveDecoder; + +class QSoundEffectPrivate : public QObject +{ + Q_OBJECT +public: + explicit QSoundEffectPrivate(QObject* parent); + ~QSoundEffectPrivate(); + + qint64 duration() const; + int volume() const; + bool isMuted() const; + QMediaContent media() const; + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + +public Q_SLOTS: + void play(); + void stop(); + void setVolume(int volume); + void setMuted(bool muted); + void setMedia(const QMediaContent &media); + +Q_SIGNALS: + void mediaChanged(const QMediaContent &media); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void stateChanged(QMediaPlayer::State newState); + void durationChanged(qint64 duration); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void error(QMediaPlayer::Error error); + +private slots: + void decoderReady(); + void decoderError(); + void checkPlayTime(); + +private: + void loadSample(); + void unloadSample(); + + bool m_queued; + bool m_muted; + QTime m_playbackTime; + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_status; + QFile *m_file; + QByteArray m_name; + QMediaContent m_media; + WaveDecoder *m_waveDecoder; + QSound *m_sound; + QTimer *m_timer; +}; + +#endif // QSOUNDEFFECT_QSOUND_H diff --git a/src/multimedia/qml/wavedecoder_p.cpp b/src/multimedia/qml/wavedecoder_p.cpp new file mode 100644 index 0000000..f45f25c --- /dev/null +++ b/src/multimedia/qml/wavedecoder_p.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 "wavedecoder_p.h" + +#include +#include + +WaveDecoder::WaveDecoder(QIODevice *s, QObject *parent): + QIODevice(parent), + haveFormat(false), + dataSize(0), + remaining(0), + source(s) +{ + open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + if (source->bytesAvailable() >= sizeof(CombinedHeader)) + QTimer::singleShot(0, this, SLOT(handleData())); + else + connect(source, SIGNAL(readyRead()), SLOT(handleData())); +} + +WaveDecoder::~WaveDecoder() +{ +} + +QAudioFormat WaveDecoder::audioFormat() const +{ + return format; +} + +int WaveDecoder::duration() const +{ + return size() * 1000 / (format.sampleSize() / 8) / format.channels() / format.frequency(); +} + +qint64 WaveDecoder::size() const +{ + return haveFormat ? dataSize : 0; +} + +bool WaveDecoder::isSequential() const +{ + return source->isSequential(); +} + +qint64 WaveDecoder::bytesAvailable() const +{ + return haveFormat ? source->bytesAvailable() : 0; +} + +qint64 WaveDecoder::readData(char *data, qint64 maxlen) +{ + return haveFormat ? source->read(data, maxlen) : 0; +} + +qint64 WaveDecoder::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return -1; +} + +void WaveDecoder::handleData() +{ + if (source->bytesAvailable() < sizeof(CombinedHeader)) + return; + + source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); + source->read((char*)&header, sizeof(CombinedHeader)); + + if (qstrncmp(header.riff.descriptor.id, "RIFF", 4) != 0 || + qstrncmp(header.riff.type, "WAVE", 4) != 0 || + qstrncmp(header.wave.descriptor.id, "fmt ", 4) != 0 || + (header.wave.audioFormat != 0 && header.wave.audioFormat != 1) || + qstrncmp(header.data.descriptor.id, "data", 4) != 0) { + + emit invalidFormat(); + } + else { + int bps = qFromLittleEndian(header.wave.bitsPerSample); + + format.setCodec("audio/pcm"); + format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setFrequency(qFromLittleEndian(header.wave.sampleRate)); + format.setSampleSize(bps); + format.setChannels(qFromLittleEndian(header.wave.numChannels)); + + dataSize = qFromLittleEndian(header.data.descriptor.size); + + haveFormat = true; + connect(source, SIGNAL(readyRead()), SIGNAL(readyRead())); + emit formatKnown(); + } +} diff --git a/src/multimedia/qml/wavedecoder_p.h b/src/multimedia/qml/wavedecoder_p.h new file mode 100644 index 0000000..010fec6 --- /dev/null +++ b/src/multimedia/qml/wavedecoder_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $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 WAVEDECODER_H +#define WAVEDECODER_H + +#include +#include + +class WaveDecoder : public QIODevice +{ +Q_OBJECT + +public: + explicit WaveDecoder(QIODevice *source, QObject *parent = 0); + ~WaveDecoder(); + + QAudioFormat audioFormat() const; + int duration() const; + + qint64 size() const; + bool isSequential() const; + qint64 bytesAvailable() const; + +signals: + void formatKnown(); + void invalidFormat(); + +private slots: + void handleData(); + +private: + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + + struct chunk + { + char id[4]; + quint32 size; + }; + struct RIFFHeader + { + chunk descriptor; + char type[4]; + }; + struct WAVEHeader + { + chunk descriptor; + quint16 audioFormat; + quint16 numChannels; + quint32 sampleRate; + quint32 byteRate; + quint16 blockAlign; + quint16 bitsPerSample; + }; + struct DATAHeader + { + chunk descriptor; + }; + struct CombinedHeader + { + RIFFHeader riff; + WAVEHeader wave; + DATAHeader data; + }; + + bool haveFormat; + qint64 dataSize; + qint64 remaining; + QAudioFormat format; + QIODevice *source; + CombinedHeader header; +}; + +#endif // WAVEDECODER_H -- cgit v0.12 From 6d14ccae6d532a8560da05cdc85d7646ea2744e6 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 12:57:52 +0100 Subject: Recreate cached vertex arrays for QStaticText when drawn to new context If you draw the QStaticText object to a new QGLWidget, then we need to recreate the VBOs (if the vertex arrays are cached.) It would be possible to share this across contexts, which can be implemented later as an extra optimization for switching between different target devices. --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index aec2ade..ed0f708 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1345,9 +1345,17 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QVector indices; #endif - if (staticTextItem->userData == 0 - || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData - || staticTextItem->userDataNeedsUpdate) { + bool recreateVertexArrays = false; + if (staticTextItem->userDataNeedsUpdate) + recreateVertexArrays = true; + else if (staticTextItem->userData == 0) + recreateVertexArrays = true; + else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) + recreateVertexArrays = true; + else if (static_cast(staticTextItem->userData)->ctx != ctx) + recreateVertexArrays = true; + + if (recreateVertexArrays) { vertexCoordinateArray.clear(); textureCoordinateArray.clear(); -- cgit v0.12 From 29a48b2d76b855b2f7401a25d6114339208fd4d4 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 13:03:42 +0100 Subject: Add explanatory comment to QGL2PaintEngineExPrivate::drawCachedGlyphs A small hack to turn off the current matrix when drawing QStaticText, since its coordinates are already transformed. --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index ed0f708..917a1a2 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1451,6 +1451,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QBrush pensBrush = q->state()->pen.brush(); setBrush(pensBrush); + // When painting a QStaticTextItem, the glyph positions are already in device coordinates, + // therefore we temporarily set an identity matrix on the painter for the draw call to + // avoid transforming the positions twice. QTransform old = s->matrix; if (includeMatrixInCache) s->matrix = QTransform(); -- cgit v0.12 From f1815f8d19b32655597b17efad4b594466abb93b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 13:22:37 +0100 Subject: Use state in QPaintBuffer rather than search for the transform cmd No reason to look through all the commands, since we have the transform saved in the state. Reviewed-by: Trond --- src/gui/painting/qpaintbuffer.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index b0a3d7a..632dea7 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -966,17 +966,8 @@ void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) { QString text = QString(staticTextItem->chars, staticTextItem->numChars); - QTransform xform; - for (int i=buffer->commands.size()-1; i>=0; --i) { - const QPaintBufferCommand &cmd = buffer->commands.at(i); - if (cmd.id == QPaintBufferPrivate::Cmd_SetTransform) { - xform = qVariantValue(buffer->variants.at(cmd.offset)); - break; - } - } - QStaticText staticText(text); - staticText.prepare(xform, staticTextItem->font); + staticText.prepare(state()->matrix, staticTextItem->font); QVariantList variants; variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText); -- cgit v0.12 From 88b1aa6b3c0e03107db111921ef69de814f1dc06 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 13:38:18 +0100 Subject: Clean up VBOs cached in QStaticText when context is deleted Follow pattern from qpaintengine_opengl.cpp and listen for the destroyed signal of the GL context. If the context that owns the VBOs is deleted, then we delete the VBOs as well. --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 54 ++++++++++++++-------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 917a1a2..c66472c 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1281,32 +1281,48 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem #define QSTATICTEXT_USE_INDEXARRAY -namespace { +class QOpenGLStaticTextUserData: public QObject, public QStaticTextUserData +{ + Q_OBJECT +public: + QOpenGLStaticTextUserData(QGLContext *glContext) + : QStaticTextUserData(OpenGLUserData), + vertexCoordVBOId(0), textureCoordVBOId(0), ctx(glContext) + { + connect(QGLSignalProxy::instance(), + SIGNAL(aboutToDestroyContext(const QGLContext*)), + SLOT(cleanupGLContextRefs(const QGLContext*))); + } - class QOpenGLStaticTextUserData: public QStaticTextUserData + ~QOpenGLStaticTextUserData() { - public: - QOpenGLStaticTextUserData(QGLContext *glContext) - : QStaticTextUserData(OpenGLUserData), - vertexCoordVBOId(0), textureCoordVBOId(0), ctx(glContext) {} - ~QOpenGLStaticTextUserData() - { + if (ctx != 0) + cleanupGLContextRefs(ctx); + } + + QGLContext *ctx; + GLuint vertexCoordVBOId; + GLuint textureCoordVBOId; + +#if defined(QSTATICTEXT_USE_INDEXARRAY) + QVector indices; +#endif + +public Q_SLOTS: + void cleanupGLContextRefs(const QGLContext *context) + { + if (context == ctx) { if (vertexCoordVBOId != 0) glDeleteBuffers(1, &vertexCoordVBOId); if (textureCoordVBOId != 0) glDeleteBuffers(1, &textureCoordVBOId); - } - - QGLContext *ctx; - GLuint vertexCoordVBOId; - GLuint textureCoordVBOId; -#if defined(QSTATICTEXT_USE_INDEXARRAY) - QVector indices; -#endif - }; -} + vertexCoordVBOId = 0; + textureCoordVBOId = 0; + } + } +}; void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem, @@ -2175,3 +2191,5 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() } QT_END_NAMESPACE + +#include "qpaintengineex_opengl2.moc" -- cgit v0.12 From 9426178288bd23cdc280b17779c2e8ebaeb3771e Mon Sep 17 00:00:00 2001 From: David Boddie Date: Fri, 5 Feb 2010 15:55:11 +0100 Subject: qdoc: Standardized encoding names and updated the Chinese config files. Reviewed-by: Trust Me --- tools/qdoc3/linguistgenerator.cpp | 4 +- tools/qdoc3/test/qt-api-only_zh_CN.qdocconf | 30 +++++++ tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf | 95 +++++++++++++++++++++++ tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf | 25 ++++++ 4 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 tools/qdoc3/test/qt-api-only_zh_CN.qdocconf create mode 100644 tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf create mode 100644 tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf diff --git a/tools/qdoc3/linguistgenerator.cpp b/tools/qdoc3/linguistgenerator.cpp index d1bd22d..21678e0 100644 --- a/tools/qdoc3/linguistgenerator.cpp +++ b/tools/qdoc3/linguistgenerator.cpp @@ -89,7 +89,7 @@ QString LinguistGenerator::fileExtension(const Node * /* node */) void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker *marker) { - out().setCodec("utf-8"); + out().setCodec("UTF-8"); QDomDocument document("TS"); QDomElement documentElement = document.createElement("TS"); @@ -100,7 +100,7 @@ void LinguistGenerator::generateClassLikeNode(const InnerNode *inner, CodeMarker documentElement.appendChild(element); QDomProcessingInstruction process = document.createProcessingInstruction( - "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("utf-8")); + "xml", QString("version=\"1.0\" encoding=\"%1\"").arg("UTF-8")); document.appendChild(process); document.appendChild(documentElement); diff --git a/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf new file mode 100644 index 0000000..c722ee8 --- /dev/null +++ b/tools/qdoc3/test/qt-api-only_zh_CN.qdocconf @@ -0,0 +1,30 @@ +include(qt-build-docs_zh_CN.qdocconf) + +# Ensures that the generated index contains a URL that can be used by the +# tools documentation (assistant.qdocconf, designer.qdocconf, linguist.qdocconf, +# qmake.qdocconf). + +url = ./ + +# Ensures that the documentation for the tools is not included in the generated +# .qhp file. + +qhp.Qt.excluded += $QT_SOURCE_TREE/doc/src/development/assistant-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/simpletextviewer.qdoc \ + $QT_SOURCE_TREE/doc/src/development/designer-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/calculatorbuilder.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/calculatorform.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/customwidgetplugin.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/taskmenuextension.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/containerextension.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/worldtimeclockbuilder.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/worldtimeclockplugin.qdoc \ + $QT_SOURCE_TREE/doc/src/internationalization/linguist-manual.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/hellotr.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/arrowpad.qdoc \ + $QT_SOURCE_TREE/doc/src/examples/trollprint.qdoc \ + $QT_SOURCE_TREE/doc/src/development/qmake-manual.qdoc + +outputdir = $QT_BUILD_TREE/doc-build/html-qt_zh_CN +tagfile = $QT_BUILD_TREE/doc-build/html-qt_zh_CN/qt.tags +base = file:$QT_BUILD_TREE/doc-build/html-qt_zh_CN diff --git a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf new file mode 100644 index 0000000..4c67856 --- /dev/null +++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf @@ -0,0 +1,95 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates_zh_CN.qdocconf) +include(qt-defines.qdocconf) + +project = Qt +description = Qt Reference Documentation +url = http://qt.nokia.com/doc/zh_CN/4.7 + +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = cn-ZH + +indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index + +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ + QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ + Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ + QAxServer QtUiTools QtTest QtDBus + +edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest +edition.DesktopLight.groups = -graphicsview-api + +qhp.projects = Qt + +qhp.Qt.file = qt.qhp +qhp.Qt.namespace = com.trolltech.qt.470 +qhp.Qt.virtualFolder = qdoc +qhp.Qt.indexTitle = Qt Reference Documentation +qhp.Qt.indexRoot = + +# Files not referenced in any qdoc file (last four are needed by qtdemo) +# See also extraimages.HTML +qhp.Qt.extraFiles = classic.css \ + images/qt-logo.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + images/stylesheet-coffee-plastique.png + +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 +qhp.Qt.subprojects = tutorials +qhp.Qt.subprojects.tutorials.title = Tutorials +qhp.Qt.subprojects.tutorials.indexTitle = Tutorials +qhp.Qt.subprojects.tutorials.selectors = fake:example + +language = Cpp + +sourcedirs = $QT_SOURCE_TREE/doc/src/zh_CN + +excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ + $QT_SOURCE_TREE/src/3rdparty/des \ + $QT_SOURCE_TREE/src/3rdparty/freetype \ + $QT_SOURCE_TREE/src/3rdparty/harfbuzz \ + $QT_SOURCE_TREE/src/3rdparty/kdebase \ + $QT_SOURCE_TREE/src/3rdparty/libjpeg \ + $QT_SOURCE_TREE/src/3rdparty/libmng \ + $QT_SOURCE_TREE/src/3rdparty/libpng \ + $QT_SOURCE_TREE/src/3rdparty/libtiff \ + $QT_SOURCE_TREE/src/3rdparty/md4 \ + $QT_SOURCE_TREE/src/3rdparty/md5 \ + $QT_SOURCE_TREE/src/3rdparty/patches \ + $QT_SOURCE_TREE/src/3rdparty/sha1 \ + $QT_SOURCE_TREE/src/3rdparty/sqlite \ + $QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \ + $QT_SOURCE_TREE/src/3rdparty/wintab \ + $QT_SOURCE_TREE/src/3rdparty/zlib \ + $QT_SOURCE_TREE/doc/src/snippets \ + $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ + $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ + $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ + $QT_SOURCE_TREE/src/3rdparty/phonon/waveout + +sources.fileextensions = "*.cpp *.qdoc *.mm" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" +examples.imageextensions = "*.png" + +exampledirs = $QT_SOURCE_TREE/doc/src \ + $QT_SOURCE_TREE/examples \ + $QT_SOURCE_TREE/examples/tutorials \ + $QT_SOURCE_TREE \ + $QT_SOURCE_TREE/qmake/examples \ + $QT_SOURCE_TREE/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QT_SOURCE_TREE/doc/src/images \ + $QT_SOURCE_TREE/examples +outputdir = $QT_BUILD_TREE/doc/html_zh_CN +tagfile = $QT_BUILD_TREE/doc/html_zh_CN/qt.tags +base = file:$QT_BUILD_TREE/doc/html_zh_CN + +HTML.generatemacrefs = "true" diff --git a/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf new file mode 100644 index 0000000..5fb68cf --- /dev/null +++ b/tools/qdoc3/test/qt-html-templates_zh_CN.qdocconf @@ -0,0 +1,25 @@ +HTML.stylesheets = classic.css +HTML.postheader = "\n" \ + "\n" \ + "\n" \ + "" \ + "" \ + "
    " \ + "" \ + "  " \ + "" \ + "主页 ·" \ + " " \ + "所有类 ·" \ + " " \ + "所有函数 ·" \ + " " \ + "简介" \ + "
    " + +HTML.footer = "


    \n" \ + "\n" \ + "\n" \ + "\n" \ + "\n" \ + "
    ç‰ˆæƒæ‰€æœ‰ © 2010 诺基亚公å¸å’Œ/或其å­å…¬å¸å•†æ ‡
    Qt \\version
    " -- cgit v0.12 From 3d89703be18d13cc4a571ce875cff3ec6cca498f Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 16:16:16 +0100 Subject: Temporarily remove QPainter::drawStaticText() for Qt 4.6.x integration We can't add new symbols to QPainter for Qt 4.6.x, as we would not be able to remove them again if we regretted the API. Hence, I've made removable symbols instead, a private global function and a drawStaticText() in QPainterPrivate. In order to tie things together, I needed a static private-getter in QPainterPrivate, and hence it had to be a friend of QPainter. Reviewed-by: Trond --- src/gui/painting/qpaintbuffer.cpp | 2 +- src/gui/painting/qpainter.cpp | 87 +++++++++++++----------------- src/gui/painting/qpainter.h | 16 +----- src/gui/painting/qpainter_p.h | 6 +++ src/gui/text/qstatictext.cpp | 82 +++++++++++++++------------- src/gui/text/qstatictext_p.h | 2 +- src/gui/text/qstatictext_p_p.h | 1 + tests/auto/qstatictext/tst_qstatictext.cpp | 29 +++++----- 8 files changed, 106 insertions(+), 119 deletions(-) diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 632dea7..51eb681 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -1448,7 +1448,7 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) QStaticText text(variants.at(0).value()); painter->setFont(font); - painter->drawStaticText(QPointF(0, 0), text); + qt_draw_static_text(painter, QPointF(0, 0), text); break; } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 4338a5f..0d47260 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5707,36 +5707,23 @@ void QPainter::drawText(const QPointF &p, const QString &str) drawText(p, str, 0, 0); } -/*! - \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) - - \internal - - \overload -*/ - -/*! - \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) - - \internal - - \overload -*/ - -/*! - Draws the given \a staticText beginning at the given \a position. +QPainterPrivate *QPainterPrivate::get(QPainter *p) +{ + return p->d_ptr.data(); +} - \internal +void qt_draw_static_text(QPainter *p, const QPointF &position, const QStaticText &text) +{ + QPainterPrivate *prv = QPainterPrivate::get(p); + Q_ASSERT(prv != 0); - This function can be used to optimize drawing text if the text and its layout is updated - seldomly. + prv->drawStaticText(position, text); +} - \sa QStaticText -*/ -void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) +void QPainterPrivate::drawStaticText(const QPointF &position, const QStaticText &staticText) { - Q_D(QPainter); - if (!d->engine || staticText.isEmpty() || pen().style() == Qt::NoPen) + Q_Q(QPainter); + if (!engine || staticText.isEmpty() || q->pen().style() == Qt::NoPen) return; QStaticTextPrivate *staticText_d = @@ -5744,31 +5731,31 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // 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()) { + if (extended == 0 || !state->matrix.isAffine()) { if (staticText_d->size.isValid()) - drawText(QRectF(position, staticText_d->size), staticText_d->text); + q->drawText(QRectF(position, staticText_d->size), staticText_d->text); else - drawText(position, staticText_d->text); + q->drawText(position, staticText_d->text); 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; + QPointF transformedPosition = position * state->matrix; + QTransform matrix = 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, + if (state->matrix.isTranslating()) { + qreal m11 = state->matrix.m11(); + qreal m12 = state->matrix.m12(); + qreal m13 = state->matrix.m13(); + qreal m21 = state->matrix.m21(); + qreal m22 = state->matrix.m22(); + qreal m23 = state->matrix.m23(); + qreal m33 = state->matrix.m33(); + + state->matrix.setMatrix(m11, m12, m13, m21, m22, m23, 0.0, 0.0, m33); } @@ -5776,21 +5763,21 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // 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; + if (staticText_d->matrix != state->matrix) { + staticText_d->matrix = state->matrix; staticTextNeedsReinit = true; } bool restoreWhenFinished = false; if (staticText_d->needsClipRect) { - save(); - setClipRect(QRectF(position, staticText_d->size)); + q->save(); + q->setClipRect(QRectF(position, staticText_d->size)); restoreWhenFinished = true; } - if (font() != staticText_d->font) { - staticText_d->font = font(); + if (q->font() != staticText_d->font) { + staticText_d->font = q->font(); staticTextNeedsReinit = true; } @@ -5817,14 +5804,14 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static for (int i=0; iitemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; - d->extended->drawStaticTextItem(item); + extended->drawStaticTextItem(item); } if (restoreWhenFinished) - restore(); + q->restore(); if (matrix.isTranslating()) - d->state->matrix = matrix; + state->matrix = matrix; } /*! diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 181eba7..088a973 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -78,7 +78,6 @@ class QPolygon; class QTextItem; class QMatrix; class QTransform; -class QStaticText; class QPainterPrivateDeleter; @@ -370,10 +369,6 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; - inline void drawStaticText(int x, int y, const QStaticText &staticText); - inline void drawStaticText(const QPoint &p, const QStaticText &staticText); - void drawStaticText(const QPointF &p, 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); @@ -527,6 +522,7 @@ private: friend class QRasterPaintEngine; friend class QAlphaPaintEngine; friend class QPreviewPaintEngine; + friend class QPainterPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QPainter::RenderHints) @@ -911,16 +907,6 @@ inline void QPainter::drawText(const QPoint &p, const QString &s) drawText(QPointF(p), s); } -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::drawText(int x, int y, int w, int h, int flags, const QString &str, QRect *br) { drawText(QRect(x, y, w, h), flags, str, br); diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 02a91aa..2979de6 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -70,6 +70,7 @@ QT_BEGIN_NAMESPACE class QPaintEngine; class QEmulationPaintEngine; class QPaintEngineEx; +class QStaticText; struct QTLWExtra; @@ -229,6 +230,8 @@ public: void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); + void drawStaticText(const QPointF &position, const QStaticText &staticText); + void updateMatrix(); void updateInvMatrix(); @@ -242,6 +245,8 @@ public: static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); void detachPainterPrivate(QPainter *q); + static QPainterPrivate *get(QPainter *p); + QPaintDevice *device; QPaintDevice *original_device; QPaintDevice *helper_device; @@ -252,6 +257,7 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); +Q_GUI_EXPORT void qt_draw_static_text(QPainter *p, const QPointF &position, const QStaticText &text); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 922920e..659324b 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -113,8 +113,8 @@ QT_BEGIN_NAMESPACE /*! Constructs an empty QStaticText */ -QStaticText::QStaticText() - : d_ptr(new QStaticTextPrivate) +QStaticText::QStaticText() + : data(new QStaticTextPrivate) { } @@ -126,11 +126,11 @@ QStaticText::QStaticText() the text will be unbounded. */ QStaticText::QStaticText(const QString &text, const QSizeF &size) - : d_ptr(new QStaticTextPrivate) + : data(new QStaticTextPrivate) { - d_ptr->text = text; - d_ptr->size = size; - d_ptr->init(); + data->text = text; + data->size = size; + data->init(); } /*! @@ -138,26 +138,24 @@ QStaticText::QStaticText(const QString &text, const QSizeF &size) */ QStaticText::QStaticText(const QStaticText &other) { - d_ptr = other.d_ptr; - d_ptr->ref.ref(); + data = other.data; } /*! Destroys the QStaticText. */ QStaticText::~QStaticText() -{ - if (!d_ptr->ref.deref()) - delete d_ptr; +{ + Q_ASSERT(!data || data->ref >= 1); } /*! \internal */ void QStaticText::detach() -{ - if (d_ptr->ref != 1) - qAtomicDetach(d_ptr); +{ + if (data->ref != 1) + data.detach(); } /*! @@ -177,9 +175,9 @@ void QStaticText::detach() */ void QStaticText::prepare(const QTransform &matrix, const QFont &font) { - d_ptr->matrix = matrix; - d_ptr->font = font; - d_ptr->init(); + data->matrix = matrix; + data->font = font; + data->init(); } @@ -187,8 +185,8 @@ void QStaticText::prepare(const QTransform &matrix, const QFont &font) Assigns \a other to this QStaticText. */ QStaticText &QStaticText::operator=(const QStaticText &other) -{ - qAtomicAssign(d_ptr, other.d_ptr); +{ + data = other.data; return *this; } @@ -198,10 +196,10 @@ QStaticText &QStaticText::operator=(const QStaticText &other) */ bool QStaticText::operator==(const QStaticText &other) const { - return (d_ptr == other.d_ptr - || (d_ptr->text == other.d_ptr->text - && d_ptr->font == other.d_ptr->font - && d_ptr->size == other.d_ptr->size)); + return (data == other.data + || (data->text == other.data->text + && data->font == other.data->font + && data->size == other.data->size)); } /*! @@ -223,8 +221,8 @@ bool QStaticText::operator!=(const QStaticText &other) const void QStaticText::setText(const QString &text) { detach(); - d_ptr->text = text; - d_ptr->init(); + data->text = text; + data->init(); } /*! @@ -234,7 +232,7 @@ void QStaticText::setText(const QString &text) */ QString QStaticText::text() const { - return d_ptr->text; + return data->text; } /*! @@ -255,13 +253,13 @@ QString QStaticText::text() const */ void QStaticText::setUseBackendOptimizations(bool on) { - if ((!on && !d_ptr->useBackendOptimizations) - || (on && d_ptr->useBackendOptimizations)) + if ((!on && !data->useBackendOptimizations) + || (on && data->useBackendOptimizations)) return; detach(); - d_ptr->useBackendOptimizations = on; - d_ptr->init(); + data->useBackendOptimizations = on; + data->init(); } /*! @@ -272,7 +270,7 @@ void QStaticText::setUseBackendOptimizations(bool on) */ bool QStaticText::useBackendOptimizations() const { - return d_ptr->useBackendOptimizations; + return data->useBackendOptimizations; } /*! @@ -285,8 +283,8 @@ bool QStaticText::useBackendOptimizations() const void QStaticText::setMaximumSize(const QSizeF &size) { detach(); - d_ptr->size = size; - d_ptr->init(); + data->size = size; + data->init(); } /*! @@ -296,7 +294,7 @@ void QStaticText::setMaximumSize(const QSizeF &size) */ QSizeF QStaticText::maximumSize() const { - return d_ptr->size; + return data->size; } /*! @@ -306,15 +304,24 @@ QSizeF QStaticText::maximumSize() const */ bool QStaticText::isEmpty() const { - return d_ptr->text.isEmpty(); + return data->text.isEmpty(); } QStaticTextPrivate::QStaticTextPrivate() - : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false) + : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + useBackendOptimizations(false) { ref = 1; } +QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) + : text(other.text), font(other.font), size(other.size), matrix(other.matrix), + items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + useBackendOptimizations(false) +{ + ref = 1; +} + QStaticTextPrivate::~QStaticTextPrivate() { delete[] items; @@ -324,10 +331,9 @@ QStaticTextPrivate::~QStaticTextPrivate() QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) { - return q->d_ptr; + return q->data.data(); } - extern int qt_defaultDpiX(); extern int qt_defaultDpiY(); diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index b07383e..a19fb6c 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -96,7 +96,7 @@ public: private: void detach(); - QStaticTextPrivate *d_ptr; + QExplicitlySharedDataPointer data; friend class QStaticTextPrivate; }; diff --git a/src/gui/text/qstatictext_p_p.h b/src/gui/text/qstatictext_p_p.h index bca59e0..72c8439 100644 --- a/src/gui/text/qstatictext_p_p.h +++ b/src/gui/text/qstatictext_p_p.h @@ -110,6 +110,7 @@ class Q_AUTOTEST_EXPORT QStaticTextPrivate { public: QStaticTextPrivate(); + QStaticTextPrivate(const QStaticTextPrivate &other); ~QStaticTextPrivate(); void init(); diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 08e7079..9e6f3d6 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -46,6 +46,7 @@ #include #include +#include // #define DEBUG_SAVE_IMAGE @@ -112,7 +113,7 @@ void tst_QStaticText::drawToPoint() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setUseBackendOptimizations(useBackendOptimizations); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -143,7 +144,7 @@ void tst_QStaticText::drawToRect() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500)); text.setUseBackendOptimizations(useBackendOptimizations); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -170,7 +171,7 @@ void tst_QStaticText::prepareToCorrectData() p.setTransform(transform); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.prepare(transform, p.font()); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -195,7 +196,7 @@ void tst_QStaticText::prepareToWrongData() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.prepare(transform, p.font()); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -226,9 +227,9 @@ void tst_QStaticText::setFont() QStaticText text; text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(0, 0, text); + qt_draw_static_text(&p, QPointF(0, 0), text); p.setFont(font); - p.drawStaticText(11, 120, text); + qt_draw_static_text(&p, QPointF(11, 120), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -249,7 +250,7 @@ void tst_QStaticText::setMaximumSize() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setMaximumSize(QSizeF(10, 500)); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -273,7 +274,7 @@ void tst_QStaticText::translatedPainter() p.translate(100, 200); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -296,7 +297,7 @@ void tst_QStaticText::rotatedPainter() QPainter p(&imageDrawStaticText); p.rotate(30.0); - p.drawStaticText(0, 0, text); + qt_draw_static_text(&p, QPointF(0, 0), text); } #if defined(DEBUG_SAVE_IMAGE) @@ -325,7 +326,7 @@ void tst_QStaticText::scaledPainter() p.scale(2.0, 0.2); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -352,7 +353,7 @@ void tst_QStaticText::projectedPainter() p.setTransform(transform); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -381,7 +382,7 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() p.translate(100, 200); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(11, 12, text); + qt_draw_static_text(&p, QPointF(11, 12), text); } #if defined(DEBUG_SAVE_IMAGE) @@ -415,10 +416,10 @@ void tst_QStaticText::transformationChanged() p.scale(0.5, 0.7); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - p.drawStaticText(0, 0, text); + qt_draw_static_text(&p, QPointF(0, 0), text); p.scale(7.0, 5.0); - p.drawStaticText(0, 0, text); + qt_draw_static_text(&p, QPointF(0, 0), text); } #if defined(DEBUG_SAVE_IMAGE) -- cgit v0.12 From f85b35d5b8a005e2d7128c203f7402750b94e1da Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 17:07:21 +0100 Subject: Add tests for using QStaticText with a QGLWidget Some tests with and without VBO caching. --- tests/auto/qstatictext/qstatictext.pro | 2 +- tests/auto/qstatictext/tst_qstatictext.cpp | 211 +++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) diff --git a/tests/auto/qstatictext/qstatictext.pro b/tests/auto/qstatictext/qstatictext.pro index 0f1ca68..a759a90 100644 --- a/tests/auto/qstatictext/qstatictext.pro +++ b/tests/auto/qstatictext/qstatictext.pro @@ -1,4 +1,4 @@ load(qttest_p4) -QT = core gui +QT = core gui opengl SOURCES += tst_qstatictext.cpp diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 9e6f3d6..9e4b540 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -44,6 +44,8 @@ #include #include +#include + #include #include #include @@ -73,6 +75,11 @@ private slots: void projectedPainter(); void rotatedScaledAndTranslatedPainter(); void transformationChanged(); + + void drawToGLWidget(); + void drawToGLWidgetRepeated(); + void drawToGLWidgetWithCaching(); + void drawToGLWidgetWithCachingRepeated(); }; void tst_QStaticText::init() @@ -430,5 +437,209 @@ void tst_QStaticText::transformationChanged() QCOMPARE(imageDrawStaticText, imageDrawText); } +class MyGLWidget: public QGLWidget +{ +public: + enum PaintEventType { + NormalDrawText, + NormalDrawStaticText, + DrawStaticTextWithCaching + }; + + MyGLWidget(PaintEventType paintEventType, QWidget *parent = 0) + : QGLWidget(parent), m_paintEventType(paintEventType) + { + m_staticText.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + if (m_paintEventType == DrawStaticTextWithCaching) + m_staticText.setUseBackendOptimizations(true); + shown = false; + } + + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.fillRect(rect(), Qt::white); + switch (m_paintEventType) { + case NormalDrawStaticText: + case DrawStaticTextWithCaching: + qt_draw_static_text(&painter, QPointF(11, 12), m_staticText); + break; + case NormalDrawText: + painter.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + break; + }; + shown = true; + } + + bool shown; + +private: + QStaticText m_staticText; + PaintEventType m_paintEventType; +}; + +void tst_QStaticText::drawToGLWidget() +{ + QImage imageDrawText; + { + MyGLWidget glWidget(MyGLWidget::NormalDrawText); + glWidget.show(); + while (!glWidget.shown) + QApplication::processEvents(); + imageDrawText = glWidget.grabFrameBuffer(); + } + + QImage imageDrawStaticText; + { + MyGLWidget glWidget(MyGLWidget::NormalDrawStaticText); + glWidget.show(); + while (!glWidget.shown) + QApplication::processEvents(); + imageDrawStaticText = glWidget.grabFrameBuffer(); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToGLWidget_imageDrawText.png"); + imageDrawStaticText.save("drawToGLWidget_imageDrawStaticText.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::drawToGLWidgetWithCaching() +{ + QImage imageDrawText; + { + MyGLWidget glWidget(MyGLWidget::NormalDrawText); + glWidget.show(); + while (!glWidget.shown) + QApplication::processEvents(); + imageDrawText = glWidget.grabFrameBuffer(); + } + + QImage imageDrawStaticText; + { + MyGLWidget glWidget(MyGLWidget::DrawStaticTextWithCaching); + glWidget.show(); + while (!glWidget.shown) + QApplication::processEvents(); + imageDrawStaticText = glWidget.grabFrameBuffer(); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToGLWidgetWithCaching_imageDrawText.png"); + imageDrawStaticText.save("drawToGLWidgetWithCaching_imageDrawStaticText.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::drawToGLWidgetWithCachingRepeated() +{ + QImage imageDrawText; + MyGLWidget glWidgetNormal(MyGLWidget::NormalDrawText); + + { + glWidgetNormal.show(); + while (!glWidgetNormal.shown) + QApplication::processEvents(); + imageDrawText = glWidgetNormal.grabFrameBuffer(); + } + + QImage imageDrawStaticText; + MyGLWidget glWidgetAbnormal(MyGLWidget::DrawStaticTextWithCaching); + { + + glWidgetAbnormal.show(); + while (!glWidgetAbnormal.shown) + QApplication::processEvents(); + imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText1.png"); + imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText1.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); + + { + glWidgetNormal.shown = false; + glWidgetNormal.update(); + while (!glWidgetNormal.shown) + QApplication::processEvents(); + imageDrawText = glWidgetNormal.grabFrameBuffer(); + } + + { + glWidgetAbnormal.shown = false; + glWidgetAbnormal.update(); + while (!glWidgetAbnormal.shown) + QApplication::processEvents(); + imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText2.png"); + imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText2.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::drawToGLWidgetRepeated() +{ + QImage imageDrawText; + MyGLWidget glWidgetNormal(MyGLWidget::NormalDrawText); + + { + glWidgetNormal.show(); + while (!glWidgetNormal.shown) + QApplication::processEvents(); + imageDrawText = glWidgetNormal.grabFrameBuffer(); + } + + QImage imageDrawStaticText; + MyGLWidget glWidgetAbnormal(MyGLWidget::NormalDrawStaticText); + { + + glWidgetAbnormal.show(); + while (!glWidgetAbnormal.shown) + QApplication::processEvents(); + imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText1.png"); + imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText1.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); + + { + glWidgetNormal.shown = false; + glWidgetNormal.update(); + while (!glWidgetNormal.shown) + QApplication::processEvents(); + imageDrawText = glWidgetNormal.grabFrameBuffer(); + } + + { + glWidgetAbnormal.shown = false; + glWidgetAbnormal.update(); + while (!glWidgetAbnormal.shown) + QApplication::processEvents(); + imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText2.png"); + imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText2.png"); +#endif + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + + QTEST_MAIN(tst_QStaticText) #include "tst_qstatictext.moc" -- cgit v0.12 From 50a668e62739c715dcd4f001b659ff25f71cc9c4 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Feb 2010 17:24:53 +0100 Subject: Remove redundant friend declaration for QPainterPrivate in QPainter This is already included in the Q_DECLARE_PRIVATE macro. --- src/gui/painting/qpainter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 088a973..ffddcba 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -522,7 +522,6 @@ private: friend class QRasterPaintEngine; friend class QAlphaPaintEngine; friend class QPreviewPaintEngine; - friend class QPainterPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QPainter::RenderHints) -- cgit v0.12 From af34b8b726600e1f63484d86495a7514bd79c163 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 8 Feb 2010 13:36:30 +1000 Subject: Make nativeSizeChanged() signal non-const. --- src/multimedia/base/qgraphicsvideoitem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.h b/src/multimedia/base/qgraphicsvideoitem.h index f8cffdc..06f471f 100644 --- a/src/multimedia/base/qgraphicsvideoitem.h +++ b/src/multimedia/base/qgraphicsvideoitem.h @@ -85,7 +85,7 @@ public: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); Q_SIGNALS: - void nativeSizeChanged(const QSizeF &size) const; + void nativeSizeChanged(const QSizeF &size); protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value); -- cgit v0.12 From 1c58f3fa6b0bc2cfab9b32bb315bbef4270f6649 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 8 Feb 2010 13:37:55 +1000 Subject: Remove documentation for QGraphicsVideoItem::FillMode. No longer exists. --- src/multimedia/base/qgraphicsvideoitem.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp index 35baabe..3cd0449 100644 --- a/src/multimedia/base/qgraphicsvideoitem.cpp +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -203,18 +203,6 @@ void QGraphicsVideoItemPrivate::_q_mediaObjectDestroyed() */ /*! - \enum QGraphicsVideoItem::FillMode - - Enumerates the methods of scaling a video to fit a graphics item. - - \value Stretch The video is stretched to fit the item's size. - \value PreserveAspectFit The video is uniformly scaled to fix the item's - size without cropping. - \value PreserveAspectCrop The video is uniformly scaled to fill the item's - size, cropping if necessary. -*/ - -/*! Constructs a graphics item that displays video. The \a parent is passed to QGraphicsItem. -- cgit v0.12 From 903e52cdad8be0c23aaba303389cc4bff675bbb2 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 8 Feb 2010 13:40:00 +1000 Subject: Correct QtMedia::SampleRate property mapping. Was mapped to frequency instead of sampleRate. --- src/multimedia/qml/qmetadatacontrolmetaobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp index c4b2b42..882d8a6 100644 --- a/src/multimedia/qml/qmetadatacontrolmetaobject.cpp +++ b/src/multimedia/qml/qmetadatacontrolmetaobject.cpp @@ -140,7 +140,7 @@ namespace { QtMedia::AverageLevel, "averageLevel" }, { QtMedia::ChannelCount, "channelCount" }, { QtMedia::PeakValue, "peakValue" }, - { QtMedia::SampleRate, "frequency" }, + { QtMedia::SampleRate, "sampleRate" }, // Music { QtMedia::AlbumTitle, "albumTitle" }, -- cgit v0.12 From 923af5cd17dcfa2038998addec44f70154b385d2 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 8 Feb 2010 13:41:54 +1000 Subject: Update QML media element documentation. --- src/multimedia/qml/qmlaudio.cpp | 72 ++-- src/multimedia/qml/qmlgraphicsvideo.cpp | 610 ++++++++++++++++++++++++++++++-- 2 files changed, 628 insertions(+), 54 deletions(-) diff --git a/src/multimedia/qml/qmlaudio.cpp b/src/multimedia/qml/qmlaudio.cpp index f56b6c3..fc340d0 100644 --- a/src/multimedia/qml/qmlaudio.cpp +++ b/src/multimedia/qml/qmlaudio.cpp @@ -49,13 +49,19 @@ QML_DEFINE_TYPE(Qt,4,6,Audio,QmlAudio); /*! \qmlclass Audio QmlAudio - \brief The Audio element allows you to add audio to a scene. + \brief The Audio element allows you to add audio playback to a scene. + + \qml + Audio { source: "audio/song.mp3" } + \endqml + + \sa Video */ /*! \internal \class QmlAudio - \brief The QmlAudio class provides a audio item that you can add to a QmlView. + \brief The QmlAudio class provides an audio item that you can add to a QmlView. */ void QmlAudio::_q_error(int errorCode, const QString &errorString) @@ -82,7 +88,9 @@ QmlAudio::~QmlAudio() /*! \qmlmethod Audio::play() - Starts playback of the audio. + Starts playback of the media. + + Sets the \l playing property to true, and the \l paused property to false. */ void QmlAudio::play() @@ -98,7 +106,9 @@ void QmlAudio::play() /*! \qmlmethod Audio::pause() - Pauses playback of the audio. + Pauses playback of the media. + + Sets the \l playing and \l paused properties to true. */ void QmlAudio::pause() @@ -114,7 +124,9 @@ void QmlAudio::pause() /*! \qmlmethod Audio::stop() - Stops playback of the audio. + Stops playback of the media. + + Sets the \l playing and \l paused properties to false. */ void QmlAudio::stop() @@ -130,19 +142,23 @@ void QmlAudio::stop() /*! \qmlproperty url Audio::source - This property holds the source URL of the audio. + This property holds the source URL of the media. */ /*! \qmlproperty bool Audio::playing - This property holds whether the audio is playing. + This property holds whether the media is playing. + + Defaults to false, and can be set to true to start playback. */ /*! \qmlproperty bool Audio::paused - This property holds whether the audio is paused. + This property holds whether the media is paused. + + Defaults to false, and can be set to true to pause playback. */ /*! @@ -172,18 +188,18 @@ void QmlAudio::stop() /*! \qmlproperty enum Audio::status - This property holds the status of audio loading. It can be one of: + This property holds the status of media loading. It can be one of: \list - \o NoMedia - no audio has been set. - \o Loading - the audio is currently being loaded. - \o Loaded - the audio has been loaded. - \o Buffering - the audio is buffering data. - \o Stalled - playback has been interrupted while the audio is buffering data. - \o Buffered - the audio has buffered data. - \o EndOfMedia - the audio has played to the end. - \o InvalidMedia - the audio cannot be played. - \o UnknownStatus - the status of the audio is unknown. + \o NoMedia - no media has been set. + \o Loading - the media is currently being loaded. + \o Loaded - the media has been loaded. + \o Buffering - the media is buffering data. + \o Stalled - playback has been interrupted while the media is buffering data. + \o Buffered - the media has buffered data. + \o EndOfMedia - the media has played to the end. + \o InvalidMedia - the media cannot be played. + \o UnknownStatus - the status of the media is unknown. \endlist */ @@ -195,44 +211,46 @@ QmlAudio::Status QmlAudio::status() const /*! \qmlsignal Audio::onLoaded() - This handler is called when the video source has been loaded. + This handler is called when the media source has been loaded. */ /*! \qmlsignal Audio::onBuffering() - This handler is called when the video stream starts buffering. + This handler is called when the media starts buffering. */ /*! \qmlsignal Audio::onStalled() - This handler is called when playback has stalled while the video stream buffers. + This handler is called when playback has stalled while the media buffers. */ /*! \qmlsignal Audio::onBuffered() - This handler is called when the video stream has finished buffering. + This handler is called when the media has finished buffering. */ /*! - \qmlsignal Audio::onEndOfMedia + \qmlsignal Audio::onEndOfMedia() - This handler is called when playback stops because end of the video has been reached. + This handler is called when playback stops because end of the media has been reached. */ /*! \qmlproperty int Audio::duration - This property holds the duration of the audio in milliseconds. + This property holds the duration of the media in milliseconds. - If the audio doesn't have a fixed duration (a live stream for example) this will be 0. + If the media doesn't have a fixed duration (a live stream for example) this will be 0. */ /*! \qmlproperty int Audio::position This property holds the current playback position in milliseconds. + + If the \l seekable property is true, this property can be set to seek to a new position. */ /*! @@ -258,6 +276,8 @@ QmlAudio::Status QmlAudio::status() const \qmlproperty bool Audio::seekable This property holds whether position of the audio can be changed. + + If true; setting a \l position value will cause playback to seek to the new position. */ /*! diff --git a/src/multimedia/qml/qmlgraphicsvideo.cpp b/src/multimedia/qml/qmlgraphicsvideo.cpp index f6a5eff..236387e 100644 --- a/src/multimedia/qml/qmlgraphicsvideo.cpp +++ b/src/multimedia/qml/qmlgraphicsvideo.cpp @@ -73,6 +73,18 @@ void QmlGraphicsVideo::_q_error(int errorCode, const QString &errorString) \qmlclass Video QmlGraphicsVideo \brief The Video element allows you to add videos to a scene. \inherits Item + + \qml + Video { source: "video/movie.mpg" } + \endqml + + The video item supports untransformed, stretched, and uniformly scaled video presentation. + For a description of stretched uniformly scaled presentation, see the \l fillMode property + description. + + The video item is only visible when the \l hasVideo property is true and the video is playing. + + \sa Audio */ /*! @@ -112,19 +124,23 @@ QmlGraphicsVideo::~QmlGraphicsVideo() /*! \qmlproperty url Video::source - This property holds the source URL of the video. + This property holds the source URL of the media. */ /*! \qmlproperty bool Video::playing - This property holds whether the video is playing. + This property holds whether the media is playing. + + Defaults to false, and can be set to true to start playback. */ /*! \qmlproperty bool Video::paused - This property holds whether the video is paused. + This property holds whether the media is paused. + + Defaults to false, and can be set to true to pause playback. */ /*! @@ -154,18 +170,18 @@ QmlGraphicsVideo::~QmlGraphicsVideo() /*! \qmlproperty enum Video::status - This property holds the status of video loading. It can be one of: + This property holds the status of media loading. It can be one of: \list - \o NoMedia - no video has been set. - \o Loading - the video is currently being loaded. - \o Loaded - the video has been loaded. - \o Buffering - the video is buffering data. - \o Stalled - playback has been interrupted while the video is buffering data. - \o Buffered - the video has buffered data. - \o EndOfMedia - the video has played to the end. - \o InvalidMedia - the video cannot be played. - \o UnknownStatus - the status of the video is unknown. + \o NoMedia - no media has been set. + \o Loading - the media is currently being loaded. + \o Loaded - the media has been loaded. + \o Buffering - the media is buffering data. + \o Stalled - playback has been interrupted while the media is buffering data. + \o Buffered - the media has buffered data. + \o EndOfMedia - the media has played to the end. + \o InvalidMedia - the media cannot be played. + \o UnknownStatus - the status of the media is cannot be determined. \endlist */ @@ -177,39 +193,39 @@ QmlGraphicsVideo::Status QmlGraphicsVideo::status() const /*! \qmlsignal Video::onLoaded() - This handler is called when the video source has been loaded. + This handler is called when the media source has been loaded. */ /*! \qmlsignal Video::onBuffering() - This handler is called when the video stream starts buffering. + This handler is called when the media starts buffering. */ /*! \qmlsignal Video::onStalled() - This handler is called when playback has stalled while the video stream buffers. + This handler is called when playback has stalled while the media buffers. */ /*! \qmlsignal Video::onBuffered() - This handler is called when the video stream has finished buffering. + This handler is called when the media has finished buffering. */ /*! - \qmlsignal Video::onEndOfMedia + \qmlsignal Video::onEndOfMedia() - This handler is called when playback stops because end of the video has been reached. + This handler is called when playback stops because end of the media has been reached. */ /*! \qmlproperty int Video::duration - This property holds the duration of the video in milliseconds. + This property holds the duration of the media in milliseconds. - If the video doesn't have a fixed duration (a live stream for example) this will be 0. + If the media doesn't have a fixed duration (a live stream for example) this will be 0. */ /*! @@ -231,9 +247,9 @@ QmlGraphicsVideo::Status QmlGraphicsVideo::status() const */ /*! - \qmlproperty bool Audio::hasAudio + \qmlproperty bool Video::hasAudio - This property holds whether the source contains audio. + This property holds whether the media contains audio. */ bool QmlGraphicsVideo::hasAudio() const @@ -244,7 +260,7 @@ bool QmlGraphicsVideo::hasAudio() const /*! \qmlproperty bool Video::hasVideo - This property holds whether the source contains video. + This property holds whether the media contains video. */ bool QmlGraphicsVideo::hasVideo() const @@ -307,7 +323,7 @@ QmlGraphicsVideo::Error QmlGraphicsVideo::error() const */ /*! - \qmlproperty enum Video::FillMode + \qmlproperty enum Video::fillMode Set this property to define how the video is scaled to fit the target area. @@ -316,6 +332,8 @@ QmlGraphicsVideo::Error QmlGraphicsVideo::error() const \o PreserveAspectFit - the video is scaled uniformly to fit without cropping \o PreserveAspectCrop - the video is scaled uniformly to fill, cropping if necessary \endlist + + The default fill mode is PreserveAspectFit. */ QmlGraphicsVideo::FillMode QmlGraphicsVideo::fillMode() const @@ -331,7 +349,9 @@ void QmlGraphicsVideo::setFillMode(FillMode mode) /*! \qmlmethod Video::play() - Starts playback of the video. + Starts playback of the media. + + Sets the \l playing property to true, and the \l paused property to false. */ void QmlGraphicsVideo::play() @@ -347,7 +367,9 @@ void QmlGraphicsVideo::play() /*! \qmlmethod Video::pause() - Pauses playback of the video. + Pauses playback of the media. + + Sets the \l playing and \l paused properties to true. */ void QmlGraphicsVideo::pause() @@ -363,7 +385,9 @@ void QmlGraphicsVideo::pause() /*! \qmlmethod Video::stop() - Stops playback of the video. + Stops playback of the media. + + Sets the \l playing and \l paused properties to false. */ void QmlGraphicsVideo::stop() @@ -389,4 +413,534 @@ void QmlGraphicsVideo::geometryChanged(const QRectF &newGeometry, const QRectF & QT_END_NAMESPACE +// *************************************** +// Documentation for meta-data properties. +// *************************************** + +/*! + \qmlproperty variant Video::title + + This property holds the tile of the media. + + \sa {QtMedia::Title} +*/ + +/*! + \qmlproperty variant Video::subTitle + + This property holds the sub-title of the media. + + \sa {QtMedia::SubTitle} +*/ + +/*! + \qmlproperty variant Video::author + + This property holds the author of the media. + + \sa {QtMedia::Author} +*/ + +/*! + \qmlproperty variant Video::comment + + This property holds a user comment about the media. + + \sa {QtMedia::Comment} +*/ + +/*! + \qmlproperty variant Video::description + + This property holds a description of the media. + + \sa {QtMedia::Description} +*/ + +/*! + \qmlproperty variant Video::category + + This property holds the category of the media + + \sa {QtMedia::Category} +*/ + +/*! + \qmlproperty variant Video::genre + + This property holds the genre of the media. + + \sa {QtMedia::Genre} +*/ + +/*! + \qmlproperty variant Video::year + + This property holds the year of release of the media. + + \sa {QtMedia::Year} +*/ + +/*! + \qmlproperty variant Video::date + + This property holds the date of the media. + + \sa {QtMedia::Date} +*/ + +/*! + \qmlproperty variant Video::userRating + + This property holds a user rating of the media in the range of 0 to 100. + + \sa {QtMedia::UserRating} +*/ + +/*! + \qmlproperty variant Video::keywords + + This property holds a list of keywords describing the media. + + \sa {QtMedia::Keywords} +*/ + +/*! + \qmlproperty variant Video::language + + This property holds the language of the media, as an ISO 639-2 code. + + \sa {QtMedia::Language} +*/ + +/*! + \qmlproperty variant Video::publisher + + This property holds the publisher of the media. + + \sa {QtMedia::Publisher} +*/ + +/*! + \qmlproperty variant Video::copyright + + This property holds the media's copyright notice. + + \sa {QtMedia::Copyright} +*/ + +/*! + \qmlproperty variant Video::parentalRating + + This property holds the parental rating of the media. + + \sa {QtMedia::ParentalRating} +*/ + +/*! + \qmlproperty variant Video::ratingOrganisation + + This property holds the name of the rating organisation responsible for the + parental rating of the media. + + \sa {QtMedia::RatingOrganisation} +*/ + +/*! + \qmlproperty variant Video::size + + This property property holds the size of the media in bytes. + + \sa {QtMedia::Size} +*/ + +/*! + \qmlproperty variant Video::mediaType + + This property holds the type of the media. + + \sa {QtMedia::MediaType} +*/ + +/*! + \qmlproperty variant Video::audioBitRate + + This property holds the bit rate of the media's audio stream ni bits per + second. + + \sa {QtMedia::AudioBitRate} +*/ + +/*! + \qmlproperty variant Video::audioCodec + + This property holds the encoding of the media audio stream. + + \sa {QtMedia::AudioCodec} +*/ + +/*! + \qmlproperty variant Video::averageLevel + + This property holds the average volume level of the media. + + \sa {QtMedia::AverageLevel} +*/ + +/*! + \qmlproperty variant Video::channelCount + + This property holds the number of channels in the media's audio stream. + + \sa {QtMedia::ChannelCount} +*/ + +/*! + \qmlproperty variant Video::peakValue + + This property holds the peak volume of media's audio stream. + + \sa {QtMedia::PeakValue} +*/ + +/*! + \qmlproperty variant Video::sampleRate + + This property holds the sample rate of the media's audio stream in hertz. + + \sa {QtMedia::SampleRate} +*/ + +/*! + \qmlproperty variant Video::albumTitle + + This property holds the title of the album the media belongs to. + + \sa {QtMedia::AlbumTitle} +*/ + +/*! + \qmlproperty variant Video::albumArtist + + This property holds the name of the principal artist of the album the media + belongs to. + + \sa {QtMedia::AlbumArtist} +*/ + +/*! + \qmlproperty variant Video::contributingArtist + + This property holds the names of artists contributing to the media. + + \sa {QtMedia::ContributingArtist} +*/ + +/*! + \qmlproperty variant Video::composer + + This property holds the composer of the media. + + \sa {QtMedia::Composer} +*/ + +/*! + \qmlproperty variant Video::conductor + + This property holds the conductor of the media. + + \sa {QtMedia::Conductor} +*/ + +/*! + \qmlproperty variant Video::lyrics + + This property holds the lyrics to the media. + + \sa {QtMedia::Lyrics} +*/ + +/*! + \qmlproperty variant Video::mood + + This property holds the mood of the media. + + \sa {QtMedia::Mood} +*/ + +/*! + \qmlproperty variant Video::trackNumber + + This property holds the track number of the media. + + \sa {QtMedia::TrackNumber} +*/ + +/*! + \qmlproperty variant Video::trackCount + + This property holds the number of track on the album containing the media. + + \sa {QtMedia::TrackNumber} +*/ + +/*! + \qmlproperty variant Video::coverArtUrlSmall + + This property holds the URL of a small cover art image. + + \sa {QtMedia::CoverArtUrlSmall} +*/ + +/*! + \qmlproperty variant Video::coverArtUrlLarge + + This property holds the URL of a large cover art image. + + \sa {QtMedia::CoverArtUrlLarge} +*/ + +/*! + \qmlproperty variant Video::resolution + + This property holds the dimension of an image or video. + + \sa {QtMedia::Resolution} +*/ + +/*! + \qmlproperty variant Video::pixelAspectRatio + + This property holds the pixel aspect ratio of an image or video. + + \sa {QtMedia::PixelAspectRatio} +*/ + +/*! + \qmlproperty variant Video::videoFrameRate + + This property holds the frame rate of the media's video stream. + + \sa {QtMedia::VideoFrameRate} +*/ + +/*! + \qmlproperty variant Video::videoBitRate + + This property holds the bit rate of the media's video stream in bits per + second. + + \sa {QtMedia::VideoBitRate} +*/ + +/*! + \qmlproperty variant Video::videoCodec + + This property holds the encoding of the media's video stream. + + \sa {QtMedia::VideoCodec} +*/ + +/*! + \qmlproperty variant Video::posterUrl + + This property holds the URL of a poster image. + + \sa {QtMedia::PosterUrl} +*/ + +/*! + \qmlproperty variant Video::chapterNumber + + This property holds the chapter number of the media. + + \sa {QtMedia::ChapterNumber} +*/ + +/*! + \qmlproperty variant Video::director + + This property holds the director of the media. + + \sa {QtMedia::Director} +*/ + +/*! + \qmlproperty variant Video::leadPerformer + + This property holds the lead performer in the media. + + \sa {QtMedia::LeadPerformer} +*/ + +/*! + \qmlproperty variant Video::writer + + This property holds the writer of the media. + + \sa {QtMedia::Writer} +*/ + +// The remaining properties are related to photos, and are technically +// available but will certainly never have values. +#ifndef Q_QDOC + +/*! + \qmlproperty variant Video::cameraManufacturer + + \sa {QtMedia::CameraManufacturer} +*/ + +/*! + \qmlproperty variant Video::cameraModel + + \sa {QtMedia::CameraModel} +*/ + +/*! + \qmlproperty variant Video::event + + \sa {QtMedia::Event} +*/ + +/*! + \qmlproperty variant Video::subject + + \sa {QtMedia::Subject} +*/ + +/*! + \qmlproperty variant Video::orientation + + \sa {QtMedia::Orientation} +*/ + +/*! + \qmlproperty variant Video::exposureTime + + \sa {QtMedia::ExposureTime} +*/ + +/*! + \qmlproperty variant Video::fNumber + + \sa {QtMedia::FNumber} +*/ + +/*! + \qmlproperty variant Video::exposureProgram + + \sa {QtMedia::ExposureProgram} +*/ + +/*! + \qmlproperty variant Video::isoSpeedRatings + + \sa {QtMedia::ISOSpeedRatings} +*/ + +/*! + \qmlproperty variant Video::exposureBiasValue + + \sa {QtMedia::ExposureBiasValue} +*/ + +/*! + \qmlproperty variant Video::dateTimeDigitized + + \sa {QtMedia::DateTimeDigitized} +*/ + +/*! + \qmlproperty variant Video::subjectDistance + + \sa {QtMedia::SubjectDistance} +*/ + +/*! + \qmlproperty variant Video::meteringMode + + \sa {QtMedia::MeteringMode} +*/ + +/*! + \qmlproperty variant Video::lightSource + + \sa {QtMedia::LightSource} +*/ + +/*! + \qmlproperty variant Video::flash + + \sa {QtMedia::Flash} +*/ + +/*! + \qmlproperty variant Video::focalLength + + \sa {QtMedia::FocalLength} +*/ + +/*! + \qmlproperty variant Video::exposureMode + + \sa {QtMedia::ExposureMode} +*/ + +/*! + \qmlproperty variant Video::whiteBalance + + \sa {QtMedia::WhiteBalance} +*/ + +/*! + \qmlproperty variant Video::DigitalZoomRatio + + \sa {QtMedia::DigitalZoomRatio} +*/ + +/*! + \qmlproperty variant Video::focalLengthIn35mmFilm + + \sa {QtMedia::FocalLengthIn35mmFile} +*/ + +/*! + \qmlproperty variant Video::sceneCaptureType + + \sa {QtMedia::SceneCaptureType} +*/ + +/*! + \qmlproperty variant Video::gainControl + + \sa {QtMedia::GainControl} +*/ + +/*! + \qmlproperty variant Video::contrast + + \sa {QtMedia::contrast} +*/ + +/*! + \qmlproperty variant Video::saturation + + \sa {QtMedia::Saturation} +*/ + +/*! + \qmlproperty variant Video::sharpness + + \sa {QtMedia::Sharpness} +*/ + +/*! + \qmlproperty variant Video::deviceSettingDescription + + \sa {QtMedia::DeviceSettingDescription} +*/ + +#endif + #include "moc_qmlgraphicsvideo_p.cpp" -- cgit v0.12 From da727b5aadf64128de0eb39fc1ce26e587211272 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 8 Feb 2010 17:50:42 +1000 Subject: Fix stall in graph when removing video and audio outputs. Must remove the decoder as well as the output otherwise the graph wont be able to resume because a disconnected decoder cant. And the graph must be stopped to connect a new output. --- .../mediaplayer/directshowplayerservice.cpp | 107 +++++++++++++++++---- .../mediaplayer/directshowplayerservice.h | 1 + 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index fdbee81..3c0a43a 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -319,6 +319,13 @@ void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker) void DirectShowPlayerService::doRender(QMutexLocker *locker) { + m_pendingTasks |= m_executedTasks & (Play | Pause); + + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); + } + if (m_pendingTasks & SetAudioOutput) { m_graph->AddFilter(m_audioOutput, L"AudioOutput"); @@ -358,7 +365,7 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker) IPin *peer = 0; if (pin->ConnectedTo(&peer) == S_OK) { PIN_INFO peerInfo; - if (peer->QueryPinInfo(&peerInfo) == S_OK) + if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) filters.append(peerInfo.pFilter); peer->Release(); } else { @@ -374,13 +381,15 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker) } } } + + pins->Release(); + if (outputs == 0) rendered = true; } filter->Release(); } - if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) { graph->RemoveFilter(m_audioOutput); @@ -604,9 +613,6 @@ void DirectShowPlayerService::doPlay(QMutexLocker *locker) control->Release(); - if (SUCCEEDED(hr)) - m_executedTasks |= Play; - if (SUCCEEDED(hr)) { m_executedTasks |= Play; @@ -851,14 +857,14 @@ void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter) m_audioOutput->AddRef(); m_pendingTasks |= SetAudioOutput; - } else { - m_pendingTasks &= ~ SetAudioOutput; - } - if (m_executedTasks & SetSource) { - m_pendingTasks |= Render; + if (m_executedTasks & SetSource) { + m_pendingTasks |= Render; - ::SetEvent(m_taskHandle); + ::SetEvent(m_taskHandle); + } + } else { + m_pendingTasks &= ~ SetAudioOutput; } } else { if (m_audioOutput) @@ -882,7 +888,20 @@ void DirectShowPlayerService::doReleaseAudioOutput(QMutexLocker *locker) control->Release(); } - m_graph->RemoveFilter(m_audioOutput); + IBaseFilter *decoder = getConnected(m_audioOutput, PINDIR_INPUT); + if (!decoder) { + decoder = m_audioOutput; + decoder->AddRef(); + } + + if (IFilterChain *chain = com_cast(m_graph)) { + chain->RemoveChain(decoder, m_audioOutput); + chain->Release(); + } else { + m_graph->RemoveFilter(m_audioOutput); + } + + decoder->Release(); m_executedTasks &= ~SetAudioOutput; @@ -911,14 +930,12 @@ void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter) m_videoOutput->AddRef(); m_pendingTasks |= SetVideoOutput; - } else { - m_pendingTasks &= ~ SetVideoOutput; - } - if (m_executedTasks & SetSource) { - m_pendingTasks |= Render; + if (m_executedTasks & SetSource) { + m_pendingTasks |= Render; - ::SetEvent(m_taskHandle); + ::SetEvent(m_taskHandle); + } } } else { if (m_videoOutput) @@ -940,7 +957,27 @@ void DirectShowPlayerService::doReleaseVideoOutput(QMutexLocker *locker) control->Release(); } - m_graph->RemoveFilter(m_videoOutput); + IBaseFilter *intermediate = 0; + if (!SUCCEEDED(m_graph->FindFilterByName(L"Color Space Converter", &intermediate))) { + intermediate = m_videoOutput; + intermediate->AddRef(); + } + + IBaseFilter *decoder = getConnected(intermediate, PINDIR_INPUT); + if (!decoder) { + decoder = intermediate; + decoder->AddRef(); + } + + if (IFilterChain *chain = com_cast(m_graph)) { + chain->RemoveChain(decoder, m_videoOutput); + chain->Release(); + } else { + m_graph->RemoveFilter(m_videoOutput); + } + + intermediate->Release(); + decoder->Release(); m_executedTasks &= ~SetVideoOutput; @@ -1109,6 +1146,38 @@ bool DirectShowPlayerService::isConnected(IBaseFilter *filter, PIN_DIRECTION dir return connected; } +IBaseFilter *DirectShowPlayerService::getConnected( + IBaseFilter *filter, PIN_DIRECTION direction) const +{ + IBaseFilter *connected = 0; + + IEnumPins *pins = 0; + + if (SUCCEEDED(filter->EnumPins(&pins))) { + for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) { + PIN_DIRECTION dir; + if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) { + IPin *peer = 0; + if (SUCCEEDED(pin->ConnectedTo(&peer))) { + PIN_INFO info; + + if (SUCCEEDED(peer->QueryPinInfo(&info))) { + if (connected) { + qWarning("DirectShowPlayerService::getConnected: " + "Multiple connected filters"); + connected->Release(); + } + connected = info.pFilter; + } + peer->Release(); + } + } + } + pins->Release(); + } + return connected; +} + void DirectShowPlayerService::run() { QMutexLocker locker(&m_mutex); diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h index 576520e..906d23b 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h @@ -114,6 +114,7 @@ private: int findStreamType(IPin *pin) const; bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const; + IBaseFilter *getConnected(IBaseFilter *filter, PIN_DIRECTION direction) const; void run(); -- cgit v0.12 From 4603dc768d8c98770311a9136f956f3cefa90362 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 8 Feb 2010 17:53:56 +1000 Subject: Don't clear the video output when the video widget is hidden. Changing the video output is a heavy task and is likely to interrupt playback. Not really worth the cost for knowing the video isn't being decoded while it cant be seen. This also applies to the QGraphicsVideoItem. --- src/multimedia/base/qgraphicsvideoitem.cpp | 16 +--------------- src/multimedia/base/qvideowidget.cpp | 3 --- tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp | 2 +- tests/auto/qvideowidget/tst_qvideowidget.cpp | 6 +++--- 4 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp index 3cd0449..8aba269 100644 --- a/src/multimedia/base/qgraphicsvideoitem.cpp +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -408,21 +408,7 @@ void QGraphicsVideoItem::paint( */ QVariant QGraphicsVideoItem::itemChange(GraphicsItemChange change, const QVariant &value) { - Q_D(QGraphicsVideoItem); - - if (change == ItemVisibleChange && d->outputControl != 0 && d->rendererControl != 0) { - if (value.toBool()) { - d->outputControl->setOutput(QVideoOutputControl::RendererOutput); - - return d->outputControl->output() == QVideoOutputControl::RendererOutput; - } else { - d->outputControl->setOutput(QVideoOutputControl::NoOutput); - - return value; - } - } else { - return QGraphicsItem::itemChange(change, value); - } + return QGraphicsItem::itemChange(change, value); } QT_END_NAMESPACE diff --git a/src/multimedia/base/qvideowidget.cpp b/src/multimedia/base/qvideowidget.cpp index 31cfd8d..5df245e 100644 --- a/src/multimedia/base/qvideowidget.cpp +++ b/src/multimedia/base/qvideowidget.cpp @@ -868,9 +868,6 @@ void QVideoWidget::hideEvent(QHideEvent *event) if (d->currentBackend) d->currentBackend->hideEvent(event); - if (d->outputControl) - d->outputControl->setOutput(QVideoOutputControl::NoOutput); - QWidget::hideEvent(event); } diff --git a/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp index 2427d64..7fb6005 100644 --- a/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp +++ b/tests/auto/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp @@ -357,7 +357,7 @@ void tst_QGraphicsVideoItem::show() QVERIFY(object.testService->rendererControl->surface() != 0); item->hide(); - QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); item->show(); QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); diff --git a/tests/auto/qvideowidget/tst_qvideowidget.cpp b/tests/auto/qvideowidget/tst_qvideowidget.cpp index 37676cf..e30d16b 100644 --- a/tests/auto/qvideowidget/tst_qvideowidget.cpp +++ b/tests/auto/qvideowidget/tst_qvideowidget.cpp @@ -653,7 +653,7 @@ void tst_QVideoWidget::showWindowControl() widget.hide(); - QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::WindowOutput); } void tst_QVideoWidget::showWidgetControl() @@ -677,7 +677,7 @@ void tst_QVideoWidget::showWidgetControl() widget.hide(); - QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::WidgetOutput); QCOMPARE(object.testService->widgetControl->videoWidget()->isVisible(), false); } @@ -702,7 +702,7 @@ void tst_QVideoWidget::showRendererControl() widget.hide(); - QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::NoOutput); + QCOMPARE(object.testService->outputControl->output(), QVideoOutputControl::RendererOutput); } void tst_QVideoWidget::aspectRatioWindowControl() -- cgit v0.12 From b10256b991ea37fdb2360682db87bc9e2f05a80f Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 8 Feb 2010 14:04:05 +0100 Subject: Doc: Updated the configuration file for the Simplified Chinese docs. Reviewed-by: Trust Me --- tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf index 4c67856..29560a2 100644 --- a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf +++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf @@ -10,7 +10,7 @@ url = http://qt.nokia.com/doc/zh_CN/4.7 sourceencoding = UTF-8 outputencoding = UTF-8 -naturallanguage = cn-ZH +naturallanguage = zh-Hans indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index @@ -27,8 +27,14 @@ qhp.projects = Qt qhp.Qt.file = qt.qhp qhp.Qt.namespace = com.trolltech.qt.470 qhp.Qt.virtualFolder = qdoc -qhp.Qt.indexTitle = Qt Reference Documentation -qhp.Qt.indexRoot = +qhp.Qt.title = Tutorials +qhp.Qt.indexTitle = Tutorials +qhp.Qt.indexRoot = tutorials.html +qhp.Qt.selectors = fake:example + +qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN +qhp.Qt.customFilters.Qt.name = Qt 4.7.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 # Files not referenced in any qdoc file (last four are needed by qtdemo) # See also extraimages.HTML @@ -39,14 +45,6 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN -qhp.Qt.customFilters.Qt.name = Qt 4.7.0 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.0 -qhp.Qt.subprojects = tutorials -qhp.Qt.subprojects.tutorials.title = Tutorials -qhp.Qt.subprojects.tutorials.indexTitle = Tutorials -qhp.Qt.subprojects.tutorials.selectors = fake:example - language = Cpp sourcedirs = $QT_SOURCE_TREE/doc/src/zh_CN -- cgit v0.12 From 1f931d2d879cf51d56268f592298f81218fb43fa Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 8 Feb 2010 14:18:18 +0100 Subject: Remove VBO caching and glDrawElements path in QStaticText glDrawElements needs to be handled properly, using triangle strips rather than triangle lists, so the code has been removed for now. The VBO caching did not gain us any particular performance. We rather cache the client-side buffers for the same speed-up but with less clean-up complexity. --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 167 ++++++--------------- 1 file changed, 43 insertions(+), 124 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index c66472c..18d67e9 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1279,50 +1279,25 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem QPaintEngineEx::drawTextItem(p, ti); } -#define QSTATICTEXT_USE_INDEXARRAY +namespace { -class QOpenGLStaticTextUserData: public QObject, public QStaticTextUserData -{ - Q_OBJECT -public: - QOpenGLStaticTextUserData(QGLContext *glContext) - : QStaticTextUserData(OpenGLUserData), - vertexCoordVBOId(0), textureCoordVBOId(0), ctx(glContext) - { - connect(QGLSignalProxy::instance(), - SIGNAL(aboutToDestroyContext(const QGLContext*)), - SLOT(cleanupGLContextRefs(const QGLContext*))); - } - - ~QOpenGLStaticTextUserData() + class QOpenGLStaticTextUserData: public QStaticTextUserData { - if (ctx != 0) - cleanupGLContextRefs(ctx); - } - - QGLContext *ctx; - GLuint vertexCoordVBOId; - GLuint textureCoordVBOId; - -#if defined(QSTATICTEXT_USE_INDEXARRAY) - QVector indices; -#endif + public: + QOpenGLStaticTextUserData() + : QStaticTextUserData(OpenGLUserData) + { + } -public Q_SLOTS: - void cleanupGLContextRefs(const QGLContext *context) - { - if (context == ctx) { - if (vertexCoordVBOId != 0) - glDeleteBuffers(1, &vertexCoordVBOId); + ~QOpenGLStaticTextUserData() + { + } - if (textureCoordVBOId != 0) - glDeleteBuffers(1, &textureCoordVBOId); + QGL2PEXVertexArray vertexCoordinateArray; + QGL2PEXVertexArray textureCoordinateArray; + }; - vertexCoordVBOId = 0; - textureCoordVBOId = 0; - } - } -}; +} void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem, @@ -1357,10 +1332,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp GLfloat dx = 1.0 / cache->width(); GLfloat dy = 1.0 / cache->height(); -#if defined(QSTATICTEXT_USE_INDEXARRAY) - QVector indices; -#endif - bool recreateVertexArrays = false; if (staticTextItem->userDataNeedsUpdate) recreateVertexArrays = true; @@ -1368,93 +1339,49 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp recreateVertexArrays = true; else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) recreateVertexArrays = true; - else if (static_cast(staticTextItem->userData)->ctx != ctx) - recreateVertexArrays = true; - - if (recreateVertexArrays) { - vertexCoordinateArray.clear(); - textureCoordinateArray.clear(); - -#if defined(QSTATICTEXT_USE_INDEXARRAY) - QStaticTextUserData *uData = staticTextItem->userData; - QOpenGLStaticTextUserData *openGlUserData = uData != 0 - && uData->type == QStaticTextUserData::OpenGLUserData - ? static_cast(uData) - : 0; - bool updateIndices = openGlUserData == 0 - || openGlUserData->indices.size() < staticTextItem->numGlyphs; - int j=0; -#endif - - for (int i=0; inumGlyphs; ++i) { - const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); - int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; - int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; - - vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h)); - textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); - -#if defined(QSTATICTEXT_USE_INDEXARRAY) - if (updateIndices) { - for (int k=0; k<6; ++k) - indices.append(j++); - } -#endif - } - if (staticTextItem->useBackendOptimizations) { - QOpenGLStaticTextUserData *userData = - staticTextItem->userData != 0 && staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData - ? static_cast(staticTextItem->userData) - : new QOpenGLStaticTextUserData(ctx); + // Use global arrays by default + QGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray; + QGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray; - int vertexCoordinateArraySize = vertexCoordinateArray.vertexCount() * sizeof(QGLPoint); - if (userData->vertexCoordVBOId == 0) - glGenBuffers(1, &userData->vertexCoordVBOId); - - int textureCoordinateArraySize = textureCoordinateArray.vertexCount() * sizeof(QGLPoint); - if (userData->textureCoordVBOId == 0) - glGenBuffers(1, &userData->textureCoordVBOId); - - glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId); - glBufferData(GL_ARRAY_BUFFER, vertexCoordinateArraySize, - vertexCoordinateArray.data(), GL_STATIC_DRAW); + if (staticTextItem->useBackendOptimizations) { + QOpenGLStaticTextUserData *userData = 0; - glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); - glBufferData(GL_ARRAY_BUFFER, textureCoordinateArraySize, - textureCoordinateArray.data(), GL_STATIC_DRAW); + if (staticTextItem->userData == 0 + || staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData) { -#if defined(QSTATICTEXT_USE_INDEXARRAY) - if (updateIndices) - userData->indices = indices; -#endif - - // If a new user data has been created, make sure we delete the old + userData = new QOpenGLStaticTextUserData(); staticTextItem->setUserData(userData); - staticTextItem->userDataNeedsUpdate = false; } else { - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + userData = static_cast(staticTextItem->userData); } + + // Use cache if backend optimizations is turned on + vertexCoordinates = &userData->vertexCoordinateArray; + textureCoordinates = &userData->textureCoordinateArray; } - if (staticTextItem->useBackendOptimizations) { - Q_ASSERT(staticTextItem->userData != 0); - Q_ASSERT(staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData); - QOpenGLStaticTextUserData *userData = static_cast(staticTextItem->userData); - glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + if (recreateVertexArrays) { + vertexCoordinates->clear(); + textureCoordinates->clear(); - glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0); + for (int i=0; inumGlyphs; ++i) { + const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]); + int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; + int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; -#if defined(QSTATICTEXT_USE_INDEXARRAY) - indices = userData->indices; -#endif + vertexCoordinates->addRect(QRectF(x, y, c.w, c.h)); + textureCoordinates->addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } + + staticTextItem->userDataNeedsUpdate = false; } + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data()); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data()); + if (addOffset) { addOffset = false; matrixDirty = true; @@ -1473,6 +1400,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp QTransform old = s->matrix; if (includeMatrixInCache) s->matrix = QTransform(); + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { // Subpixel antialiasing without gamma correction @@ -1557,14 +1485,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); -#if defined(QSTATICTEXT_USE_INDEXARRAY) - glDrawElements(GL_TRIANGLES, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_INT, indices.constData()); -#else glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); -#endif - - // Reset bindings - glBindBuffer(GL_ARRAY_BUFFER, 0); if (includeMatrixInCache) s->matrix = old; @@ -2191,5 +2112,3 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() } QT_END_NAMESPACE - -#include "qpaintengineex_opengl2.moc" -- cgit v0.12 From f2ba5e4d83f112f14a08e65e032497754750e8fa Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 8 Feb 2010 16:51:40 +0100 Subject: qdoc: Removed debugging code. Reviewed-by: Trust Me --- tools/qdoc3/node.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index 4da916c..9357671 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -570,8 +570,6 @@ void InnerNode::addChild(Node *child) else { if (child->type() == Enum) enumChildren.append(child); - if (childMap.contains(child->name())) - qDebug() << "Duplicate child" << child->name(); childMap.insert(child->name(), child); } } -- cgit v0.12 From deb0f3c17bcbdf4565eb7652ca4ed086f0938bfe Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 8 Feb 2010 20:19:38 +0100 Subject: Doc/qdoc: Converted encoding of ISO-8859-1 docs to UTF-8. Output UTF-8. We now write UTF-8 encoded XHTML and assume all pure documentation which isn't pure ASCII is now UTF-8 encoded. Reviewed-by: Trust Me --- doc/src/legal/3rdparty.qdoc | 12 +- doc/src/legal/licenses.qdoc | 16 +- doc/src/legal/trademarks.qdoc | 2 +- doc/src/tutorials/addressbook-fr.qdoc | 816 ++++++++++++++++---------------- tools/qdoc3/test/qt-build-docs.qdocconf | 9 +- tools/qdoc3/test/qt.qdocconf | 9 +- 6 files changed, 437 insertions(+), 427 deletions(-) diff --git a/doc/src/legal/3rdparty.qdoc b/doc/src/legal/3rdparty.qdoc index b710449..bb2effa 100644 --- a/doc/src/legal/3rdparty.qdoc +++ b/doc/src/legal/3rdparty.qdoc @@ -116,9 +116,9 @@ \hr - Copyright (C) 2004,2007  Red Hat, Inc.\br - Copyright (C) 1998-2004  David Turner and Werner Lemberg\br - Copyright (C) 2006  Behdad Esfahbod\br + Copyright (C) 2004,2007  Red Hat, Inc.\br + Copyright (C) 1998-2004  David Turner and Werner Lemberg\br + Copyright (C) 2006  Behdad Esfahbod\br Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) This is part of HarfBuzz, an OpenType Layout engine library. @@ -137,7 +137,7 @@ THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS + FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. @@ -323,7 +323,7 @@ duplicated in all such forms and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed - by the University of California, Berkeley.  The name of the + by the University of California, Berkeley.  The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR @@ -364,7 +364,7 @@ documentation for such software. THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. diff --git a/doc/src/legal/licenses.qdoc b/doc/src/legal/licenses.qdoc index 9e680a6..344ebd4 100644 --- a/doc/src/legal/licenses.qdoc +++ b/doc/src/legal/licenses.qdoc @@ -276,14 +276,14 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\br -     * Redistributions of source code must retain the above copyright -       notice, this list of conditions and the following disclaimer.\br -     * Redistributions in binary form must reproduce the above copyright -       notice, this list of conditions and the following disclaimer in the -       documentation and/or other materials provided with the distribution.\br -     * Neither the name of Research In Motion Limited nor the -       names of its contributors may be used to endorse or promote products -       derived from this software without specific prior written permission. +     * Redistributions of source code must retain the above copyright +       notice, this list of conditions and the following disclaimer.\br +     * Redistributions in binary form must reproduce the above copyright +       notice, this list of conditions and the following disclaimer in the +       documentation and/or other materials provided with the distribution.\br +     * Neither the name of Research In Motion Limited nor the +       names of its contributors may be used to endorse or promote products +       derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Research In Motion Limited ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/doc/src/legal/trademarks.qdoc b/doc/src/legal/trademarks.qdoc index a7b5764..23d0cf6 100644 --- a/doc/src/legal/trademarks.qdoc +++ b/doc/src/legal/trademarks.qdoc @@ -47,7 +47,7 @@ \brief Information about trademarks owned by Nokia and other organisations. Nokia, the Nokia logo, Qt, and the Qt logo are trademarks of Nokia -  Corporation and/or its subsidiaries in Finland and other countries. +  Corporation and/or its subsidiaries in Finland and other countries. \list \o Intel, Intel Inside (logos), MMX and Pentium are \reg trademarks of diff --git a/doc/src/tutorials/addressbook-fr.qdoc b/doc/src/tutorials/addressbook-fr.qdoc index d3bd1ca..98c44a3 100644 --- a/doc/src/tutorials/addressbook-fr.qdoc +++ b/doc/src/tutorials/addressbook-fr.qdoc @@ -47,47 +47,47 @@ \nextpage {tutorials/addressbook-fr/part1}{Chapitre 1} \title Tutoriel "Carnet d'adresses" - \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt. + \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt. - Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur) - à l'aide des outils fournis par la plateforme multiplate-forme Qt. + Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur) + à l'aide des outils fournis par la plateforme multiplate-forme Qt. \image addressbook-tutorial-screenshot.png - Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies + Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies par Qt, tel que: \list - \o Les Widgets et leur mise en page à l'aide des layouts + \o Les Widgets et leur mise en page à l'aide des layouts \o Les signaux et slots - \o Les structures de données de collections - \o Les entrées/sorties + \o Les structures de données de collections + \o Les entrées/sorties \endlist Si c'est votre premier contact avec Qt, lisez \l{How to Learn Qt}{Comment apprendre Qt} - si ce n'est déjà fait. + si ce n'est déjà fait. - Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook + Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook Les chapitres du tutoriel: \list 1 \o \l{tutorials/addressbook-fr/part1}{Conception de l'interface utilisateur} \o \l{tutorials/addressbook-fr/part2}{Ajouter des adresses} - \o \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments} - \o \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses} + \o \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments} + \o \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses} \o \l{tutorials/addressbook-fr/part5}{Ajout d'une fonction de recherche} \o \l{tutorials/addressbook-fr/part6}{Sauvegarde et chargement} - \o \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées} + \o \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées} \endlist - La petite application que nous développerons ici ne possède pas tous les éléments + La petite application que nous développerons ici ne possède pas tous les éléments des interfaces dernier cri, elle va nous permettre d'utiliser les techniques de base - utilisées dans les applications plus complexes. + utilisées dans les applications plus complexes. - Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple - "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant - les menus et barres d'outils, la barre d'état, etc. + Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple + "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant + les menus et barres d'outils, la barre d'état, etc. */ @@ -98,156 +98,156 @@ \example tutorials/addressbook-fr/part1 \title Carnet d'adresses 1 - Conception de l'interface utilisateur - La première partie de ce tutoriel traite de la conception d'une interface graphique + La première partie de ce tutoriel traite de la conception d'une interface graphique (GUI) basique, que l'on utilisera pour l'application Carnet d'adresses. - La première étape dans la création d'applications graphiques est la conception de - l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels - et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base. - Le résultat attendu est illustré par la capture d'écran ci-dessous. + La première étape dans la création d'applications graphiques est la conception de + l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels + et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base. + Le résultat attendu est illustré par la capture d'écran ci-dessous. \image addressbook-tutorial-part1-screenshot.png Nous allons avoir besoin de deux objets QLabel, \c nameLabel et \c addressLabel, ainsi que deux champs de saisie: un objet QLineEdit, \c nameLine, et un objet - QTextEdit, \c addressText, afin de permettre à l'utilisateur d'entrer le nom d'un - contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous. + QTextEdit, \c addressText, afin de permettre à l'utilisateur d'entrer le nom d'un + contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous. \image addressbook-tutorial-part1-labeled-screenshot.png - Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses: + Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses: \list - \o \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook, - \o \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe + \o \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook, + \o \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe \c AddressBook - \o \c{main.cpp} - le fichier qui contient la méthode \c main() , et + \o \c{main.cpp} - le fichier qui contient la méthode \c main() , et une instance de la classe \c AddressBook. \endlist - \section1 Programmation en Qt - héritage + \section1 Programmation en Qt - héritage - Lorsque l'on écrit des programmes avec Qt, on a généralement recours à - l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités. - C'est l'un des concepts fondamentaux de la création de widgets personnalisés - ou de collections de widgets. Utiliser l'héritage afin de compléter - ou modifier le comportement d'un widget présente les avantages suivants: + Lorsque l'on écrit des programmes avec Qt, on a généralement recours à + l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités. + C'est l'un des concepts fondamentaux de la création de widgets personnalisés + ou de collections de widgets. Utiliser l'héritage afin de compléter + ou modifier le comportement d'un widget présente les avantages suivants: \list - \o La possibilité d'implémenter des méthodes virtuelles et des méthodes - virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité - d'utiliser l'implémentation de la classe mère si besoin est. + \o La possibilité d'implémenter des méthodes virtuelles et des méthodes + virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité + d'utiliser l'implémentation de la classe mère si besoin est. \o Cela permet l'encapsulation partielle de l'interface utilisateur dans une classe, - afin que les autres parties de l'application n'aient pas à se soucier de chacun des + afin que les autres parties de l'application n'aient pas à se soucier de chacun des widgets qui forment l'interface utilisateur. - \o La classe fille peut être utilisée pour créer de nombreux widgets personnalisés - dans une même application ou bibliothèque, et le code de la classe fille peut être - réutilisé dans d'autres projets + \o La classe fille peut être utilisée pour créer de nombreux widgets personnalisés + dans une même application ou bibliothèque, et le code de la classe fille peut être + réutilisé dans d'autres projets \endlist Comme Qt ne fournit pas de widget standard pour un carnet d'adresses, nous - partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités. - La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un + partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités. + La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un widget carnet d'adresses basique. \section1 La classe AddressBook Le fichier \l{tutorials/addressbook-fr/part1/addressbook.h}{\c addressbook.h} permet de - définir la classe \c AddressBook. + définir la classe \c AddressBook. - On commence par définir \c AddressBook comme une classe fille de QWidget et déclarer - un constructeur. On utilise également la macro Q_OBJECT pour indiquer que la classe - exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que - l'internationalisation, bien que nous ne les utilisions pas à ce stade. + On commence par définir \c AddressBook comme une classe fille de QWidget et déclarer + un constructeur. On utilise également la macro Q_OBJECT pour indiquer que la classe + exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que + l'internationalisation, bien que nous ne les utilisions pas à ce stade. \snippet tutorials/addressbook-fr/part1/addressbook.h class definition - La classe contient les déclarations de \c nameLine et \c addressText, - les instances privées de QLineEdit et QTextEdit mentionnées précédemment. - Vous verrez, dans les chapitres à venir que les informations contenues - dans \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes + La classe contient les déclarations de \c nameLine et \c addressText, + les instances privées de QLineEdit et QTextEdit mentionnées précédemment. + Vous verrez, dans les chapitres à venir que les informations contenues + dans \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes du carnet d'adresses. - Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser - puisque nous n'aurons pas besoin d'y faire référence après leur création. - La façon dont Qt gère la parenté des objets est traitée dans la section suivante. + Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser + puisque nous n'aurons pas besoin d'y faire référence après leur création. + La façon dont Qt gère la parenté des objets est traitée dans la section suivante. - La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt. + La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt. Pour le moment, il est bon de voir la macro Q_OBJECT comme un raccourci nous - permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}. + permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}. - Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons - passer à l'implémentation du fichier \c addressbook.cpp. + Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons + passer à l'implémentation du fichier \c addressbook.cpp. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e parent. - Par convention, on passe ce paramètre au constructeur de la classe mère. - Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile - pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent, - tous ses enfants seront détruits égalament. + Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e parent. + Par convention, on passe ce paramètre au constructeur de la classe mère. + Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile + pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent, + tous ses enfants seront détruits égalament. \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields - à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux - QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et - \c addressText. La méthode \l{QObject::tr()}{tr()} renvoie une version traduite - de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie - la chaîne elle même. On peut voir cette méthode comme un marqueur \tt{}, permettant de repérer les objets QString à considérer - pour traduire une application. Vous remarquerez, dans les chapitres à venir - comme dans les \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois - que l'on utilise une chaîne susceptible d'être traduite. + à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux + QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et + \c addressText. La méthode \l{QObject::tr()}{tr()} renvoie une version traduite + de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie + la chaîne elle même. On peut voir cette méthode comme un marqueur \tt{}, permettant de repérer les objets QString à considérer + pour traduire une application. Vous remarquerez, dans les chapitres à venir + comme dans les \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois + que l'on utilise une chaîne susceptible d'être traduite. Lorsque l'on programme avec Qt, il est utile de savoir comment fonctionnent les agencements ou layouts. Qt fournit trois classes principales de layouts pour - contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout. + contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout. \image addressbook-tutorial-part1-labeled-layout.png - On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière - structurée. QGridLayout divise l'espace disponible en une grille, et place les - widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne. - Le diagramme ci-dessus présente les cellules et la position des widgets, et cette - organisation est obtenue à l'aide du code suivant: + On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière + structurée. QGridLayout divise l'espace disponible en une grille, et place les + widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne. + Le diagramme ci-dessus présente les cellules et la position des widgets, et cette + organisation est obtenue à l'aide du code suivant: \snippet tutorials/addressbook/part1/addressbook.cpp layout - On remarque que le label \c AddressLabel est positionné en utilisant Qt::AlignTop - comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré - verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt, + On remarque que le label \c AddressLabel est positionné en utilisant Qt::AlignTop + comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré + verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt, consultez la section \l{Layout Management}. - Afin d'installer l'objet layout dans un widget, il faut appeler la méthode + Afin d'installer l'objet layout dans un widget, il faut appeler la méthode \l{QWidget::setLayout()}{setLayout()} du widget en question: \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout - Enfin, on initialise le titre du widget à "Simple Address Book" + Enfin, on initialise le titre du widget à "Simple Address Book" - \section1 Exécution de l'application + \section1 Exécution de l'application - Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette - fonction, on crée une instance de QApplication, \c app. QApplication se charge de - des ressources communes à l'ensemble de l'application, tel que les polices de - caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements. + Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette + fonction, on crée une instance de QApplication, \c app. QApplication se charge de + des ressources communes à l'ensemble de l'application, tel que les polices de + caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements. De ce fait, il y a toujours un objet QApplication dans toute application graphique en Qt. \snippet tutorials/addressbook/part1/main.cpp main function On construit un nouveau widget \c AddressBook sur la pile et on invoque - sa méthode \l{QWidget::show()}{show()} pour l'afficher. - Cependant, le widget ne sera pas visible tant que la boucle d'évènements - n'aura pas été lancée. On démarre la boucle d'évènements en appelant la - méthode \l{QApplication::}{exec()} de l'application; le résultat renvoyé - par cette méthode est lui même utilisé comme valeur de retour pour la méthode + sa méthode \l{QWidget::show()}{show()} pour l'afficher. + Cependant, le widget ne sera pas visible tant que la boucle d'évènements + n'aura pas été lancée. On démarre la boucle d'évènements en appelant la + méthode \l{QApplication::}{exec()} de l'application; le résultat renvoyé + par cette méthode est lui même utilisé comme valeur de retour pour la méthode \c main(). - On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin + On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin du programme, l'objet sort du scope de la fonction \c main() et tous ses widgets enfants - sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire. + sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire. */ /*! @@ -258,53 +258,53 @@ \example tutorials/addressbook-fr/part2 \title Carnet d'adresses 2 - Ajouter des adresses - La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon - d'interactivité. + La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon + d'interactivité. \image addressbook-tutorial-part2-add-contact.png Nous allons fournir un bouton que l'utilisateur peut - cliquer pour ajouter un nouveau contact. Une structure de données est aussi - nécessaire afin de pouvoir stocker les contacts en mémoire. + cliquer pour ajouter un nouveau contact. Une structure de données est aussi + nécessaire afin de pouvoir stocker les contacts en mémoire. - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Maintenant que nous avons mis en place les labels et les champs de saisie, - nous ajoutons les boutons pour compléter le processus d'ajout d'un contact. + nous ajoutons les boutons pour compléter le processus d'ajout d'un contact. Cela veut dire que notre fichier \c addressbook.h a maintenant trois objets QPushButton et trois slots publics correspondant. \snippet tutorials/addressbook/part2/addressbook.h slots - Un slot est une méthode qui répond à un signal. Nous allons - voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}. - Pour une explication détaillée du concept de signal et slot, vous pouvez - vous référer au document \l{Signals and Slots}. + Un slot est une méthode qui répond à un signal. Nous allons + voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}. + Pour une explication détaillée du concept de signal et slot, vous pouvez + vous référer au document \l{Signals and Slots}. Les trois objets QPushButton \c addButton, \c submitButton et \c cancelButton - sont maintenant inclus dans la déclaration des variables privées, avec - \c nameLine et \c addressText du chapitre précédent. + sont maintenant inclus dans la déclaration des variables privées, avec + \c nameLine et \c addressText du chapitre précédent. \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration Nous avons besoin d'un conteneur pour stocker les contacts du carnet - d'adresses, de façon à pouvoir les énumérer et les afficher. - Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker - des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact + d'adresses, de façon à pouvoir les énumérer et les afficher. + Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker + des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact est la \e{valeur}. \snippet tutorials/addressbook/part2/addressbook.h remaining private variables - Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress. - Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact - affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables + Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress. + Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact + affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables si l'utilisateur clique sur "Cancel", il est possible de revenir - à l'affichage du dernier contact. + à l'affichage du dernier contact. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook Dans le constructeur de \c AddressBook, \c nameLine et - \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage + \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage mais pas la modification du contact courant. \dots @@ -317,16 +317,16 @@ \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration - Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()} - {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant - \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque - l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact() - décrite plus loin. + Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()} + {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant + \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque + l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact() + décrite plus loin. \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots Nous connectons le signal \l{QPushButton::clicked()}{clicked()} de chaque bouton - au slot qui gèrera l'action. + au slot qui gèrera l'action. L'image ci-dessous illustre ceci: \image addressbook-tutorial-part2-signals-and-slots.png @@ -336,77 +336,77 @@ \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout - La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour - assurer que les boutons ne sont pas répartis uniformément, mais regroupés - dans la partie supperieure du widget. La figure ci-dessous montre la différence - si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas. + La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour + assurer que les boutons ne sont pas répartis uniformément, mais regroupés + dans la partie supperieure du widget. La figure ci-dessous montre la différence + si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas. \image addressbook-tutorial-part2-stretch-effects.png - Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant + Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant \l{QGridLayout::addLayout()}{addLayout()}. Ceci nous permet d'imbriquer les mises en page puisque \c buttonLayout1 est maintenant un enfant de \c mainLayout. \snippet tutorials/addressbook/part2/addressbook.cpp grid layout - Les coordonnées du layout global ressemblent maintenant à ça: + Les coordonnées du layout global ressemblent maintenant à ça: \image addressbook-tutorial-part2-labeled-layout.png - Dans la méthode \c addContact(), nous stockons les détails du dernier - contact affiché dans \c oldName et \c oldAddress. Ensuite, nous - vidons ces champs de saisie et nous désactivons le mode - lecture seule. Le focus est placé sur \c nameLine et on affiche + Dans la méthode \c addContact(), nous stockons les détails du dernier + contact affiché dans \c oldName et \c oldAddress. Ensuite, nous + vidons ces champs de saisie et nous désactivons le mode + lecture seule. Le focus est placé sur \c nameLine et on affiche \c submitButton et \c cancelButton. \snippet tutorials/addressbook/part2/addressbook.cpp addContact - La méthode \c submitContact() peut être divisée en trois parties: + La méthode \c submitContact() peut être divisée en trois parties: \list 1 - \o Nous extrayons les détails du contact depuis \c nameLine et \c addressText + \o Nous extrayons les détails du contact depuis \c nameLine et \c addressText et les stockons dans des objets QString. Nous les validons pour s'assurer - que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie - vides; sinon un message est affiché avec QMessageBox pour rappeller à - l'utilisateur que les deux champs doivent être complétés. + que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie + vides; sinon un message est affiché avec QMessageBox pour rappeller à + l'utilisateur que les deux champs doivent être complétés. \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1 - \o Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts - existant n'entre en conflit avec le nouveau, nous l'ajoutons à + \o Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts + existant n'entre en conflit avec le nouveau, nous l'ajoutons à \c contacts et nous affichons un QMessageBox pour informer l'utilisateur - que le contact a été ajouté. + que le contact a été ajouté. \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2 - Si le contact existe déjà, nous affichons un QMessageBox pour informer - l'utilisateur du problème. - Notre objet \c contacts est basé sur des paires clé-valeur formés par - le nom et l'adresse, nous voulons nous assurer que la \e clé est unique. + Si le contact existe déjà, nous affichons un QMessageBox pour informer + l'utilisateur du problème. + Notre objet \c contacts est basé sur des paires clé-valeur formés par + le nom et l'adresse, nous voulons nous assurer que la \e clé est unique. - \o Une fois que les deux vérifications précédentes ont été traitées, - nous restaurons les boutons à leur état normal à l'aide du code + \o Une fois que les deux vérifications précédentes ont été traitées, + nous restaurons les boutons à leur état normal à l'aide du code suivant: \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3 \endlist - La capture d'écran ci-dessous montre l'affichage fournit par un objet - QMessageBox, utilisé ici pour afficher un message d'information - à l'utilisateur: + La capture d'écran ci-dessous montre l'affichage fournit par un objet + QMessageBox, utilisé ici pour afficher un message d'information + à l'utilisateur: \image addressbook-tutorial-part2-add-successful.png - La méthode \c cancel() restaure les détails du dernier contact, active + La méthode \c cancel() restaure les détails du dernier contact, active \c addButton, et cache \c submitButton et \c cancelButton. \snippet tutorials/addressbook/part2/addressbook.cpp cancel - L'idée générale pour augmenter la flexibilité lors de l'ajout d'un - contact est de donner la possiblité de cliquer sur "Add" - ou "Cancel" à n'importe quel moment. - L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées + L'idée générale pour augmenter la flexibilité lors de l'ajout d'un + contact est de donner la possiblité de cliquer sur "Add" + ou "Cancel" à n'importe quel moment. + L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées jusqu'ici: \image addressbook-tutorial-part2-add-flowchart.png @@ -418,118 +418,118 @@ \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} \nextpage {tutorials/addressbook-fr/part4}{Chapitre 4} \example tutorials/addressbook-fr/part3 - \title Carnet d'adresses 3 - Navigation entre les éléments + \title Carnet d'adresses 3 - Navigation entre les éléments - L'application "Carnet d'adresses" est maintenant à moitié terminée. Il + L'application "Carnet d'adresses" est maintenant à moitié terminée. Il nous faut maintenant ajouter quelques fonctions pour naviguer entre - les contacts. Avant de commencer, il faut se décider sur le type de structure de - données le plus approprié pour stocker les contacts. + les contacts. Avant de commencer, il faut se décider sur le type de structure de + données le plus approprié pour stocker les contacts. - Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur, - avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur. + Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur, + avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur. Cela fonctionnait bien jusqu'ici, mais pour ajouter la navigation entre les - entrées, quelques améliorations sont nécessaires. + entrées, quelques améliorations sont nécessaires. - Nous améliorerons le QMap en le faisant ressembler à une structure de données - similaire à une liste liée, où tous les éléments sont connectés, y compris - le premier et le dernier élément. La figure ci-dessous illustre cette structure - de donnée. + Nous améliorerons le QMap en le faisant ressembler à une structure de données + similaire à une liste liée, où tous les éléments sont connectés, y compris + le premier et le dernier élément. La figure ci-dessous illustre cette structure + de donnée. \image addressbook-tutorial-part3-linkedlist.png - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Pour ajouter les fonctions de navigation au carnet d'adresses, nous avons - besoin de deux slots supplémentaires dans notre classe \c AddressBook: - \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h: + besoin de deux slots supplémentaires dans notre classe \c AddressBook: + \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h: \snippet tutorials/addressbook/part3/addressbook.h navigation functions Nous avons aussi besoin de deux nouveaux objets QPushButton, nous ajoutons - donc les variables privées \c nextButton et \c previousButton. + donc les variables privées \c nextButton et \c previousButton. \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous - instancions \c nextButton et \c previousButton et nous les désactivons - par défaut. Nous faisons ceci car la navigation ne doit être activée + A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous + instancions \c nextButton et \c previousButton et nous les désactivons + par défaut. Nous faisons ceci car la navigation ne doit être activée que lorsqu'il y a plus d'un contact dans le carnet d'adresses. \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons - Nous connectons alors ces boutons à leur slots respectifs: + Nous connectons alors ces boutons à leur slots respectifs: \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals - L'image ci-dessous montre l'interface utilisateur que nous allons créer. - Remarquez que cela ressemble de plus en plus à l'interface du programme + L'image ci-dessous montre l'interface utilisateur que nous allons créer. + Remarquez que cela ressemble de plus en plus à l'interface du programme complet. \image addressbook-tutorial-part3-screenshot.png Nous suivons les conventions pour les fonctions \c next() et \c previous() - en plaçant \c nextButton à droite et \c previousButton à gauche. Pour + en plaçant \c nextButton à droite et \c previousButton à gauche. Pour faire cette mise en page intuitive, nous utilisons un QHBoxLayout pour - placer les widgets côte à côte: + placer les widgets côte à côte: \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout - L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout. + L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout. \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout - La figure ci-dessous montre les systèmes de coordonnées pour les widgets du + La figure ci-dessous montre les systèmes de coordonnées pour les widgets du \c mainLayout. \image addressbook-tutorial-part3-labeled-layout.png - Dans notre méthode \c addContact(), nous avons desactivé ces boutons - pour être sûr que l'utilisateur n'utilise pas la navigation lors de + Dans notre méthode \c addContact(), nous avons desactivé ces boutons + pour être sûr que l'utilisateur n'utilise pas la navigation lors de l'ajout d'un contact. \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation - Dans notre méthode \c submitContact(), nous activons les boutons de + Dans notre méthode \c submitContact(), nous activons les boutons de navigation, \c nextButton et \c previousButton, en fonction de la - taille de \c contacts. Commen mentionné plus tôt, la navigation n'est - activée que si il y a plus d'un contact dans le carnet d'adresses. + taille de \c contacts. Commen mentionné plus tôt, la navigation n'est + activée que si il y a plus d'un contact dans le carnet d'adresses. Les lignes suivantes montrent comment faire cela: \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation Nous incluons aussi ces lignes de code dans le bouton \c cancel(). - Souvenez vous que nous voulons émuler une liste-liée ciruculaire à - l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur - sur \c contact dans la méthode \c next(), et ensuite: + Souvenez vous que nous voulons émuler une liste-liée ciruculaire à + l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur + sur \c contact dans la méthode \c next(), et ensuite: \list - \o Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons - \o Si l'itérateur est à la fin de \c contacts, nous changeons sa position - jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap + \o Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons + \o Si l'itérateur est à la fin de \c contacts, nous changeons sa position + jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap fonctionne comme une liste circulaire. \endlist \snippet tutorials/addressbook/part3/addressbook.cpp next() function - Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts, + Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts, nous affichons son contenu sur \c nameLine et \c addressText. - De la même façon, pour la méthode \c previous(), nous obtenons un - itérateur sur \c contacts et ensuite: + De la même façon, pour la méthode \c previous(), nous obtenons un + itérateur sur \c contacts et ensuite: \list - \o Si l'itérateur est à la fin de \c contacts, on réinitialise + \o Si l'itérateur est à la fin de \c contacts, on réinitialise l'affichage et on retourne. - \o Si l'itérateur est au début de \c contacts, on change sa - position jusqu'à la fin - \o Ensuite, on décrémente l'itérateur + \o Si l'itérateur est au début de \c contacts, on change sa + position jusqu'à la fin + \o Ensuite, on décrémente l'itérateur \endlist \snippet tutorials/addressbook/part3/addressbook.cpp previous() function - à nouveau, nous affichons le contenu de l'objet courant dans \c contacts. + à nouveau, nous affichons le contenu de l'objet courant dans \c contacts. */ @@ -540,27 +540,27 @@ \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} \nextpage {tutorials/addressbook-fr/part5}{Chapitre 5} \example tutorials/addressbook-fr/part4 - \title Carnet d'Adresses 4 - éditer et supprimer des adresses + \title Carnet d'Adresses 4 - éditer et supprimer des adresses - Dans ce chapitre, nous verrons comment modifier les données des contacts + Dans ce chapitre, nous verrons comment modifier les données des contacts contenus dans l'application carnet d'adresses. \image addressbook-tutorial-screenshot.png Nous avons maintenant un carnet d'adresses qui ne se contente pas de - lister des contacts de façon ordonnée, mais permet également la - navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et - supprimer, afin que les détails associés à un contact puissent être - modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère - modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux - modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas - définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les + lister des contacts de façon ordonnée, mais permet également la + navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et + supprimer, afin que les détails associés à un contact puissent être + modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère + modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux + modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas + définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les boutons correspondants manuellement, au prix de multiples redondances dans le code. - Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles. + Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles. \list \o \c{NavigationMode}, @@ -568,22 +568,22 @@ \o \c{EditingMode}. \endlist - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook - Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode : + Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode : \snippet tutorials/addressbook/part4/addressbook.h Mode enum - On ajoute également deux nouveaux slots, \c editContact() et - \c removeContact(), à notre liste de slots publics. + On ajoute également deux nouveaux slots, \c editContact() et + \c removeContact(), à notre liste de slots publics. \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots - Afin de basculer d'un mode à l'autre, on introduit la méthode - \c updateInterface() pour contrôller l'activation et la désactivation de - tous les objets QPushButton. On ajoute également deux nouveaux boutons, - \c editButton et \c removeButton, pour les fonctions d'édition - et de suppression mentionnées plus haut. + Afin de basculer d'un mode à l'autre, on introduit la méthode + \c updateInterface() pour contrôller l'activation et la désactivation de + tous les objets QPushButton. On ajoute également deux nouveaux boutons, + \c editButton et \c removeButton, pour les fonctions d'édition + et de suppression mentionnées plus haut. \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration \dots @@ -591,97 +591,97 @@ \dots \snippet tutorials/addressbook/part4/addressbook.h mode declaration - Enfin, on déclare \c currentMode pour garder une trace du mode - actuellement utilisé. + Enfin, on déclare \c currentMode pour garder une trace du mode + actuellement utilisé. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - Il nous faut maintenant implémenter les fonctionnalités de changement de + Il nous faut maintenant implémenter les fonctionnalités de changement de mode de l'application carnet d'adresses. Les boutons \c editButton et - \c removeButton sont instanciés et désactivés par défaut, puisque le - carnet d'adresses démarre sans aucun contact en mémoire. + \c removeButton sont instanciés et désactivés par défaut, puisque le + carnet d'adresses démarre sans aucun contact en mémoire. \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons - Ces boutons sont ensuite connectés à leurs slots respectifs, - \c editContact() et \c removeContact(), avant d'être ajoutés à + Ces boutons sont ensuite connectés à leurs slots respectifs, + \c editContact() et \c removeContact(), avant d'être ajoutés à \c buttonLayout1. \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove \dots \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout - La methode \c editContact() place les anciens détails du contact dans + La methode \c editContact() place les anciens détails du contact dans \c oldName et \c oldAddress, avant de basculer vers le mode \c EditingMode. Dans ce mode, les boutons \c submitButton et - \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent - modifier les détails du contact et cliquer sur l'un de ces deux boutons + \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent + modifier les détails du contact et cliquer sur l'un de ces deux boutons par la suite. \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function - La méthode \c submitContact() a été divisée en deux avec un bloc + La méthode \c submitContact() a été divisée en deux avec un bloc \c{if-else}. On teste \c currentMode pour voir si le mode courant est - \c AddingMode. Si c'est le cas, on procède à l'ajout. + \c AddingMode. Si c'est le cas, on procède à l'ajout. \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning \dots \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1 Sinon, on s'assure que \c currentMode est en \c EditingMode. Si c'est le - cas, on compare \c oldName et \c name. Si le nom a changé, on supprime - l'ancien contact de \c contacts et on insère le contact mis a jour. + cas, on compare \c oldName et \c name. Si le nom a changé, on supprime + l'ancien contact de \c contacts et on insère le contact mis a jour. \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2 - Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à - \c address), on met à jour l'adresse du contact. Enfin on règle - \c currentMode à \c NavigationMode. C'est une étape importante puisque - c'est cela qui réactive tous les boutons désactivés. + Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à + \c address), on met à jour l'adresse du contact. Enfin on règle + \c currentMode à \c NavigationMode. C'est une étape importante puisque + c'est cela qui réactive tous les boutons désactivés. - Afin de retirer un contact du carnet d'adresses, on implémente la méthode - \c removeContact(). Cette méthode vérifie que le contact est présent dans + Afin de retirer un contact du carnet d'adresses, on implémente la méthode + \c removeContact(). Cette méthode vérifie que le contact est présent dans \c contacts. \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function - Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant - confirmation de la suppression à l'utilisateur. Une fois la confirmation - effectuée, on appelle \c previous(), afin de s'assurer que l'interface - utilisateur affiche une autre entrée, et on supprime le contact en - utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un + Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant + confirmation de la suppression à l'utilisateur. Une fois la confirmation + effectuée, on appelle \c previous(), afin de s'assurer que l'interface + utilisateur affiche une autre entrée, et on supprime le contact en + utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un souci pratique, on informe l'utilisateur de la suppression par le biais - d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette - méthode sont représentées ci-dessous. + d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette + méthode sont représentées ci-dessous. \image addressbook-tutorial-part4-remove.png - \section2 Mise à jour de l'Interface utilisateur + \section2 Mise à jour de l'Interface utilisateur - On a évoqué plus haut la méthode \c updateInterface() comme moyen - d'activer et de désactiver les différents boutons de l'interface en - fonction du mode. Cette méthode met à jour le mode courant selon - l'argument \c mode qui lui est passé, en l'assignant à \c currentMode, + On a évoqué plus haut la méthode \c updateInterface() comme moyen + d'activer et de désactiver les différents boutons de l'interface en + fonction du mode. Cette méthode met à jour le mode courant selon + l'argument \c mode qui lui est passé, en l'assignant à \c currentMode, avant de tester sa valeur. - Chacun des boutons est ensuite activé ou désactivé, en fonction du mode. + Chacun des boutons est ensuite activé ou désactivé, en fonction du mode. Le code source pour les cas \c AddingMode et \c EditingMode est visible ci-dessous: \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1 Dans le cas de \c NavigationMode, en revanche, des tests conditionnels - sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de - s'assurer que les boutons \c editButton et \c removeButton ne sont activés + sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de + s'assurer que les boutons \c editButton et \c removeButton ne sont activés que s'il existe au moins un contact dans le carnet d'adresses; - \c nextButton et \c previousButton ne sont activés que lorsqu'il existe + \c nextButton et \c previousButton ne sont activés que lorsqu'il existe plus d'un contact dans le carnet d'adresses. \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2 - En effectuant les opérations de réglage du mode et de mise à jour de - l'interface utilisateur au sein de la même méthode, on est à l'abri de - l'éventualité où l'interface utilisateur se "désynchronise" de l'état + En effectuant les opérations de réglage du mode et de mise à jour de + l'interface utilisateur au sein de la même méthode, on est à l'abri de + l'éventualité où l'interface utilisateur se "désynchronise" de l'état interne de l'application. */ @@ -694,7 +694,7 @@ \example tutorials/addressbook-fr/part5 \title Carnet d'adresse 5 - Ajout d'une fonction de recherche - Dans ce chapitre, nous allons voir les possibilités pour rechercher + Dans ce chapitre, nous allons voir les possibilités pour rechercher des contacts dans le carnet d'adresse. \image addressbook-tutorial-part5-screenshot.png @@ -703,110 +703,110 @@ il devient difficile de naviguer avec les boutons \e Next et \e Previous. Dans ce cas, une fonction de recherche serait plus efficace pour rechercher les contacts. - La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position + La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position dans le paneau de bouton. Lorsque l'utilisateur clique sur le bouton \e Find, il est courant d'afficher - une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact. + une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact. Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour - implémenter la class \c FindDialog. + implémenter la class \c FindDialog. - \section1 Définition de la classe FindDialog + \section1 Définition de la classe FindDialog \image addressbook-tutorial-part5-finddialog.png - Pour sous-classer QDialog, nous commençons par inclure le header de - QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les + Pour sous-classer QDialog, nous commençons par inclure le header de + QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les classes QLineEdit et QPushButton car nous utilisons ces widgets dans notre classe dialogue. Tout comme dans la classe \c AddressBook, la classe \c FindDialog utilise - la macro Q_OBJECT et son constructeur est défini de façon à accepter - un QWidget parent, même si cette boîte de dialogue sera affichée dans une - fenêtre séparée. + la macro Q_OBJECT et son constructeur est défini de façon à accepter + un QWidget parent, même si cette boîte de dialogue sera affichée dans une + fenêtre séparée. \snippet tutorials/addressbook/part5/finddialog.h FindDialog header - Nous définissons la méthode publique \c getFindText() pour être utilisée + Nous définissons la méthode publique \c getFindText() pour être utilisée par les classes qui instancient \c FindDialog, ce qui leur permet d'obtenir - le texte entré par l'utilisateur. Un slot public, \c findClicked(), est - défini pour prendre en charge le texte lorsque l'utilisateur clique sur + le texte entré par l'utilisateur. Un slot public, \c findClicked(), est + défini pour prendre en charge le texte lorsque l'utilisateur clique sur le bouton \gui Find. - Finalement, nous définissons les variables privées \c findButton, + Finalement, nous définissons les variables privées \c findButton, \c lineEdit et \c findText, qui correspondent respectivement au bouton \gui Find, au champ de texte dans lequel l'utilisateur tape le texte - à rechercher, et à une variable interne stockant le texte pour une - utilisation ultérieure. + à rechercher, et à une variable interne stockant le texte pour une + utilisation ultérieure. - \section1 Implémentation de la classe FindDialog + \section1 Implémentation de la classe FindDialog Dans le constructeur de \c FindDialog, nous instancions les objets des - variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite + variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite un QHBoxLayout pour positionner les widgets. \snippet tutorials/addressbook/part5/finddialog.cpp constructor - Nous mettons en place la mise en page et le titre de la fenêtre, et + Nous mettons en place la mise en page et le titre de la fenêtre, et nous connectons les signaux aux slots. Remarquez que le signal - \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté - à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot + \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté + à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot \l{QDialog::accept()}{accept()} fourni par le QDialog ferme - la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}. - Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe - \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera - expliqué plus loin lorsque nous verrons la méthode \c findContact(). + la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}. + Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe + \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera + expliqué plus loin lorsque nous verrons la méthode \c findContact(). \image addressbook-tutorial-part5-signals-and-slots.png Dans \c findClicked(), nous validons le champ de texte pour nous - assurer que l'utilisateur n'a pas cliqué sur le bouton \gui Find sans - avoir entré un nom de contact. Ensuite, nous stockons le texte du champ - d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le - contenu de \c lineEdit et cachons la boîte de dialogue. + assurer que l'utilisateur n'a pas cliqué sur le bouton \gui Find sans + avoir entré un nom de contact. Ensuite, nous stockons le texte du champ + d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le + contenu de \c lineEdit et cachons la boîte de dialogue. \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function - La variable \c findText a un accesseur publique associé: \c getFindText(). - Étant donné que nous ne modifions \c findText directement que dans le - constructeur et la méthode \c findClicked(), nous ne créons pas - de manipulateurs associé à \c getFindText(). + La variable \c findText a un accesseur publique associé: \c getFindText(). + Étant donné que nous ne modifions \c findText directement que dans le + constructeur et la méthode \c findClicked(), nous ne créons pas + de manipulateurs associé à \c getFindText(). Puisque \c getFindText() est publique, les classes instanciant et - utilisant \c FindDialog peuvent toujours accéder à la chaîne de - caractères que l'utilisateur a entré et accepté. + utilisant \c FindDialog peuvent toujours accéder à la chaîne de + caractères que l'utilisateur a entré et accepté. \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Pour utiliser \c FindDialog depuis la classe \c AddressBook, nous incluons \c finddialog.h dans le fichier \c addressbook.h. \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header - Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un - QPushButton et un slot correspondant. De la même façon, pour la - fonctionnalité \gui Find, nous avons \c findButton et \c findContact(). + Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un + QPushButton et un slot correspondant. De la même façon, pour la + fonctionnalité \gui Find, nous avons \c findButton et \c findContact(). - Le \c findButton est déclaré comme une variable privée et la - méthode \c findContact() est déclarée comme un slot public. + Le \c findButton est déclaré comme une variable privée et la + méthode \c findContact() est déclarée comme un slot public. \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration \dots \snippet tutorials/addressbook/part5/addressbook.h findButton declaration - Finalement, nous déclarons la variable privée \c dialog que nous allons - utiliser pour accéder à une instance de \c FindDialog. + Finalement, nous déclarons la variable privée \c dialog que nous allons + utiliser pour accéder à une instance de \c FindDialog. \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration - Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser - plus qu'une fois. Utiliser une variable privée nous permet d'y référer - à plus d'un endroit dans la classe. + Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser + plus qu'une fois. Utiliser une variable privée nous permet d'y référer + à plus d'un endroit dans la classe. - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook - Dans le constructeur de \c AddressBook, nous instancions nos objets privés, + Dans le constructeur de \c AddressBook, nous instancions nos objets privés, \c findbutton et \c findDialog: \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton @@ -814,25 +814,25 @@ \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de - \c{findButton} à \c findContact(). + \c{findButton} à \c findContact(). \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find - Maintenant, tout ce qui manque est le code de notre méthode \c findContact(): + Maintenant, tout ce qui manque est le code de notre méthode \c findContact(): \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function - Nous commençons par afficher l'instance de \c FindDialog, \c dialog. - L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque - l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est - masquée et le code de retour devient QDialog::Accepted. Ce code de retour + Nous commençons par afficher l'instance de \c FindDialog, \c dialog. + L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque + l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est + masquée et le code de retour devient QDialog::Accepted. Ce code de retour vient remplir la condition du premier if. Ensuite, nous extrayons le texte que nous utiliserons pour la recherche, - il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText() + il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText() de \c FindDialog. Si le contact existe dans le carnet d'adresse, nous l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour - indiquer que la recherche à échouée. + indiquer que la recherche à échouée. \image addressbook-tutorial-part5-notfound.png */ @@ -845,49 +845,49 @@ \example tutorials/addressbook-fr/part6 \title Carnet d'Adresses 6 - Sauvegarde et chargement - Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que - l'on utilise pour écrire les procédures de sauvegarde et chargement pour + Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que + l'on utilise pour écrire les procédures de sauvegarde et chargement pour l'application carnet d'adresses. \image addressbook-tutorial-part6-screenshot.png Bien que la navigation et la recherche de contacts soient des - fonctionnalités importantes, notre carnet d'adresses ne sera pleinement + fonctionnalités importantes, notre carnet d'adresses ne sera pleinement utilisable qu'une fois que l'on pourra sauvegarder les contacts existants - et les charger à nouveau par la suite. - Qt fournit de nombreuses classes pour gérer les \l{Input/Output and - Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une - combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream. + et les charger à nouveau par la suite. + Qt fournit de nombreuses classes pour gérer les \l{Input/Output and + Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une + combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream. - Un objet QFile représente un fichier sur le disque qui peut être lu, et - dans lequel on peut écrire. QFile est une classe fille de la classe plus - générique QIODevice, qui peut représenter différents types de - périphériques. + Un objet QFile représente un fichier sur le disque qui peut être lu, et + dans lequel on peut écrire. QFile est une classe fille de la classe plus + générique QIODevice, qui peut représenter différents types de + périphériques. - Un objet QDataStream est utilisé pour sérialiser des données binaires - dans le but de les passer à un QIODevice pour les récupérer dans le - futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le - flux, avec le périphérique approprié en paramètre, et d'y lire ou - écrire. + Un objet QDataStream est utilisé pour sérialiser des données binaires + dans le but de les passer à un QIODevice pour les récupérer dans le + futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le + flux, avec le périphérique approprié en paramètre, et d'y lire ou + écrire. - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook - On déclare deux slots publics, \c saveToFile() et \c loadFromFile(), + On déclare deux slots publics, \c saveToFile() et \c loadFromFile(), ainsi que deux objets QPushButton, \c loadButton et \c saveButton. \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration \dots \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook Dans notre constructeur, on instancie \c loadButton et \c saveButton. - Idéalement, l'interface serait plus conviviale avec des boutons + Idéalement, l'interface serait plus conviviale avec des boutons affichant "Load contacts from a file" et "Save contacts to a file". Mais compte tenu de la dimension des autres boutons, on initialise les labels - des boutons à \gui{Load...} et \gui{Save...}. Heureusement, Qt offre une - façon simple d'ajouter des info-bulles avec - \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon + des boutons à \gui{Load...} et \gui{Save...}. Heureusement, Qt offre une + façon simple d'ajouter des info-bulles avec + \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon suivante pour nos boutons: \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1 @@ -895,85 +895,85 @@ \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2 Bien qu'on ne cite pas le code correspondant ici, nous ajoutons ces deux boutons au - layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et + layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et nous connectons leurs signaux - \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs. + \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs. - Pour la sauvegarde, on commence par récupérer le nom de fichier + Pour la sauvegarde, on commence par récupérer le nom de fichier \c fileName, en utilisant QFileDialog::getSaveFileName(). C'est une - méthode pratique fournie par QFileDialog, qui ouvre une boîte de - dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou + méthode pratique fournie par QFileDialog, qui ouvre une boîte de + dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou de choisir un fichier \c{.abk} existant. Les fichiers \c{.abk} - correspondent à l'extension choisie pour la sauvegarde des contacts de + correspondent à l'extension choisie pour la sauvegarde des contacts de notre carnet d'adresses. \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1 - La boîte de dialogue affichée est visible sur la capture d'écran ci- + La boîte de dialogue affichée est visible sur la capture d'écran ci- dessous. \image addressbook-tutorial-part6-save.png - Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir - de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de + Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir + de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de QIODevice. - Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au - mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe + Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au + mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe l'utilisateur avec une QMessageBox. \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2 Dans le cas contraire, on instancie un objet QDataStream, \c out, afin - d'écrire dans le fichier ouvert. QDataStream nécessite que la même - version de flux soit utilisée pour la lecture et l'écriture. On s'assure - que c'est le cas en spécifiant explicitement d'utiliser la + d'écrire dans le fichier ouvert. QDataStream nécessite que la même + version de flux soit utilisée pour la lecture et l'écriture. On s'assure + que c'est le cas en spécifiant explicitement d'utiliser la \l{QDataStream::Qt_4_5}{version introduite avec Qt 4.5} avant de - sérialiser les données vers le fichier \c file. + sérialiser les données vers le fichier \c file. \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3 - Pour le chargement, on récupère également \c fileName en utilisant - QFileDialog::getOpenFileName(). Cette méthode est l'homologue de - QFileDialog::getSaveFileName() et affiche également une boîte de - dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou + Pour le chargement, on récupère également \c fileName en utilisant + QFileDialog::getOpenFileName(). Cette méthode est l'homologue de + QFileDialog::getSaveFileName() et affiche également une boîte de + dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou de selectionner un fichier \c{.abk} existant, afin de le charger dans le carnet d'adresses. \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1 - Sous Windows, par exemple, cette méthode affiche une boîte de dialogue - native pour la sélection de fichier, comme illustré sur la capture - d'écran suivante: + Sous Windows, par exemple, cette méthode affiche une boîte de dialogue + native pour la sélection de fichier, comme illustré sur la capture + d'écran suivante: \image addressbook-tutorial-part6-load.png Si \c fileName n'est pas vide, on utilise une fois de plus un objet QFile, \c file, et on tente de l'ouvrir en lecture, avec le mode - \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre - implémentation de \c saveToFile(), si cette tentative s'avère + \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre + implémentation de \c saveToFile(), si cette tentative s'avère infructueuse, on en informe l'utilisateur par le biais d'une QMessageBox. \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2 Dans le cas contraire, on instancie un objet QDataStream, \c in, en - spécifiant la version à utiliser comme précédemment, et on lit les - informations sérialisées vers la structure de données \c contacts. Notez + spécifiant la version à utiliser comme précédemment, et on lit les + informations sérialisées vers la structure de données \c contacts. Notez qu'on purge \c contacts avant d'y mettre les informations lues afin de - simplifier le processus de lecture de fichier. Une façon plus avancée de - procéder serait de lire les contacts dans un objet QMap temporaire, et + simplifier le processus de lecture de fichier. Une façon plus avancée de + procéder serait de lire les contacts dans un objet QMap temporaire, et de copier uniquement les contacts n'existant pas encore dans \c contacts. \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3 Pour afficher les contacts lus depuis le fichier, on doit d'abord - valider les données obtenues afin de s'assurer que le fichier lu - contient effectivement des entrées de carnet d'adresses. Si c'est le + valider les données obtenues afin de s'assurer que le fichier lu + contient effectivement des entrées de carnet d'adresses. Si c'est le cas, on affiche le premier contact; sinon on informe l'utilisateur du - problème par une QMessageBox. Enfin, on met à jour l'interface afin - d'activer et de désactiver les boutons de façon appropriée. + problème par une QMessageBox. Enfin, on met à jour l'interface afin + d'activer et de désactiver les boutons de façon appropriée. */ /*! @@ -981,86 +981,86 @@ \previouspage {tutorials/addressbook-fr/part6}{Chapitre 6} \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} \example tutorials/addressbook-fr/part7 - \title Carnet d'adresse 7 - Fonctionnalités avancées + \title Carnet d'adresse 7 - Fonctionnalités avancées - Ce chapitre couvre quelques fonctionnalités additionnelles qui + Ce chapitre couvre quelques fonctionnalités additionnelles qui feront de notre carnet d'adresses une application plus pratique pour une utilisation quotidienne. \image addressbook-tutorial-part7-screenshot.png Bien que notre application carnet d'adresses soit utile en tant que telle, - il serait pratique de pouvoir échanger les contacts avec d'autres applications. - Le format vCard est un un format de fichier populaire pour échanger - ce type de données. - Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre + il serait pratique de pouvoir échanger les contacts avec d'autres applications. + Le format vCard est un un format de fichier populaire pour échanger + ce type de données. + Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre d'exporter des contacts dans des fichiers vCard \c{.vcf}. - \section1 Définition de la classe AddressBook + \section1 Définition de la classe AddressBook Nous ajoutons un objet QPushButton, \c exportButton, et un slot - public correspondant, \c exportAsVCard(), à notre classe \c AddressBook + public correspondant, \c exportAsVCard(), à notre classe \c AddressBook dans le fichier \c addressbook.h. \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration \dots \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration - \section1 Implémentation de la classe AddressBook + \section1 Implémentation de la classe AddressBook Dans le constructeur de \c AddressBook, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de \c{exportButton} au slot \c exportAsVCard(). - Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable + Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable du groupe de boutons sur la droite. - Dans la méthode \c exportAsVCard(), nous commençons par extraire le - nom du contact dans \n name. Nous déclarons \c firstname, \c lastName et + Dans la méthode \c exportAsVCard(), nous commençons par extraire le + nom du contact dans \n name. Nous déclarons \c firstname, \c lastName et \c nameList. Ensuite, nous cherchons la position du premier espace blanc de \c name. - Si il y a un espace, nous séparons le nom du contact en \c firstName et - \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_"). + Si il y a un espace, nous séparons le nom du contact en \c firstName et + \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_"). Si il n'y a pas d'espace, nous supposons que le contact ne comprend que - le prénom. + le prénom. \snippet tutorials/addressbook/part7/addressbook.cpp export function part1 - Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue - pour donner la possibilité à l'utilisateur de choisir un emplacement pour - le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile - pour y écrire. + Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue + pour donner la possibilité à l'utilisateur de choisir un emplacement pour + le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile + pour y écrire. Nous essayons d'ouvrir le fichier en mode \l{QIODevice::}{WriteOnly}. Si - cela échoue, nous affichons un QMessageBox pour informer l'utilisateur - à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le - fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que - QDataStream, la classe QTextStream fournit les fonctionnalités pour - lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf} - généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte. + cela échoue, nous affichons un QMessageBox pour informer l'utilisateur + à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le + fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que + QDataStream, la classe QTextStream fournit les fonctionnalités pour + lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf} + généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte. \snippet tutorials/addressbook/part7/addressbook.cpp export function part2 - Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD}, + Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD}, suivit par \c{VERSION:2.1}. - Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise - \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact - à un nom de famille défini ou non. Si oui, nous utilions les détails de - \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu + Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise + \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact + à un nom de famille défini ou non. Si oui, nous utilions les détails de + \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu de \c firstName. \snippet tutorials/addressbook/part7/addressbook.cpp export function part3 - Nous continuons en écrivant l'adresse du contact. Les points-virgules - dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont - remplacés par des points-virgules, et les vigules sont remplacées par des espaces. - Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse + Nous continuons en écrivant l'adresse du contact. Les points-virgules + dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont + remplacés par des points-virgules, et les vigules sont remplacées par des espaces. + Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse et la balise \c{END:VCARD}. \snippet tutorials/addressbook/part7/addressbook.cpp export function part4 - À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur - que la vCard a été exportée avec succès. + À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur + que la vCard a été exportée avec succès. - \e{vCard est une marque déposée de \l{http://www.imc.org} + \e{vCard est une marque déposée de \l{http://www.imc.org} {Internet Mail Consortium}}. */ diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index dae5ca1..4f1ae5d 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -8,6 +8,10 @@ project = Qt description = Qt Reference Documentation url = http://qt.nokia.com/doc/4.7 +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US + edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ @@ -90,12 +94,13 @@ excludedirs = $QT_SOURCE_TREE/src/3rdparty/clucene \ $QT_SOURCE_TREE/src/3rdparty/webkit/WebCore \ $QT_SOURCE_TREE/src/3rdparty/wintab \ $QT_SOURCE_TREE/src/3rdparty/zlib \ - $QT_SOURCE_TREE/doc/src/snippets \ $QT_SOURCE_TREE/src/3rdparty/phonon/gstreamer \ $QT_SOURCE_TREE/src/3rdparty/phonon/ds9 \ $QT_SOURCE_TREE/src/3rdparty/phonon/qt7 \ $QT_SOURCE_TREE/src/3rdparty/phonon/mmf \ - $QT_SOURCE_TREE/src/3rdparty/phonon/waveout + $QT_SOURCE_TREE/src/3rdparty/phonon/waveout \ + $QT_SOURCE_TREE/doc/src/snippets \ + $QT_SOURCE_TREE/doc/src/zh_CN sources.fileextensions = "*.cpp *.qdoc *.mm" examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index 4dfabcf..1039c18 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -10,6 +10,10 @@ version = %VERSION% description = Qt Reference Documentation url = http://qt.nokia.com/doc/4.7 +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US + edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript \ QtScriptTools QtSql QtSvg QtWebKit QtXml QtXmlPatterns \ Qt3Support QtHelp QtDesigner QtAssistant QAxContainer Phonon \ @@ -91,12 +95,13 @@ excludedirs = $QTDIR/src/3rdparty/clucene \ $QTDIR/src/3rdparty/webkit/WebCore \ $QTDIR/src/3rdparty/wintab \ $QTDIR/src/3rdparty/zlib \ - $QTDIR/doc/src/snippets \ $QTDIR/src/3rdparty/phonon/gstreamer \ $QTDIR/src/3rdparty/phonon/ds9 \ $QTDIR/src/3rdparty/phonon/qt7 \ $QTDIR/src/3rdparty/phonon/mmf \ - $QTDIR/src/3rdparty/phonon/waveout + $QTDIR/src/3rdparty/phonon/waveout \ + $QTDIR/doc/src/snippets \ + $QTDIR/doc/src/zh_CN sources.fileextensions = "*.cpp *.qdoc *.mm" examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" -- cgit v0.12 From 4027c52d9fb6ea1bca13e1f3a2bc5ac5032387e0 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 8 Feb 2010 20:22:44 +0100 Subject: Doc/qdoc: Use Chinese titles; canonicalize titles with non-ASCII chars. The documentation root in the qdocconf file now refers to the Chinese title for the Tutorials page. Modified qdoc's function to canonicalize titles so that it preserves characters that outside the range of ASCII letters and numbers. Reviewed-by: Trust Me --- doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc | 2 +- doc/src/zh_CN/getting-started/tutorials.qdoc | 7 ++----- doc/src/zh_CN/tutorials/addressbook.qdoc | 4 ++-- doc/src/zh_CN/tutorials/widgets-tutorial.qdoc | 4 ++-- tools/qdoc3/doc.cpp | 3 ++- tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf | 5 ++--- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc index 5f95dde..1c2f56b 100644 --- a/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc +++ b/doc/src/zh_CN/getting-started/how-to-learn-qt.qdoc @@ -43,7 +43,7 @@ \page how-to-learn-qt.html \title 如何学习 Qt \brief Links to guides and resources for learning Qt. - \nextpage Tutorials + \nextpage 教程 \section1 Getting Started diff --git a/doc/src/zh_CN/getting-started/tutorials.qdoc b/doc/src/zh_CN/getting-started/tutorials.qdoc index 56d147e..dc371d8 100644 --- a/doc/src/zh_CN/getting-started/tutorials.qdoc +++ b/doc/src/zh_CN/getting-started/tutorials.qdoc @@ -41,15 +41,12 @@ /*! \page tutorials.html - \title Tutorials + \title 教程 - \contentspage How to Learn Qt - \nextpage Qt Examples + \contentspage 如何学习 Qt \brief Tutorials, guides and overviews to help you learn Qt. - \nextpage Qt Examples - A collection of tutorials and "walkthrough" guides are provided with Qt to help new users get started with Qt development. These documents cover a range of topics, from basic use of widgets to step-by-step tutorials that diff --git a/doc/src/zh_CN/tutorials/addressbook.qdoc b/doc/src/zh_CN/tutorials/addressbook.qdoc index 5bd0d35..72349af 100644 --- a/doc/src/zh_CN/tutorials/addressbook.qdoc +++ b/doc/src/zh_CN/tutorials/addressbook.qdoc @@ -43,7 +43,7 @@ \page tutorials-addressbook.html \startpage {index.html}{Qt Reference Documentation} - \contentspage Tutorials + \contentspage 教程 \nextpage {tutorials/addressbook/part1}{第一章} \title 地å€ç°¿æ•™ç¨‹ @@ -176,7 +176,7 @@ /*! \page tutorials-addressbook-part2.html - \previouspage 地å€ç°¿ 1 — è®¾è®¡ç”¨æˆ·æŽ¥å£ + \previouspage 地å€ç°¿ 1 — è®¾è®¡ç”¨æˆ·ç•Œé¢ \contentspage {地å€ç°¿æ•™ç¨‹}{目录} \nextpage {tutorials/addressbook/part3}{第三章} \example tutorials/addressbook/part2 diff --git a/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc index 0e90210..90ef4f3 100644 --- a/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc +++ b/doc/src/zh_CN/tutorials/widgets-tutorial.qdoc @@ -46,7 +46,7 @@ they are used to build GUI applications. \startpage {index.html}{Qt Reference Documentation} - \contentspage Tutorials + \contentspage 教程 \nextpage {Widgets 教程 — 创建窗å£} @@ -197,7 +197,7 @@ \contentspage {Widgets 教程}{目录} \previouspage {Widgets 教程 — 使用布局} \example tutorials/widgets/nestedlayouts - \title Widgets 教程 - Nested Layouts + \title Widgets 教程 — Nested Layouts 由于 widget å¯åŒ…å«å…¶ä»– widget,布局å¯ç”¨æ¥æä¾›æŒ‰ä¸åŒå±‚次分组的 widget。这里,我们è¦åœ¨æ˜¾ç¤ºæŸ¥è¯¢ç»“果的表视图上方ã€çª—å£é¡¶éƒ¨çš„行编辑框æ—,显示一个标签。 diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index 17a6efd..ad4cdde 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -3056,7 +3056,8 @@ QString Doc::canonicalTitle(const QString &title) slurping = true; } else { - // !alnum && slurping -> nothin + result += title[i]; + lastAlnum = result.size(); } } result.truncate(lastAlnum); diff --git a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf index 29560a2..18b72a1 100644 --- a/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf +++ b/tools/qdoc3/test/qt-build-docs_zh_CN.qdocconf @@ -27,9 +27,8 @@ qhp.projects = Qt qhp.Qt.file = qt.qhp qhp.Qt.namespace = com.trolltech.qt.470 qhp.Qt.virtualFolder = qdoc -qhp.Qt.title = Tutorials -qhp.Qt.indexTitle = Tutorials -qhp.Qt.indexRoot = tutorials.html +qhp.Qt.title = 教程 +qhp.Qt.indexTitle = 教程 qhp.Qt.selectors = fake:example qhp.Qt.filterAttributes = qt 4.7.0 qtrefdoc zh_CN -- cgit v0.12 From bced83df38693948bb815cbfad1a8dc1a9c66baa Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Tue, 9 Feb 2010 15:56:36 +1000 Subject: Added errors reporting to gst playback backend. --- .../gstreamer/mediaplayer/qgstreamerplayercontrol.cpp | 2 ++ .../gstreamer/mediaplayer/qgstreamerplayersession.cpp | 13 +++++++++++++ .../gstreamer/mediaplayer/qgstreamerplayersession.h | 1 + 3 files changed, 16 insertions(+) diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp index f008e81..d417266 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp @@ -86,6 +86,8 @@ QGstreamerPlayerControl::QGstreamerPlayerControl(QGstreamerPlayerSession *sessio this, SIGNAL(videoAvailableChanged(bool))); connect(m_session, SIGNAL(seekableChanged(bool)), this, SIGNAL(seekableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), + this, SIGNAL(error(int,QString))); } QGstreamerPlayerControl::~QGstreamerPlayerControl() diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp index 016909a..355df2f 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -266,6 +266,8 @@ void QGstreamerPlayerSession::play() emit stateChanged(m_state); emit mediaStatusChanged(m_mediaStatus); + + emit error(int(QMediaPlayer::ResourceError), tr("Unable to play %1").arg(m_url.path())); } } } @@ -525,7 +527,18 @@ void QGstreamerPlayerSession::busMessage(const QGstreamerMessage &message) case GST_MESSAGE_TAG: case GST_MESSAGE_STREAM_STATUS: case GST_MESSAGE_UNKNOWN: + break; case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + gst_message_parse_error (gm, &err, &debug); + emit error(int(QMediaPlayer::ResourceError), QString::fromUtf8(err->message)); + qWarning() << "Error:" << QString::fromUtf8(err->message); + g_error_free (err); + g_free (debug); + } + break; case GST_MESSAGE_WARNING: case GST_MESSAGE_INFO: break; diff --git a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h index d33ffd2..e277ba9 100644 --- a/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h +++ b/src/plugins/mediaservices/gstreamer/mediaplayer/qgstreamerplayersession.h @@ -129,6 +129,7 @@ signals: void tagsChanged(); void streamsChanged(); void seekableChanged(bool); + void error(int error, const QString &errorString); private slots: void busMessage(const QGstreamerMessage &message); -- cgit v0.12 From d92f8dd19a2f52771063faf0b926faa22149a206 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 9 Feb 2010 13:05:15 +0100 Subject: Use glDrawElements and triangle strips to draw glyphs in GL engine We keep around a engine-global index array which we only grow when we need to. This should hopefully speed up text drawing on some devices. --- src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h | 14 +++++++++++++ .../gl2paintengineex/qpaintengineex_opengl2.cpp | 23 ++++++++++++++++++---- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 1 + 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h index ae73040..d1e7615 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h @@ -118,6 +118,20 @@ public: << QGLPoint(left, top); } + inline void addQuad(const QRectF &rect) + { + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QGLPoint(left, top) + << QGLPoint(right, top) + << QGLPoint(left, bottom) + << QGLPoint(right, bottom); + + } + void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); void clear(); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 18d67e9..685f0c1 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1372,13 +1372,28 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin; int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin; - vertexCoordinates->addRect(QRectF(x, y, c.w, c.h)); - textureCoordinates->addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); + textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); } staticTextItem->userDataNeedsUpdate = false; } + if (elementIndices.size() < staticTextItem->numGlyphs*6) { + Q_ASSERT(elementIndices.size() % 6 == 0); + int j = elementIndices.size() / 6 * 4; + while (j < staticTextItem->numGlyphs*4) { + elementIndices.append(j + 0); + elementIndices.append(j + 0); + elementIndices.append(j + 1); + elementIndices.append(j + 2); + elementIndices.append(j + 3); + elementIndices.append(j + 3); + + j += 4; + } + } + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data()); setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data()); @@ -1454,7 +1469,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); - glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); + glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2); @@ -1485,7 +1500,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); - glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs); + glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); if (includeMatrixInCache) s->matrix = old; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 70a1621..f757bc4 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -267,6 +267,7 @@ public: QGL2PEXVertexArray vertexCoordinateArray; QGL2PEXVertexArray textureCoordinateArray; + QVector elementIndices; QDataBuffer opacityArray; GLfloat staticVertexCoordinateArray[8]; GLfloat staticTextureCoordinateArray[8]; -- cgit v0.12 From 004b09ffd423cd3100e346825dd7d730fc86d366 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 9 Feb 2010 15:10:00 +0100 Subject: Make the GL glyph cache a POT texture This is a significant speed-up on some architectures and drivers. --- src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 6cb76ee..53c627f 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -70,8 +70,12 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache() } } -void QGLTextureGlyphCache::createTextureData(int width, int height) +void QGLTextureGlyphCache::createTextureData(int width, int unalteredHeight) { + extern int qt_next_power_of_two(int v); + // Set height to lowest POT number which is higher than or equal to height + int height = qt_next_power_of_two(unalteredHeight); + glGenTextures(1, &m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); -- cgit v0.12 From c509c5e5de3557c31adc78744e212b8ed37d5e1f Mon Sep 17 00:00:00 2001 From: David Boddie Date: Tue, 9 Feb 2010 19:43:24 +0100 Subject: Doc: Tidied up the class layout and removed an unnecessary image. Reviewed-by: Trust Me --- src/gui/widgets/qdialogbuttonbox.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/gui/widgets/qdialogbuttonbox.cpp b/src/gui/widgets/qdialogbuttonbox.cpp index 48d7022..d848125 100644 --- a/src/gui/widgets/qdialogbuttonbox.cpp +++ b/src/gui/widgets/qdialogbuttonbox.cpp @@ -103,7 +103,7 @@ QT_BEGIN_NAMESPACE You can mix and match normal buttons and standard buttons. Currently the buttons are laid out in the following way if the button box is horizontal: - \table 100% + \table \row \o \inlineimage buttonbox-gnomelayout-horizontal.png GnomeLayout Horizontal \o Button box laid out in horizontal GnomeLayout \row \o \inlineimage buttonbox-kdelayout-horizontal.png KdeLayout Horizontal @@ -116,25 +116,23 @@ QT_BEGIN_NAMESPACE The buttons are laid out the following way if the button box is vertical: - \table 100% + \table + \row \o GnomeLayout + \o KdeLayout + \o MacLayout + \o WinLayout \row \o \inlineimage buttonbox-gnomelayout-vertical.png GnomeLayout Vertical - \o Button box laid out in vertical GnomeLayout - \row \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical - \o Button box laid out in vertical KdeLayout - \row \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical - \o Button box laid out in vertical MacLayout - \row \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical - \o Button box laid out in vertical WinLayout + \o \inlineimage buttonbox-kdelayout-vertical.png KdeLayout Vertical + \o \inlineimage buttonbox-maclayout-vertical.png MacLayout Vertical + \o \inlineimage buttonbox-winlayout-vertical.png WinLayout Vertical \endtable Additionally, button boxes that contain only buttons with ActionRole or - HelpRole can be considered modeless and have an alternate look on the mac: + HelpRole can be considered modeless and have an alternate look on Mac OS X: - \table 100% - \row \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout - \o modeless horizontal MacLayout - \row \o \inlineimage buttonbox-mac-modeless-vertical.png Screenshot of modeless vertical MacLayout - \o modeless vertical MacLayout + \table + \row \o modeless horizontal MacLayout + \o \inlineimage buttonbox-mac-modeless-horizontal.png Screenshot of modeless horizontal MacLayout \endtable When a button is clicked in the button box, the clicked() signal is emitted -- cgit v0.12 From 89859e4dc667989bf41ad340df9b553457ae46db Mon Sep 17 00:00:00 2001 From: David Boddie Date: Tue, 9 Feb 2010 19:44:06 +0100 Subject: qdoc: Made a temporary fix for comment highlighting. Reviewed-by: Trust Me --- tools/qdoc3/cppcodemarker.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 2df7133..571fd75 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -881,8 +881,7 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, static QRegExp globalX("[\n{()=] *([a-zA-Z_][a-zA-Z_0-9]*)[ \n]*\\("); static QRegExp multiLineComment("/(?:( )?\\*(?:[^*]+|\\*(?! /))*\\*\\1/)"); multiLineComment.setMinimal(true); - static QRegExp singleLineCommentLine("(?:^|\n)(?:[^&]|&(?!quot;)|"(?:[^&\\\\]|&(?!quot;)|\\\\"|\\\\(?!"))*")*//(?!!)[^!\n]*"); - static QRegExp singleLineComment("//(?!!)[^!\n]*"); + static QRegExp singleLineComment("[^:]//(?!!)[^!\\n]*"); static QRegExp preprocessor("(?:^|\n)(#[ \t]*(?:include|if|elif|endif|error|pragma|define" "|warning)(?:(?:\\\\\n|\\n#)[^\n]*)*)"); static QRegExp literals(""(?:[^\\\\&]|\\\\[^\n]|&(?!quot;))*"" @@ -1057,8 +1056,7 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, int mlpos; int slpos; int len; - int sllpos = singleLineCommentLine.indexIn(result, pos); - slpos = sllpos == -1 ? -1 : singleLineComment.indexIn(result, sllpos); + slpos = singleLineComment.indexIn(result, pos); mlpos = multiLineComment.indexIn(result, pos); if (slpos == -1 && mlpos == -1) @@ -1069,13 +1067,13 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, len = multiLineComment.matchedLength(); } else if (mlpos == -1) { - pos = slpos; - len = singleLineComment.matchedLength(); + pos = slpos + 1; + len = singleLineComment.matchedLength() - 1; } else { if (slpos < mlpos) { - pos = slpos; - len = singleLineComment.matchedLength(); + pos = slpos + 1; + len = singleLineComment.matchedLength() - 1; } else { pos = mlpos; -- cgit v0.12 From 46c9f5174d208fd98903a6f95e4e3bc8af6df9e4 Mon Sep 17 00:00:00 2001 From: Kurt Korbatits Date: Wed, 10 Feb 2010 07:45:50 +1000 Subject: maemo define spelling incorrect. --- src/multimedia/qml/qsoundeffect_pulse_p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.cpp b/src/multimedia/qml/qsoundeffect_pulse_p.cpp index fa2119d..c16e999 100644 --- a/src/multimedia/qml/qsoundeffect_pulse_p.cpp +++ b/src/multimedia/qml/qsoundeffect_pulse_p.cpp @@ -181,7 +181,7 @@ private: m_prepared = false; } -#if(QWS_MAEMO_5) +#if(Q_WS_MAEMO_5) static void context_state_callback(pa_context *c, void *userdata) { PulseDaemon *self = reinterpret_cast(userdata); -- cgit v0.12 From e6646c68cf273934b74acd40492d63b447cf800c Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Wed, 10 Feb 2010 11:40:38 +1000 Subject: Added missing qgstxvimagebuffer.h/cpp to gstreamer.pro --- src/plugins/mediaservices/gstreamer/gstreamer.pro | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/gstreamer/gstreamer.pro b/src/plugins/mediaservices/gstreamer/gstreamer.pro index e4e8d5a..5a16f03 100644 --- a/src/plugins/mediaservices/gstreamer/gstreamer.pro +++ b/src/plugins/mediaservices/gstreamer/gstreamer.pro @@ -33,7 +33,9 @@ HEADERS += \ qgstreamervideorenderer.h \ qgstvideobuffer.h \ qvideosurfacegstsink.h \ - qx11videosurface.h + qx11videosurface.h \ + qgstxvimagebuffer.h + SOURCES += \ qgstreamermessage.cpp \ @@ -48,7 +50,8 @@ SOURCES += \ qgstreamervideorenderer.cpp \ qgstvideobuffer.cpp \ qvideosurfacegstsink.cpp \ - qx11videosurface.cpp + qx11videosurface.cpp \ + qgstxvimagebuffer.cpp include(mediaplayer/mediaplayer.pri) -- cgit v0.12 From aec0628295cda95f2169e3007368797ba6585ee3 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 10 Feb 2010 15:46:53 +1000 Subject: Fix crash on exit in player example on Windows. Explicitly clear the QPointer to QVideoWidget on destruction, otherwise the destruction of the QVideoWidget will seeminly attempt to clear an invalidated QPointer. --- src/multimedia/playback/qmediaplayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index 0853597..d3dfbb2 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -308,6 +308,8 @@ QMediaPlayer::~QMediaPlayer() Q_D(QMediaPlayer); d->provider->releaseService(d->service); + d->videoWidget = 0; + d->videoItem = 0; } QMediaContent QMediaPlayer::media() const -- cgit v0.12 From eab600d2d58a2f638636281ec5db65b4a07b890f Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 10 Feb 2010 16:51:43 +1000 Subject: Emit an error if given a QIODevice that is unusable. Where unusable is not readable or sequential. --- .../mediaplayer/directshowplayercontrol.cpp | 65 +++++++++++++--------- .../mediaplayer/directshowplayercontrol.h | 9 ++- .../mediaplayer/directshowplayerservice.cpp | 34 +++++++---- .../mediaplayer/directshowplayerservice.h | 1 + 4 files changed, 69 insertions(+), 40 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp index a4308d7..587f4b1 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp @@ -82,6 +82,7 @@ DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *servic , m_updateProperties(0) , m_state(QMediaPlayer::StoppedState) , m_status(QMediaPlayer::UnknownMediaStatus) + , m_error(QMediaPlayer::NoError) , m_streamTypes(0) , m_muteVolume(-1) , m_duration(0) @@ -240,12 +241,7 @@ void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *st m_service->load(media, stream); - emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream); - emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); - emit durationChanged(m_duration); - emit seekableChanged(m_seekable); - emit mediaStatusChanged(m_status); - emit stateChanged(m_state); + emitPropertyChanges(); } void DirectShowPlayerControl::play() @@ -269,33 +265,41 @@ void DirectShowPlayerControl::stop() void DirectShowPlayerControl::customEvent(QEvent *event) { if (event->type() == QEvent::Type(PropertiesChanged)) { - int properties = m_updateProperties; - m_updateProperties = 0; + emitPropertyChanges(); - if (properties & PlaybackRateProperty) - emit playbackRateChanged(m_playbackRate); + event->accept(); + } else { + QMediaPlayerControl::customEvent(event); + } +} - if (properties & StreamTypesProperty) { - emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream); - emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); - } +void DirectShowPlayerControl::emitPropertyChanges() +{ + int properties = m_updateProperties; + m_updateProperties = 0; - if (properties & DurationProperty) - emit durationChanged(m_duration); + if ((properties & ErrorProperty) && m_error != QMediaPlayer::NoError) + emit error(m_error, m_errorString); - if (properties & SeekableProperty) - emit seekableChanged(m_seekable); + if (properties & PlaybackRateProperty) + emit playbackRateChanged(m_playbackRate); - if (properties & StatusProperty) - emit mediaStatusChanged(m_status); + if (properties & StreamTypesProperty) { + emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream); + emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); + } - if (properties & StateProperty) - emit stateChanged(m_state); + if (properties & DurationProperty) + emit durationChanged(m_duration); - event->accept(); - } else { - QMediaPlayerControl::customEvent(event); - } + if (properties & SeekableProperty) + emit seekableChanged(m_seekable); + + if (properties & StatusProperty) + emit mediaStatusChanged(m_status); + + if (properties & StateProperty) + emit stateChanged(m_state); } void DirectShowPlayerControl::scheduleUpdate(int properties) @@ -366,4 +370,13 @@ void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter) m_audio = com_cast(filter); } +void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString) +{ + m_error = error; + m_errorString = errorString; + + if (m_error != QMediaPlayer::NoError) + scheduleUpdate(ErrorProperty); +} + QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h index af2cd3f..6706bab 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h @@ -101,8 +101,7 @@ public: void updateMediaInfo(qint64 duration, int streamTypes, bool seekable); void updatePlaybackRate(qreal rate); void updateAudioOutput(IBaseFilter *filter); - - using QMediaPlayerControl::error; + void updateError(QMediaPlayer::Error error, const QString &errorString); protected: void customEvent(QEvent *event); @@ -115,7 +114,8 @@ private: StreamTypesProperty = 0x04, DurationProperty = 0x08, PlaybackRateProperty = 0x10, - SeekableProperty = 0x20 + SeekableProperty = 0x20, + ErrorProperty = 0x40 }; enum Event @@ -124,6 +124,7 @@ private: }; void scheduleUpdate(int properties); + void emitPropertyChanges(); DirectShowPlayerService *m_service; IBasicAudio *m_audio; @@ -131,12 +132,14 @@ private: int m_updateProperties; QMediaPlayer::State m_state; QMediaPlayer::MediaStatus m_status; + QMediaPlayer::Error m_error; int m_streamTypes; int m_muteVolume; qint64 m_duration; qreal m_playbackRate; bool m_seekable; QMediaContent m_media; + QString m_errorString; }; diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index 3c0a43a..e9bce71 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -182,6 +182,8 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_resources = media.resources(); m_stream = stream; + m_error = QMediaPlayer::NoError; + m_errorString = QString(); m_duration = 0; m_streamTypes = 0; m_executedTasks = 0; @@ -195,6 +197,10 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_graphStatus = NoMedia; m_url.clear(); + } else if (stream && (!stream->isReadable() || stream->isSequential())) { + m_pendingTasks = 0; + m_graphStatus = InvalidMedia; + m_error = QMediaPlayer::ResourceError; } else { m_graphStatus = Loading; @@ -208,6 +214,7 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream ::SetEvent(m_taskHandle); } + m_playerControl->updateError(m_error, m_errorString); m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); m_playerControl->updateState(QMediaPlayer::StoppedState); updateStatus(); @@ -273,13 +280,16 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) switch (hr) { case VFW_E_UNKNOWN_FILE_TYPE: m_error = QMediaPlayer::FormatError; + m_errorString = QString(); break; case E_OUTOFMEMORY: case VFW_E_CANNOT_LOAD_SOURCE_FILTER: case VFW_E_NOT_FOUND: m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); default: m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", hr); break; } @@ -312,6 +322,7 @@ void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker) m_graphStatus = InvalidMedia; m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); } @@ -415,14 +426,17 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker) if (!m_audioOutput && !m_videoOutput) { m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); } else { switch (renderHr) { case VFW_E_UNSUPPORTED_AUDIO: case VFW_E_UNSUPPORTED_VIDEO: case VFW_E_UNSUPPORTED_STREAM: m_error = QMediaPlayer::FormatError; + m_errorString = QString(); default: m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); qWarning("DirectShowPlayerService::doRender: Unresolved error code %x", renderHr); } @@ -619,6 +633,7 @@ void DirectShowPlayerService::doPlay(QMutexLocker *locker) QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); } else { m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", hr); QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); @@ -660,6 +675,7 @@ void DirectShowPlayerService::doPause(QMutexLocker *locker) QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); } else { m_error = QMediaPlayer::ResourceError; + m_errorString = QString(); qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", hr); QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error))); @@ -994,18 +1010,14 @@ void DirectShowPlayerService::customEvent(QEvent *event) updateStatus(); } else if (event->type() == QEvent::Type(Error)) { - QMediaPlayer::Error error; - { - QMutexLocker locker(&m_mutex); - error = m_error; - - if (error != QMediaPlayer::NoError) { - m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); - m_playerControl->updateState(QMediaPlayer::StoppedState); - updateStatus(); - } + QMutexLocker locker(&m_mutex); + + if (m_error != QMediaPlayer::NoError) { + m_playerControl->updateError(m_error, m_errorString); + m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); + m_playerControl->updateState(QMediaPlayer::StoppedState); + updateStatus(); } - m_playerControl->error(error, QString()); } else if (event->type() == QEvent::Type(RateChange)) { QMutexLocker locker(&m_mutex); diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h index 906d23b..f9d3232 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h @@ -205,6 +205,7 @@ private: QMediaTimeRange m_playbackRange; QUrl m_url; QMediaResourceList m_resources; + QString m_errorString; QMutex m_mutex; friend class DirectShowPlayerServiceThread; -- cgit v0.12 From 8b112609b7d86572fbb41dc59354da1f958d1910 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 9 Feb 2010 10:39:37 +0100 Subject: Cocoa: Menu in menubar stays highlighted If you use the menu bar for a window to open up another window woth no menu bar, the first menu bar stays highlighted once it is set as current again. The reason is that we remove the first menu bar before cocoa gets a chance to update it correctly. This patch implements a system for us to post a message/call to cocoa, so we delay removing the toolbar until after cocoa has finished closing it properly. NB: Rather than posting the call to a window on screen, it would have been better and safer to post it no window, and then receive the event in the event handler of NSApplication. But for the moment, we have decided not to subclass NSApplication... Rev-By:prasanth --- src/gui/kernel/qcocoamenuloader_mac.mm | 6 ++++++ src/gui/kernel/qcocoamenuloader_mac_p.h | 1 + src/gui/kernel/qcocoasharedwindowmethods_mac_p.h | 18 ++++++++++++++++++ src/gui/kernel/qeventdispatcher_mac.mm | 3 +-- src/gui/kernel/qt_cocoa_helpers_mac.mm | 24 ++++++++++++++++++++++++ src/gui/kernel/qt_cocoa_helpers_mac_p.h | 22 ++++++++++++++++++++++ src/gui/widgets/qmenu_mac.mm | 15 ++++++++++++++- src/gui/widgets/qmenubar_p.h | 1 + 8 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qcocoamenuloader_mac.mm b/src/gui/kernel/qcocoamenuloader_mac.mm index 18b3772..573b763 100644 --- a/src/gui/kernel/qcocoamenuloader_mac.mm +++ b/src/gui/kernel/qcocoamenuloader_mac.mm @@ -46,6 +46,7 @@ #include #include #include +#include #include QT_FORWARD_DECLARE_CLASS(QCFString) @@ -208,6 +209,11 @@ QT_USE_NAMESPACE [NSApp hide:sender]; } +- (void)qtUpdateMenubar +{ + QMenuBarPrivate::macUpdateMenuBarImmediatly(); +} + - (IBAction)qtDispatcherToQAction:(id)sender { QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData); diff --git a/src/gui/kernel/qcocoamenuloader_mac_p.h b/src/gui/kernel/qcocoamenuloader_mac_p.h index 81c136e..2504b8c 100644 --- a/src/gui/kernel/qcocoamenuloader_mac_p.h +++ b/src/gui/kernel/qcocoamenuloader_mac_p.h @@ -85,6 +85,7 @@ - (IBAction)unhideAllApplications:(id)sender; - (IBAction)hide:(id)sender; - (IBAction)qtDispatcherToQAction:(id)sender; +- (void)qtUpdateMenubar; @end #endif // QT_MAC_USE_COCOA diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index d8bbcd4..3b92ce2 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -178,8 +178,26 @@ QT_END_NAMESPACE [NSApp terminate:sender]; } +- (void)sendPostedMessage:(NSEvent *)event +{ + // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! + // That is why we need to split the address in two parts: + quint64 lower = [event data1]; + quint64 upper = [event data2]; + QCocoaPostCallArgs *args = reinterpret_cast(lower | (upper << 32)); + if (args != 0) { + [args->target performSelector:args->selector]; + delete args; + } +} + - (void)sendEvent:(NSEvent *)event { + if ([event type] == NSApplicationDefined) { + if ([event subtype] == QtCocoaEventSubTypePostMessage) + [self sendPostedMessage:event]; + return; + } QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; // Cocoa can hold onto the window after we've disavowed its knowledge. So, diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index c7d042d..8a67dee 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -1064,10 +1064,9 @@ void QEventDispatcherMacPrivate::cancelWaitForMoreEvents() // In case the event dispatcher is waiting for more // events somewhere, we post a dummy event to wake it up: QMacCocoaAutoReleasePool pool; - static const short NSAppShouldStopForQt = SHRT_MAX; [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint modifierFlags:0 timestamp:0. windowNumber:0 context:0 - subtype:NSAppShouldStopForQt data1:0 data2:0] atStart:NO]; + subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO]; } #endif diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index 377e5a0..74514a0 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -1281,6 +1281,30 @@ void qt_cocoaChangeOverrideCursor(const QCursor &cursor) } #endif +bool qt_cocoaPostMessage(id target, SEL selector) +{ + if (!target) + return false; + NSWindow *nswin = [NSApp mainWindow]; + if (!nswin) { + nswin = [NSApp keyWindow]; + if (!nswin) + return false; + } + + // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! + // That is why we need to split the address in two parts: + QCocoaPostCallArgs *args = new QCocoaPostCallArgs(target, selector); + quint32 lower = quintptr(args); + quint32 upper = quintptr(args) >> 32; + NSEvent *e = [NSEvent otherEventWithType:NSApplicationDefined + location:NSZeroPoint modifierFlags:0 timestamp:0 + windowNumber:[nswin windowNumber] + context:nil subtype:QtCocoaEventSubTypePostMessage data1:lower data2:upper]; + [NSApp postEvent:e atStart:NO]; + return true; +} + @implementation DebugNSApplication { } - (void)sendEvent:(NSEvent *)event diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h index ace8255..0b961b1 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h +++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h @@ -114,6 +114,12 @@ typedef struct CGPoint NSPoint; #endif QT_BEGIN_NAMESPACE + +enum { + QtCocoaEventSubTypeWakeup = SHRT_MAX, + QtCocoaEventSubTypePostMessage = SHRT_MAX-1 +}; + Qt::MouseButtons qt_mac_get_buttons(int buttons); Qt::MouseButton qt_mac_get_button(EventMouseButton button); void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds = 0.15); @@ -182,6 +188,22 @@ inline QString qt_mac_NSStringToQString(const NSString *nsstr) inline NSString *qt_mac_QStringToNSString(const QString &qstr) { return [reinterpret_cast(QCFString::toCFStringRef(qstr)) autorelease]; } +class QCocoaPostCallArgs { + public: + id target; + SEL selector; + QCocoaPostCallArgs(id target, SEL selector) : target(target), selector(selector) + { + [target retain]; + } + + ~QCocoaPostCallArgs() + { + [target release]; + } +}; +bool qt_cocoaPostMessage(id target, SEL selector); + @interface DebugNSApplication : NSApplication {} @end diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index 658a020..99c550f 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -2030,6 +2030,18 @@ void qt_mac_clear_menubar() */ bool QMenuBar::macUpdateMenuBar() { +#ifdef QT_MAC_USE_COCOA + QMacCocoaAutoReleasePool pool; + if (!qt_cocoaPostMessage(getMenuLoader(), @selector(qtUpdateMenubar))) + return QMenuBarPrivate::macUpdateMenuBarImmediatly(); + return true; +#else + return QMenuBarPrivate::macUpdateMenuBarImmediatly(); +#endif +} + +bool QMenuBarPrivate::macUpdateMenuBarImmediatly() +{ bool ret = false; cancelAllMenuTracking(); QWidget *w = findWindowThatShouldDisplayMenubar(); @@ -2095,8 +2107,9 @@ bool QMenuBar::macUpdateMenuBar() } } - if(!ret) + if (!ret) { qt_mac_clear_menubar(); + } return ret; } diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index f2e5357..819aee4 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -196,6 +196,7 @@ public: return 0; } } *mac_menubar; + static bool macUpdateMenuBarImmediatly(); bool macWidgetHasNativeMenubar(QWidget *widget); void macCreateMenuBar(QWidget *); void macDestroyMenuBar(); -- cgit v0.12 From 5be0f78985f73515645762b2895b6969be69a6e4 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 10 Feb 2010 09:04:50 +0100 Subject: Cocoa: Implement our own NSApplication subclass We have avoided doing so up till now, since we cannot always know if we will be able to use it. If some 3rd-party application creates NSApplication before Qt, our subclass will never be used (because of the singleton pattern that NSApplication follows). However, in most cases, Qt will be used in standalone applications, or the 3rd-party application will not subclass NSApplication. And in those cases, we can make certain functionallity more robust. Rev-By:msorvig --- src/gui/kernel/qapplication_mac.mm | 2 +- src/gui/kernel/qcocoaapplication_mac.mm | 45 ++++++++++++++++++++++++ src/gui/kernel/qcocoaapplication_mac_p.h | 8 +++++ src/gui/kernel/qcocoasharedwindowmethods_mac_p.h | 24 +++++-------- src/gui/kernel/qt_cocoa_helpers_mac.mm | 45 +++++++++++------------- src/gui/kernel/qt_cocoa_helpers_mac_p.h | 13 ++++--- 6 files changed, 89 insertions(+), 48 deletions(-) diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index 3fba833..0199e87 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -1237,7 +1237,7 @@ void qt_init(QApplicationPrivate *priv, int) // Cocoa application delegate #ifdef QT_MAC_USE_COCOA - NSApplication *cocoaApp = [NSApplication sharedApplication]; + NSApplication *cocoaApp = [QNSApplication sharedApplication]; QMacCocoaAutoReleasePool pool; NSObject *oldDelegate = [cocoaApp delegate]; QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; diff --git a/src/gui/kernel/qcocoaapplication_mac.mm b/src/gui/kernel/qcocoaapplication_mac.mm index 5b98420..5629940 100644 --- a/src/gui/kernel/qcocoaapplication_mac.mm +++ b/src/gui/kernel/qcocoaapplication_mac.mm @@ -107,5 +107,50 @@ | NSFontPanelStrikethroughEffectModeMask; } + +- (void)qt_sendPostedMessage:(NSEvent *)event +{ + // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! + // That is why we need to split the address in two parts: + quint64 lower = [event data1]; + quint64 upper = [event data2]; + QCocoaPostMessageArgs *args = reinterpret_cast(lower | (upper << 32)); + [args->target performSelector:args->selector]; + delete args; +} + +- (BOOL)qt_sendEvent:(NSEvent *)event +{ + if ([event type] == NSApplicationDefined) { + switch ([event subtype]) { + case QtCocoaEventSubTypePostMessage: + [NSApp qt_sendPostedMessage:event]; + return true; + default: + break; + } + } + return false; +} + @end + +@implementation QNSApplication + +// WARNING: If Qt did not create NSApplication (this can e.g. +// happend if Qt is used as a plugin from a 3rd-party cocoa +// application), QNSApplication::sendEvent will never be called. +// SO DO NOT RELY ON THIS FUNCTION BEING AVAILABLE. +// Plugin developers that _do_ control the NSApplication sub-class +// implementation of the 3rd-party application can call qt_sendEvent +// from the sub-class event handler (like we do here) to work around +// any issues. +- (void)sendEvent:(NSEvent *)event +{ + if (![self qt_sendEvent:event]) + [super sendEvent:event]; +} + +@end + #endif diff --git a/src/gui/kernel/qcocoaapplication_mac_p.h b/src/gui/kernel/qcocoaapplication_mac_p.h index e845d58..5569feb 100644 --- a/src/gui/kernel/qcocoaapplication_mac_p.h +++ b/src/gui/kernel/qcocoaapplication_mac_p.h @@ -99,5 +99,13 @@ QT_FORWARD_DECLARE_CLASS(QApplicationPrivate) - (QApplicationPrivate *)QT_MANGLE_NAMESPACE(qt_qappPrivate); - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader); - (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel; + +- (void)qt_sendPostedMessage:(NSEvent *)event; +- (BOOL)qt_sendEvent:(NSEvent *)event; +@end + +@interface QNSApplication : NSApplication { +} @end + #endif diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index 3b92ce2..24a3bb5 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -178,28 +178,20 @@ QT_END_NAMESPACE [NSApp terminate:sender]; } -- (void)sendPostedMessage:(NSEvent *)event -{ - // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! - // That is why we need to split the address in two parts: - quint64 lower = [event data1]; - quint64 upper = [event data2]; - QCocoaPostCallArgs *args = reinterpret_cast(lower | (upper << 32)); - if (args != 0) { - [args->target performSelector:args->selector]; - delete args; - } -} - - (void)sendEvent:(NSEvent *)event { if ([event type] == NSApplicationDefined) { - if ([event subtype] == QtCocoaEventSubTypePostMessage) - [self sendPostedMessage:event]; + switch ([event subtype]) { + case QtCocoaEventSubTypePostMessage: + [NSApp qt_sendPostedMessage:event]; + return; + default: + break; + } return; } - QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; // Cocoa can hold onto the window after we've disavowed its knowledge. So, // if we get sent an event afterwards just have it go through the super's // version and don't do any stuff with Qt. diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index 74514a0..8c23902 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -1279,46 +1280,42 @@ void qt_cocoaChangeOverrideCursor(const QCursor &cursor) QMacCocoaAutoReleasePool pool; [static_cast(qt_mac_nsCursorForQCursor(cursor)) set]; } -#endif +// WARNING: If Qt did not create NSApplication (e.g. in case it is +// used as a plugin), and at the same time, there is no window on +// screen (or the window that the event is sendt to becomes hidden etc +// before the event gets delivered), the message will not be performed. bool qt_cocoaPostMessage(id target, SEL selector) { if (!target) return false; - NSWindow *nswin = [NSApp mainWindow]; - if (!nswin) { - nswin = [NSApp keyWindow]; - if (!nswin) - return false; + + NSInteger windowNumber = 0; + if (![NSApp isMemberOfClass:[QNSApplication class]]) { + // INVARIANT: Cocoa is not using our NSApplication subclass. That means + // we don't control the main event handler either. So target the event + // for one of the windows on screen: + NSWindow *nswin = [NSApp mainWindow]; + if (!nswin) { + nswin = [NSApp keyWindow]; + if (!nswin) + return false; + } + windowNumber = [nswin windowNumber]; } // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5! // That is why we need to split the address in two parts: - QCocoaPostCallArgs *args = new QCocoaPostCallArgs(target, selector); + QCocoaPostMessageArgs *args = new QCocoaPostMessageArgs(target, selector); quint32 lower = quintptr(args); quint32 upper = quintptr(args) >> 32; NSEvent *e = [NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint modifierFlags:0 timestamp:0 - windowNumber:[nswin windowNumber] + location:NSZeroPoint modifierFlags:0 timestamp:0 windowNumber:windowNumber context:nil subtype:QtCocoaEventSubTypePostMessage data1:lower data2:upper]; [NSApp postEvent:e atStart:NO]; return true; } - -@implementation DebugNSApplication { -} -- (void)sendEvent:(NSEvent *)event -{ - NSLog(@"NSAppDebug: sendEvent: %@", event); - return [super sendEvent:event]; -} - -- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender -{ - NSLog(@"NSAppDebug: sendAction: %s to %@ from %@", anAction, aTarget, sender); - return [super sendAction:anAction to:aTarget from:sender]; -} -@end +#endif QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool() { diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h index 0b961b1..c43ea55 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h +++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h @@ -188,24 +188,23 @@ inline QString qt_mac_NSStringToQString(const NSString *nsstr) inline NSString *qt_mac_QStringToNSString(const QString &qstr) { return [reinterpret_cast(QCFString::toCFStringRef(qstr)) autorelease]; } -class QCocoaPostCallArgs { - public: +#ifdef QT_MAC_USE_COCOA +class QCocoaPostMessageArgs { +public: id target; SEL selector; - QCocoaPostCallArgs(id target, SEL selector) : target(target), selector(selector) + QCocoaPostMessageArgs(id target, SEL selector) : target(target), selector(selector) { [target retain]; } - ~QCocoaPostCallArgs() + ~QCocoaPostMessageArgs() { [target release]; } }; bool qt_cocoaPostMessage(id target, SEL selector); - -@interface DebugNSApplication : NSApplication {} -@end +#endif #endif -- cgit v0.12 From 238528f67922d74bb951dae1a4a6a3745ce8b178 Mon Sep 17 00:00:00 2001 From: Prasanth Ullattil Date: Wed, 10 Feb 2010 10:36:05 +0100 Subject: Incorrect property setter generated by dumpcpp for Microsoft Word 2007. This particular propery setter had multiple parameters (or is Array type property). An incorrect return type was set by the function generator. This patch clears the type name for such INVOKE_PROPERTYPUT functions, the return type will be void. Task-number: QTBUG-7571 Reviewed-by: Volker Hilsheimer --- src/activeqt/container/qaxbase.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp index 99447a9..02a29d9 100644 --- a/src/activeqt/container/qaxbase.cpp +++ b/src/activeqt/container/qaxbase.cpp @@ -2543,6 +2543,11 @@ void MetaObjectGenerator::readFuncsInfo(ITypeInfo *typeinfo, ushort nFuncs) break; } if (funcdesc->invkind == INVOKE_PROPERTYPUT) { + // remove the typename guessed for property setters + // its done only for setter's with more than one parameter. + if (funcdesc->cParams - funcdesc->cParamsOpt > 1) { + type.clear(); + } QByteArray set; if (isupper(prototype.at(0))) { set = "Set"; -- cgit v0.12 From 8032423bb8fa91c623ece61bff528adfd49e8685 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 10 Feb 2010 12:28:27 +0100 Subject: Revert 004b09ffd423cd3100e346825dd7d730fc86d366 Changing the height here will make the coords out of sync with the ' buffer, causing broken drawing. I revert this change to prepare QStaticText for integration, and will revisit it later on. --- src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 53c627f..6cb76ee 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -70,12 +70,8 @@ QGLTextureGlyphCache::~QGLTextureGlyphCache() } } -void QGLTextureGlyphCache::createTextureData(int width, int unalteredHeight) +void QGLTextureGlyphCache::createTextureData(int width, int height) { - extern int qt_next_power_of_two(int v); - // Set height to lowest POT number which is higher than or equal to height - int height = qt_next_power_of_two(unalteredHeight); - glGenTextures(1, &m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); -- cgit v0.12 From 2e8d090fa6813a2e37c9ed27d69bc3fc99a7ae35 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 10 Feb 2010 14:16:24 +0100 Subject: Make QStaticText public API again QStaticText was previously made private API to support inclusion in Qt 4.6.x. This change turns it back into public API for Qt 4.7.0. --- src/gui/painting/qpaintbuffer.cpp | 7 +- src/gui/painting/qpaintengine_raster.cpp | 2 +- src/gui/painting/qpainter.cpp | 82 ++++++------ src/gui/painting/qpainter.h | 15 +++ src/gui/painting/qpainter_p.h | 6 - src/gui/text/qstatictext.cpp | 2 +- src/gui/text/qstatictext.h | 98 ++++++++++++++ src/gui/text/qstatictext_p.h | 110 ++++++++++------ src/gui/text/qstatictext_p_p.h | 141 --------------------- src/gui/text/text.pri | 4 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- src/opengl/qpaintengine_opengl.cpp | 2 +- src/openvg/qpaintengine_vg.cpp | 2 +- tests/auto/qstatictext/tst_qstatictext.cpp | 34 ++--- 14 files changed, 253 insertions(+), 254 deletions(-) create mode 100644 src/gui/text/qstatictext.h delete mode 100644 src/gui/text/qstatictext_p_p.h diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 51eb681..664d864 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -45,8 +45,8 @@ #include #include #include +#include #include -#include #include @@ -1448,9 +1448,10 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) QStaticText text(variants.at(0).value()); painter->setFont(font); - qt_draw_static_text(painter, QPointF(0, 0), text); + painter->drawStaticText(QPointF(0, 0), text); - break; } + break; + } case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index a2e14e1..41c4f14 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -67,7 +67,7 @@ // #include // #include #include -#include +#include #include "qpaintengine_raster_p.h" // #include "qbezier_p.h" diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index c2e2fef..8ab813d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -69,8 +69,8 @@ #include #include #include +#include #include -#include QT_BEGIN_NAMESPACE @@ -5699,6 +5699,19 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR } /*! + + \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) + + \overload +*/ + +/*! + \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) + + \overload +*/ + +/*! \fn void QPainter::drawText(const QPointF &position, const QString &text) Draws the given \a text with the currently defined text direction, @@ -5720,23 +5733,10 @@ void QPainter::drawText(const QPointF &p, const QString &str) drawText(p, str, 0, 0); } -QPainterPrivate *QPainterPrivate::get(QPainter *p) +void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) { - return p->d_ptr.data(); -} - -void qt_draw_static_text(QPainter *p, const QPointF &position, const QStaticText &text) -{ - QPainterPrivate *prv = QPainterPrivate::get(p); - Q_ASSERT(prv != 0); - - prv->drawStaticText(position, text); -} - -void QPainterPrivate::drawStaticText(const QPointF &position, const QStaticText &staticText) -{ - Q_Q(QPainter); - if (!engine || staticText.isEmpty() || q->pen().style() == Qt::NoPen) + Q_D(QPainter); + if (!d->engine || staticText.isEmpty() || pen().style() == Qt::NoPen) return; QStaticTextPrivate *staticText_d = @@ -5744,31 +5744,31 @@ void QPainterPrivate::drawStaticText(const QPointF &position, const QStaticText // If we don't have an extended paint engine, or if the painter is projected, // we go through standard code path - if (extended == 0 || !state->matrix.isAffine()) { + if (d->extended == 0 || !d->state->matrix.isAffine()) { if (staticText_d->size.isValid()) - q->drawText(QRectF(position, staticText_d->size), staticText_d->text); + drawText(QRectF(position, staticText_d->size), staticText_d->text); else - q->drawText(position, staticText_d->text); + drawText(position, staticText_d->text); 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 * state->matrix; - QTransform matrix = state->matrix; + QPointF transformedPosition = position * d->state->matrix; + QTransform matrix = d->state->matrix; // The translation has been applied to transformedPosition. Remove translation // component from matrix. - if (state->matrix.isTranslating()) { - qreal m11 = state->matrix.m11(); - qreal m12 = state->matrix.m12(); - qreal m13 = state->matrix.m13(); - qreal m21 = state->matrix.m21(); - qreal m22 = state->matrix.m22(); - qreal m23 = state->matrix.m23(); - qreal m33 = state->matrix.m33(); - - state->matrix.setMatrix(m11, m12, m13, + 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); } @@ -5776,21 +5776,21 @@ void QPainterPrivate::drawStaticText(const QPointF &position, const QStaticText // 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 != state->matrix) { - staticText_d->matrix = state->matrix; + if (staticText_d->matrix != d->state->matrix) { + staticText_d->matrix = d->state->matrix; staticTextNeedsReinit = true; } bool restoreWhenFinished = false; if (staticText_d->needsClipRect) { - q->save(); - q->setClipRect(QRectF(position, staticText_d->size)); + save(); + setClipRect(QRectF(position, staticText_d->size)); restoreWhenFinished = true; } - if (q->font() != staticText_d->font) { - staticText_d->font = q->font(); + if (font() != staticText_d->font) { + staticText_d->font = font(); staticTextNeedsReinit = true; } @@ -5817,14 +5817,14 @@ void QPainterPrivate::drawStaticText(const QPointF &position, const QStaticText for (int i=0; iitemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; - extended->drawStaticTextItem(item); + d->extended->drawStaticTextItem(item); } if (restoreWhenFinished) - q->restore(); + restore(); if (matrix.isTranslating()) - state->matrix = matrix; + d->state->matrix = matrix; } /*! 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/qpainter_p.h b/src/gui/painting/qpainter_p.h index 2979de6..02a91aa 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -70,7 +70,6 @@ QT_BEGIN_NAMESPACE class QPaintEngine; class QEmulationPaintEngine; class QPaintEngineEx; -class QStaticText; struct QTLWExtra; @@ -230,8 +229,6 @@ public: void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); - void drawStaticText(const QPointF &position, const QStaticText &staticText); - void updateMatrix(); void updateInvMatrix(); @@ -245,8 +242,6 @@ public: static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev); void detachPainterPrivate(QPainter *q); - static QPainterPrivate *get(QPainter *p); - QPaintDevice *device; QPaintDevice *original_device; QPaintDevice *helper_device; @@ -257,7 +252,6 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); -Q_GUI_EXPORT void qt_draw_static_text(QPainter *p, const QPointF &position, const QStaticText &text); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 659324b..74c5958 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -39,8 +39,8 @@ ** ****************************************************************************/ +#include "qstatictext.h" #include "qstatictext_p.h" -#include "qstatictext_p_p.h" #include #include diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h new file mode 100644 index 0000000..11a4249 --- /dev/null +++ b/src/gui/text/qstatictext.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTATICTEXT_H +#define QSTATICTEXT_H + +#include +#include +#include + +#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStaticTextPrivate; +class Q_GUI_EXPORT QStaticText +{ +public: + QStaticText(); + QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); + QStaticText(const QStaticText &other); + ~QStaticText(); + + void setText(const QString &text); + QString text() const; + + void setMaximumSize(const QSizeF &maximumSize); + QSizeF maximumSize() const; + + void prepare(const QTransform &matrix, const QFont &font); + + void setUseBackendOptimizations(bool on); + bool useBackendOptimizations() const; + + QStaticText &operator=(const QStaticText &); + bool operator==(const QStaticText &) const; + bool operator!=(const QStaticText &) const; + + bool isEmpty() const; + +private: + void detach(); + + QExplicitlySharedDataPointer 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 index a19fb6c..72c8439 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QSTATICTEXT_H -#define QSTATICTEXT_H +#ifndef QSTATICTEXT_P_H +#define QSTATICTEXT_P_H // // W A R N I N G @@ -53,57 +53,89 @@ // We mean it. // -#include -#include -#include +#include -#include -#include +QT_BEGIN_NAMESPACE +class QStaticTextUserData +{ +public: + enum Type { + NoUserData, + OpenGLUserData + }; -QT_BEGIN_HEADER + QStaticTextUserData(Type t) : type(t) {} + virtual ~QStaticTextUserData() {} -QT_BEGIN_NAMESPACE + Type type; +}; -QT_MODULE(Gui) +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 + QStaticTextUserData *userData; // 8 bytes per item + char useBackendOptimizations : 1; // 1 byte per item + char userDataNeedsUpdate : 1; // + // ================ + // 41 bytes per item +}; -class QStaticTextPrivate; -class Q_GUI_EXPORT QStaticText -{ +class QStaticText; +class Q_AUTOTEST_EXPORT QStaticTextPrivate +{ public: - QStaticText(); - QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); - QStaticText(const QStaticText &other); - ~QStaticText(); + QStaticTextPrivate(); + QStaticTextPrivate(const QStaticTextPrivate &other); + ~QStaticTextPrivate(); - void setText(const QString &text); - QString text() const; + void init(); - void setMaximumSize(const QSizeF &maximumSize); - QSizeF maximumSize() const; + QAtomicInt ref; // 4 bytes per text - void prepare(const QTransform &matrix, const QFont &font); + QString text; // 4 bytes per text + QFont font; // 8 bytes per text + QSizeF size; // 16 bytes per text + QPointF position; // 16 bytes per text - void setUseBackendOptimizations(bool on); - bool useBackendOptimizations() const; + 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 - QStaticText &operator=(const QStaticText &); - bool operator==(const QStaticText &) const; - bool operator!=(const QStaticText &) const; + char needsClipRect : 1; // 1 byte per text + char useBackendOptimizations : 1; + // ================ + // 145 bytes per text - bool isEmpty() const; - -private: - void detach(); - - QExplicitlySharedDataPointer data; - friend class QStaticTextPrivate; + static QStaticTextPrivate *get(const QStaticText *q); }; -Q_DECLARE_METATYPE(QStaticText) - QT_END_NAMESPACE -QT_END_HEADER - -#endif // QSTATICTEXT_H +#endif // QSTATICTEXT_P_H diff --git a/src/gui/text/qstatictext_p_p.h b/src/gui/text/qstatictext_p_p.h deleted file mode 100644 index 72c8439..0000000 --- a/src/gui/text/qstatictext_p_p.h +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@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 - -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 - QStaticTextUserData *userData; // 8 bytes per item - char useBackendOptimizations : 1; // 1 byte per item - char userDataNeedsUpdate : 1; // - // ================ - // 41 bytes per item -}; - -class QStaticText; -class Q_AUTOTEST_EXPORT QStaticTextPrivate -{ -public: - QStaticTextPrivate(); - QStaticTextPrivate(const QStaticTextPrivate &other); - ~QStaticTextPrivate(); - - void init(); - - QAtomicInt ref; // 4 bytes per text - - QString text; // 4 bytes per text - QFont font; // 8 bytes per text - QSizeF size; // 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 - - char needsClipRect : 1; // 1 byte per text - char useBackendOptimizations : 1; - // ================ - // 145 bytes per text - - static QStaticTextPrivate *get(const QStaticText *q); -}; - -QT_END_NAMESPACE - -#endif // QSTATICTEXT_P_H diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 2eaa418..9ec3142 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -38,8 +38,8 @@ HEADERS += \ text/qzipreader_p.h \ text/qzipwriter_p.h \ text/qtextodfwriter_p.h \ - text/qstatictext_p_p.h \ - text/qstatictext_p.h + text/qstatictext_p.h \ + text/qstatictext.h SOURCES += \ text/qfont.cpp \ diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 685f0c1..4ae8e6a 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -77,7 +77,7 @@ #include #include #include -#include +#include #include "qglgradientcache_p.h" #include "qglengineshadermanager_p.h" diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index e7a1b7e..a2f085c 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include "private/qtessellator_p.h" diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index c8a60d0..41772d1 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 9e4b540..92c0008 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -46,9 +46,8 @@ #include +#include #include -#include -#include // #define DEBUG_SAVE_IMAGE @@ -120,7 +119,7 @@ void tst_QStaticText::drawToPoint() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setUseBackendOptimizations(useBackendOptimizations); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -151,7 +150,7 @@ void tst_QStaticText::drawToRect() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500)); text.setUseBackendOptimizations(useBackendOptimizations); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -178,7 +177,7 @@ void tst_QStaticText::prepareToCorrectData() p.setTransform(transform); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.prepare(transform, p.font()); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -203,7 +202,7 @@ void tst_QStaticText::prepareToWrongData() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.prepare(transform, p.font()); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -234,9 +233,10 @@ void tst_QStaticText::setFont() QStaticText text; text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - qt_draw_static_text(&p, QPointF(0, 0), text); + p.drawStaticText(0, 0, text); + p.setFont(font); - qt_draw_static_text(&p, QPointF(11, 120), text); + p.drawStaticText(11, 120, text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -257,7 +257,7 @@ void tst_QStaticText::setMaximumSize() QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setMaximumSize(QSizeF(10, 500)); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -281,7 +281,7 @@ void tst_QStaticText::translatedPainter() p.translate(100, 200); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -304,7 +304,7 @@ void tst_QStaticText::rotatedPainter() QPainter p(&imageDrawStaticText); p.rotate(30.0); - qt_draw_static_text(&p, QPointF(0, 0), text); + p.drawStaticText(QPoint(0, 0), text); } #if defined(DEBUG_SAVE_IMAGE) @@ -333,7 +333,7 @@ void tst_QStaticText::scaledPainter() p.scale(2.0, 0.2); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -360,7 +360,7 @@ void tst_QStaticText::projectedPainter() p.setTransform(transform); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -389,7 +389,7 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() p.translate(100, 200); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - qt_draw_static_text(&p, QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12), text); } #if defined(DEBUG_SAVE_IMAGE) @@ -423,10 +423,10 @@ void tst_QStaticText::transformationChanged() p.scale(0.5, 0.7); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - qt_draw_static_text(&p, QPointF(0, 0), text); + p.drawStaticText(QPointF(0, 0), text); p.scale(7.0, 5.0); - qt_draw_static_text(&p, QPointF(0, 0), text); + p.drawStaticText(QPointF(0, 0), text); } #if defined(DEBUG_SAVE_IMAGE) @@ -462,7 +462,7 @@ public: switch (m_paintEventType) { case NormalDrawStaticText: case DrawStaticTextWithCaching: - qt_draw_static_text(&painter, QPointF(11, 12), m_staticText); + painter.drawStaticText(QPointF(11, 12), m_staticText); break; case NormalDrawText: painter.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); -- cgit v0.12 From d44081d5a63cebd05783b343dd4ef364345855ff Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 10 Feb 2010 14:49:54 +0100 Subject: qdoc3: Added capability to create qt.pageindex. Task: QTBUG-7877 --- tools/qdoc3/htmlgenerator.cpp | 118 ++++++++++++++++++++++++++++++++++++-- tools/qdoc3/htmlgenerator.h | 12 +++- tools/qdoc3/javadocgenerator.cpp | 2 +- tools/qdoc3/javadocgenerator.h | 2 +- tools/qdoc3/linguistgenerator.cpp | 2 +- tools/qdoc3/linguistgenerator.h | 2 +- tools/qdoc3/main.cpp | 3 +- tools/qdoc3/mangenerator.cpp | 2 +- tools/qdoc3/mangenerator.h | 2 +- tools/qdoc3/node.cpp | 50 +++++++++++++++- tools/qdoc3/node.h | 16 +++++- tools/qdoc3/pagegenerator.cpp | 4 +- tools/qdoc3/pagegenerator.h | 6 +- tools/qdoc3/webxmlgenerator.cpp | 2 +- tools/qdoc3/webxmlgenerator.h | 2 +- 15 files changed, 202 insertions(+), 23 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 15386f1..b1642df 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_VERSION Doc::alias("version") +int HtmlGenerator::id = 0; QString HtmlGenerator::sinceTitles[] = { @@ -389,9 +390,9 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) "qmake Manual", dcfQmakeRoot); - generateIndex(project.toLower().simplified().replace(" ", "-"), - projectUrl, - projectDescription); + QString fileBase = project.toLower().simplified().replace(" ", "-"); + generateIndex(fileBase, projectUrl, projectDescription); + generatePageIndex(outputDir() + "/" + fileBase + ".pageindex", marker); helpProjectWriter->generate(myTree); } @@ -1619,7 +1620,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) } } -QString HtmlGenerator::fileExtension(const Node * /* node */) +QString HtmlGenerator::fileExtension(const Node * /* node */) const { return "html"; } @@ -4352,4 +4353,113 @@ void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, } } +/*! + Generate the element for the given \a node using the \a writer. + Return true if a element was written; otherwise return false. + */ +bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, + const Node* node, + CodeMarker* marker) const +{ + if (node->pageType() == Node::NoPageType) + return false; + if (node->name().isEmpty()) + return false; + if (node->access() == Node::Private) + return false; + + QString title; + QString rawTitle; + QString fullTitle; + + writer.writeStartElement("page"); + QXmlStreamAttributes attributes; + QString t; + t.setNum(id++); + switch (node->type()) { + case Node::Fake: + const FakeNode* fake = static_cast(node); + title = fake->fullTitle(); + break; + case Node::Class: + title = node->name() + " Class Reference"; + break; + case Node::Namespace: + const InnerNode* inner = static_cast(node); + rawTitle = marker->plainName(inner); + fullTitle = marker->plainFullName(inner); + title = rawTitle + " Namespace Reference"; + break; + default: + title = node->name(); + break; + } + writer.writeAttribute("id",t); + writer.writeStartElement("pageWords"); + writer.writeCharacters(title); + writer.writeEndElement(); + writer.writeStartElement("pageTitle"); + writer.writeCharacters(title); + writer.writeEndElement(); + writer.writeStartElement("pageUrl"); + writer.writeCharacters(PageGenerator::fileName(node)); + writer.writeEndElement(); + writer.writeStartElement("pageType"); + switch (node->pageType()) { + case Node::ApiPage: + writer.writeCharacters("APIPage"); + break; + case Node::ArticlePage: + writer.writeCharacters("Article"); + break; + case Node::ExamplePage: + writer.writeCharacters("Example"); + break; + default: + break; + } + writer.writeEndElement(); + writer.writeEndElement(); + return true; +} + +/*! + Traverse the tree recursively and generate the + elements. + */ +void HtmlGenerator::generatePageElements(QXmlStreamWriter& writer, const Node* node, CodeMarker* marker) const +{ + if (generatePageElement(writer, node, marker)) { + + if (node->isInnerNode()) { + const InnerNode *inner = static_cast(node); + + // Recurse to write an element for this child node and all its children. + foreach (const Node *child, inner->childNodes()) + generatePageElements(writer, child, marker); + } + } +} + +/*! + Outputs the file containing the index used for searching the html docs. + */ +void HtmlGenerator::generatePageIndex(const QString& fileName, CodeMarker* marker) const +{ + QFile file(fileName); + if (!file.open(QFile::WriteOnly | QFile::Text)) + return ; + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + writer.writeStartElement("qtPageIndex"); + + generatePageElements(writer, myTree->root(), marker); + + writer.writeEndElement(); // qtPageIndex + writer.writeEndDocument(); + file.close(); +} + #endif diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 19a7c78..41f0ff8 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -50,6 +50,7 @@ #include #include +#include #include "codemarker.h" #include "config.h" @@ -115,7 +116,7 @@ class HtmlGenerator : public PageGenerator CodeMarker *marker); virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; virtual QString refForNode(const Node *node); virtual QString linkForNode(const Node *node, const Node *relative); virtual QString refForAtom(Atom *atom, const Node *node); @@ -261,6 +262,14 @@ class HtmlGenerator : public PageGenerator const Node *relative, CodeMarker *marker); void endLink(); + bool generatePageElement(QXmlStreamWriter& writer, + const Node* node, + CodeMarker* marker) const; + void generatePageElements(QXmlStreamWriter& writer, + const Node* node, + CodeMarker* marker) const; + void generatePageIndex(const QString& fileName, + CodeMarker* marker) const; #if 0 NavigationBar currentNavigationBar; @@ -315,6 +324,7 @@ class HtmlGenerator : public PageGenerator NewSinceMaps newSinceMaps; static QString sinceTitles[]; NewClassMaps newClassMaps; + static int id; }; #define HTMLGENERATOR_ADDRESS "address" diff --git a/tools/qdoc3/javadocgenerator.cpp b/tools/qdoc3/javadocgenerator.cpp index 001bd27..eb9c1c9 100644 --- a/tools/qdoc3/javadocgenerator.cpp +++ b/tools/qdoc3/javadocgenerator.cpp @@ -145,7 +145,7 @@ void JavadocGenerator::generateTree(const Tree *tree, CodeMarker *marker) HtmlGenerator::generateTree(tree, marker); } -QString JavadocGenerator::fileExtension(const Node *node) +QString JavadocGenerator::fileExtension(const Node *node) const { if (node->type() == Node::Fake) { return "html"; diff --git a/tools/qdoc3/javadocgenerator.h b/tools/qdoc3/javadocgenerator.h index 73452cf..b485502 100644 --- a/tools/qdoc3/javadocgenerator.h +++ b/tools/qdoc3/javadocgenerator.h @@ -61,7 +61,7 @@ public: QString imageFileName(const Node *relative, const QString &fileBase); protected: - QString fileExtension(const Node *node); + QString fileExtension(const Node *node) const; void startText( const Node *relative, CodeMarker *marker ); void endText( const Node *relative, CodeMarker *marker ); int generateAtom( const Atom *atom, const Node *relative, CodeMarker *marker ); diff --git a/tools/qdoc3/linguistgenerator.cpp b/tools/qdoc3/linguistgenerator.cpp index d1bd22d..dde8b4c 100644 --- a/tools/qdoc3/linguistgenerator.cpp +++ b/tools/qdoc3/linguistgenerator.cpp @@ -82,7 +82,7 @@ QString LinguistGenerator::format() return "Linguist"; } -QString LinguistGenerator::fileExtension(const Node * /* node */) +QString LinguistGenerator::fileExtension(const Node * /* node */) const { return "ts"; } diff --git a/tools/qdoc3/linguistgenerator.h b/tools/qdoc3/linguistgenerator.h index f7f0606..979db02 100644 --- a/tools/qdoc3/linguistgenerator.h +++ b/tools/qdoc3/linguistgenerator.h @@ -70,7 +70,7 @@ protected: virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode( const FakeNode *fake, CodeMarker *marker ); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; QList generateIndexSections(QDomDocument &document, const Node *node, CodeMarker *marker); diff --git a/tools/qdoc3/main.cpp b/tools/qdoc3/main.cpp index 3d0106d..57823fb 100644 --- a/tools/qdoc3/main.cpp +++ b/tools/qdoc3/main.cpp @@ -337,8 +337,9 @@ static void processQdocconfFile(const QString &fileName) Generate the XML tag file, if it was requested. */ QString tagFile = config.getString(CONFIG_TAGFILE); - if (!tagFile.isEmpty()) + if (!tagFile.isEmpty()) { tree->generateTagFile(tagFile); + } tree->setVersion(""); Generator::terminate(); diff --git a/tools/qdoc3/mangenerator.cpp b/tools/qdoc3/mangenerator.cpp index c3b7780..1e85b73 100644 --- a/tools/qdoc3/mangenerator.cpp +++ b/tools/qdoc3/mangenerator.cpp @@ -187,7 +187,7 @@ void ManGenerator::generateFakeNode( const FakeNode *fake, CodeMarker *marker ) generateFooter(); } -QString ManGenerator::fileExtension(const Node * /* node */) +QString ManGenerator::fileExtension(const Node * /* node */) const { return "3qt"; } diff --git a/tools/qdoc3/mangenerator.h b/tools/qdoc3/mangenerator.h index 284517e..0fca342 100644 --- a/tools/qdoc3/mangenerator.h +++ b/tools/qdoc3/mangenerator.h @@ -63,7 +63,7 @@ protected: CodeMarker *marker ); virtual void generateClassLikeNode(const InnerNode *node, CodeMarker *marker); virtual void generateFakeNode( const FakeNode *fake, CodeMarker *marker ); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; private: void generateHeader( const QString& name ); diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index 9357671..f3958c6 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -92,8 +92,9 @@ void Node::setDoc(const Doc& doc, bool replace) Node::Node(Type type, InnerNode *parent, const QString& name) : typ(type), acc(Public), - sta(Commendable), saf(UnspecifiedSafeness), + pageTyp(NoPageType), + sta(Commendable), par(parent), rel(0), nam(name) @@ -103,6 +104,7 @@ Node::Node(Type type, InnerNode *parent, const QString& name) } /*! + Returns the node's URL. */ QString Node::url() const { @@ -110,13 +112,25 @@ QString Node::url() const } /*! + Sets the node's URL to \a url */ void Node::setUrl(const QString &url) { u = url; } +void Node::setPageType(const QString& t) +{ + if ((t == "API") || (t == "api")) + pageTyp = ApiPage; + else if (t == "article") + pageTyp = ArticlePage; + else if (t == "example") + pageTyp = ExamplePage; +} + /*! + Sets the pointer to the node that this node relates to. */ void Node::setRelates(InnerNode *pseudoParent) { @@ -455,6 +469,9 @@ const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const } /*! + Returnds the sequence number of the function node \a func + in the list of overloaded functions for a class, such that + all the functions have the same name as the \a func. */ int InnerNode::overloadNumber(const FunctionNode *func) const { @@ -468,6 +485,8 @@ int InnerNode::overloadNumber(const FunctionNode *func) const } /*! + Returns the number of member functions of a class such that + the functions are all named \a funcName. */ int InnerNode::numOverloads(const QString& funcName) const { @@ -480,6 +499,8 @@ int InnerNode::numOverloads(const QString& funcName) const } /*! + Returns a node list containing all the member functions of + some class such that the functions overload the name \a funcName. */ NodeList InnerNode::overloads(const QString &funcName) const { @@ -499,6 +520,8 @@ NodeList InnerNode::overloads(const QString &funcName) const InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name) : Node(type, parent, name) { + if (type == Class) + setPageType(ApiPage); } /*! @@ -682,6 +705,8 @@ bool LeafNode::isInnerNode() const } /*! + Constructs a leaf node named \a name of the specified + \a type. The new leaf node becomes a child of \a parent. */ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name) : Node(type, parent, name) @@ -693,10 +718,12 @@ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name) */ /*! + Constructs a namespace node. */ NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name) : InnerNode(Namespace, parent, name) { + setPageType(ApiPage); } /*! @@ -704,11 +731,13 @@ NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name) */ /*! + Constructs a class node. A class node will generate an API page. */ ClassNode::ClassNode(InnerNode *parent, const QString& name) : InnerNode(Class, parent, name) { hidden = false; + setPageType(ApiPage); } /*! @@ -765,11 +794,28 @@ void ClassNode::fixBaseClasses() /*! The type of a FakeNode is Fake, and it has a \a subtype, - which specifies the type of FakeNode. + which specifies the type of FakeNode. The page type for + the page index is set here. */ FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype) : InnerNode(Fake, parent, name), sub(subtype) { + switch (subtype) { + case Module: + case Page: + case Group: + setPageType(ArticlePage); + break; + case QmlClass: + case QmlBasicType: + setPageType(ApiPage); + break; + case Example: + setPageType(ExamplePage); + break; + default: + break; + } } /*! diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 077aeb8..679a9d4 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -137,6 +137,13 @@ class Node AppendixLink */ }; + enum PageType { + NoPageType, + ApiPage, + ArticlePage, + ExamplePage + }; + virtual ~Node(); void setAccess(Access access) { acc = access; } @@ -150,6 +157,8 @@ class Node void setLink(LinkType linkType, const QString &link, const QString &desc); void setUrl(const QString &url); void setTemplateStuff(const QString &templateStuff) { tpl = templateStuff; } + void setPageType(PageType t) { pageTyp = t; } + void setPageType(const QString& t); virtual bool isInnerNode() const = 0; virtual bool isReimp() const { return false; } @@ -173,6 +182,7 @@ class Node ThreadSafeness inheritedThreadSafeness() const; QString since() const { return sinc; } QString templateStuff() const { return tpl; } + PageType pageType() const { return pageTyp; } void clearRelated() { rel = 0; } @@ -186,13 +196,15 @@ class Node #ifdef Q_WS_WIN Type typ; Access acc; - Status sta; ThreadSafeness saf; + PageType pageTyp; + Status sta; #else Type typ : 4; Access acc : 2; - Status sta : 3; ThreadSafeness saf : 2; + PageType pageTyp : 4; + Status sta : 3; #endif InnerNode *par; InnerNode *rel; diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index 07edcc4..e0c5006 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -77,7 +77,7 @@ void PageGenerator::generateTree(const Tree *tree, CodeMarker *marker) generateInnerNode(tree->root(), marker); } -QString PageGenerator::fileBase(const Node *node) +QString PageGenerator::fileBase(const Node *node) const { if (node->relates()) node = node->relates(); @@ -153,7 +153,7 @@ QString PageGenerator::fileBase(const Node *node) return res; } -QString PageGenerator::fileName(const Node *node) +QString PageGenerator::fileName(const Node *node) const { if (!node->url().isEmpty()) return node->url(); diff --git a/tools/qdoc3/pagegenerator.h b/tools/qdoc3/pagegenerator.h index db24edd..ce236f3 100644 --- a/tools/qdoc3/pagegenerator.h +++ b/tools/qdoc3/pagegenerator.h @@ -67,9 +67,9 @@ class PageGenerator : public Generator virtual void generateTree(const Tree *tree, CodeMarker *marker); protected: - virtual QString fileBase(const Node *node); - virtual QString fileExtension(const Node *node) = 0; - QString fileName(const Node *node); + virtual QString fileBase(const Node *node) const; + virtual QString fileExtension(const Node *node) const = 0; + QString fileName(const Node *node) const; QString outFileName(); void beginSubPage(const Location& location, const QString& fileName); void endSubPage(); diff --git a/tools/qdoc3/webxmlgenerator.cpp b/tools/qdoc3/webxmlgenerator.cpp index a3c92ce..205bc8c 100644 --- a/tools/qdoc3/webxmlgenerator.cpp +++ b/tools/qdoc3/webxmlgenerator.cpp @@ -90,7 +90,7 @@ QString WebXMLGenerator::format() return "WebXML"; } -QString WebXMLGenerator::fileExtension(const Node * /* node */) +QString WebXMLGenerator::fileExtension(const Node * /* node */) const { return "xml"; } diff --git a/tools/qdoc3/webxmlgenerator.h b/tools/qdoc3/webxmlgenerator.h index 3145d50..cadf176 100644 --- a/tools/qdoc3/webxmlgenerator.h +++ b/tools/qdoc3/webxmlgenerator.h @@ -69,7 +69,7 @@ protected: const Node *relative, CodeMarker *marker ); virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker); - virtual QString fileExtension(const Node *node); + virtual QString fileExtension(const Node *node) const; virtual const Atom *addAtomElements(QXmlStreamWriter &writer, const Atom *atom, const Node *relative, CodeMarker *marker); -- cgit v0.12 From 9a83bf2676dabdf36f9ca491b480b50d8e7ed93d Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 10 Feb 2010 14:58:00 +0100 Subject: qdoc3: Fixed bug in creation of qt.pageindex. Task: QTBUG-7877 --- tools/qdoc3/htmlgenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index b1642df..27716a4 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -4364,7 +4364,7 @@ bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, if (node->pageType() == Node::NoPageType) return false; if (node->name().isEmpty()) - return false; + return true; if (node->access() == Node::Private) return false; -- cgit v0.12 From 689dba5dde34da15b954d21951e4066b3e29b208 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Wed, 10 Feb 2010 16:49:36 +0100 Subject: Doc: Added the qdoc manual to the repository for future maintenance. Reviewed-by: Trust Me --- tools/qdoc3/doc/classic.css | 284 + tools/qdoc3/doc/examples/layoutmanagement.qdocinc | 13 + tools/qdoc3/doc/examples/main.cpp | 13 + tools/qdoc3/doc/examples/minimum.qdocconf | 42 + tools/qdoc3/doc/examples/objectmodel.qdocinc | 11 + tools/qdoc3/doc/examples/signalandslots.qdocinc | 9 + tools/qdoc3/doc/files/compat.qdocconf | 31 + tools/qdoc3/doc/files/qt.qdocconf | 115 + tools/qdoc3/doc/images/happy.gif | Bin 0 -> 11526 bytes tools/qdoc3/doc/images/happyguy.jpg | Bin 0 -> 53442 bytes tools/qdoc3/doc/images/qt-logo.png | Bin 0 -> 5149 bytes tools/qdoc3/doc/images/training.jpg | Bin 0 -> 8368 bytes tools/qdoc3/doc/qdoc-manual.qdoc | 8695 +++++++++++++++++++++ tools/qdoc3/doc/qdoc-manual.qdocconf | 49 + 14 files changed, 9262 insertions(+) create mode 100644 tools/qdoc3/doc/classic.css create mode 100644 tools/qdoc3/doc/examples/layoutmanagement.qdocinc create mode 100644 tools/qdoc3/doc/examples/main.cpp create mode 100644 tools/qdoc3/doc/examples/minimum.qdocconf create mode 100644 tools/qdoc3/doc/examples/objectmodel.qdocinc create mode 100644 tools/qdoc3/doc/examples/signalandslots.qdocinc create mode 100644 tools/qdoc3/doc/files/compat.qdocconf create mode 100644 tools/qdoc3/doc/files/qt.qdocconf create mode 100644 tools/qdoc3/doc/images/happy.gif create mode 100644 tools/qdoc3/doc/images/happyguy.jpg create mode 100644 tools/qdoc3/doc/images/qt-logo.png create mode 100644 tools/qdoc3/doc/images/training.jpg create mode 100644 tools/qdoc3/doc/qdoc-manual.qdoc create mode 100644 tools/qdoc3/doc/qdoc-manual.qdocconf diff --git a/tools/qdoc3/doc/classic.css b/tools/qdoc3/doc/classic.css new file mode 100644 index 0000000..b8cae8e --- /dev/null +++ b/tools/qdoc3/doc/classic.css @@ -0,0 +1,284 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Arial, Geneva, Helvetica, sans-serif; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} + +h3.fn,span.fn +{ + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 0px 6px 10px; + margin: 42px 0px 0px 0px; +} + +hr { + border: 0; + color: #a0a0a0; + background-color: #ccc; + height: 1px; + width: 100%; + text-align: left; + margin: 34px 0px 34px 0px; +} + +table.valuelist { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-color: #dddddd; + border-collapse: collapse; + background-color: #f0f0f0; +} + +table.indextable { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; + font-size: 100%; +} + +table td.largeindex { + border-width: 1px 1px 1px 1px; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; + font-size: 120%; +} + +table.valuelist th { + border-width: 1px 1px 1px 2px; + padding: 4px; + border-style: solid; + border-color: #666; + color:white; + background-color:#666; +} + +th.titleheader { + border-width: 1px 0px 1px 0px; + padding: 2px; + border-style: solid; + border-color: #666; + color:white; + background-color:#555; + background-image:url('images/gradient.png')}; + background-repeat: repeat-x; + font-size: 100%; +} + + +th.largeheader { + border-width: 1px 0px 1px 0px; + padding: 4px; + border-style: solid; + border-color: #444; + color:white; + background-color:#555555; + font-size: 120%; +} + +p { + + margin-left: 4px; + margin-top: 8px; + margin-bottom: 8px; +} + +a:link +{ + color: #0046ad; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +a.obsolete +{ + color: #661100; + text-decoration: none +} + +a.compat +{ + color: #661100; + text-decoration: none +} + +a.obsolete:visited +{ + color: #995500; + text-decoration: none +} + +a.compat:visited +{ + color: #995500; + text-decoration: none +} + +body +{ + background: #ffffff; + color: black +} + +table.generic, table.annotated +{ + border-width: 1px; + border-color:#bbb; + border-style:solid; + border-collapse:collapse; +} + +table td.memItemLeft { + width: 180px; + padding: 2px 0px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; + white-space: nowrap +} + +table td.memItemRight { + padding: 2px 8px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; +} + +table tr.odd { + background: #f0f0f0; + color: black; +} + +table tr.even { + background: #e4e4e4; + color: black; +} + +table.annotated th { + padding: 3px; + text-align: left +} + +table.annotated td { + padding: 3px; +} + +table tr pre +{ + padding-top: 0px; + padding-bottom: 0px; + padding-left: 0px; + padding-right: 0px; + border: none; + background: none +} + +tr.qt-style +{ + background: #96E066; + color: black +} + +body pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +table tr.qt-code pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +span.preprocessor, span.preprocessor a +{ + color: darkblue; +} + +span.comment +{ + color: darkred; + font-style: italic +} + +span.string,span.char +{ + color: darkgreen; +} + +.title +{ + text-align: center +} + +.subtitle +{ + font-size: 0.8em +} + +.small-subtitle +{ + font-size: 0.65em +} + +.qmlitem { + padding: 0; +} + +.qmlname { + white-space: nowrap; +} + +.qmltype { + text-align: center; + font-size: 160%; +} + +.qmlproto { + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 10px 6px 10px; + margin: 42px 0px 0px 0px; +} + +.qmlreadonly { + float: right; + color: red +} + +.qmldoc { +} + +*.qmlitem p { +} diff --git a/tools/qdoc3/doc/examples/layoutmanagement.qdocinc b/tools/qdoc3/doc/examples/layoutmanagement.qdocinc new file mode 100644 index 0000000..01f8acf --- /dev/null +++ b/tools/qdoc3/doc/examples/layoutmanagement.qdocinc @@ -0,0 +1,13 @@ +\section1 Layout Classes + +The Qt layout system provides a simple and powerful way of specifying +the layout of child widgets. + +By specifying the logical layout once, you get the following benefits: + +\list + \o Positioning of child widgets. + \o Sensible default sizes for windows. + \o Sensible minimum sizes for windows. + \o ... +\endlist diff --git a/tools/qdoc3/doc/examples/main.cpp b/tools/qdoc3/doc/examples/main.cpp new file mode 100644 index 0000000..b777754 --- /dev/null +++ b/tools/qdoc3/doc/examples/main.cpp @@ -0,0 +1,13 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QPushButton *hello("Hello world!"); + hello.resize(100, 30); + + hello.show(); + return app.exec(); +} diff --git a/tools/qdoc3/doc/examples/minimum.qdocconf b/tools/qdoc3/doc/examples/minimum.qdocconf new file mode 100644 index 0000000..e5e9e67 --- /dev/null +++ b/tools/qdoc3/doc/examples/minimum.qdocconf @@ -0,0 +1,42 @@ +# QDoc is a tool that constantly evolves to suit our needs, +# and there are some compatibility issues between old and new +# practices. For that reason, any QDoc configuration file needs to +# include compat.qdocconf. + +#include(compat.qdocconf) + + +# The outputdir variable specifies the directory +# where QDoc will put the generated documentation. + +outputdir = html + + +# The headerdirs variable specifies the directories +# containing the header files associated +# with the .cpp source files used in the documentation. + +headerdirs = . + + +# The sourcedirs variable specifies the +# directories containing the .cpp or .qdoc +# files used in the documentation. + +#sourcedirs = . + + +# The exampledirs variable specifies the directories containing +# the source code of the example files. + +exampledirs = . + + +# The imagedirs variable specifies the +# directories containing the images used in the documentation. + +imagedirs = ./images + + + + diff --git a/tools/qdoc3/doc/examples/objectmodel.qdocinc b/tools/qdoc3/doc/examples/objectmodel.qdocinc new file mode 100644 index 0000000..02b5991 --- /dev/null +++ b/tools/qdoc3/doc/examples/objectmodel.qdocinc @@ -0,0 +1,11 @@ +\section1 Qt Object Model + +The standard C++ object model provides very efficient runtime support +for the object paradigm. But its static nature is inflexibile in +certain problem domains. Graphical user interface programming is a +domain that requires both runtime efficiency and a high level of +flexibility. Qt provides this, by combining the speed of C++ with the +flexibility of the Qt Object Model. + +... + diff --git a/tools/qdoc3/doc/examples/signalandslots.qdocinc b/tools/qdoc3/doc/examples/signalandslots.qdocinc new file mode 100644 index 0000000..cfae43a --- /dev/null +++ b/tools/qdoc3/doc/examples/signalandslots.qdocinc @@ -0,0 +1,9 @@ +\section1 Signals and Slots + +Signals and slots are used for communication between objects. The signals and +slots mechanism is a central feature of Qt and probably the part that differs +most from the features provided by other frameworks. + +\section2 Introduction + +In GUI programming, when we ... diff --git a/tools/qdoc3/doc/files/compat.qdocconf b/tools/qdoc3/doc/files/compat.qdocconf new file mode 100644 index 0000000..5745ed9 --- /dev/null +++ b/tools/qdoc3/doc/files/compat.qdocconf @@ -0,0 +1,31 @@ +alias.i = e +alias.include = input + +macro.0 = "\\\\0" +macro.b = "\\\\b" +macro.n = "\\\\n" +macro.r = "\\\\r" +macro.i = "\\o" +macro.i11 = "\\o{1,1}" +macro.i12 = "\\o{1,2}" +macro.i13 = "\\o{1,3}" +macro.i14 = "\\o{1,4}" +macro.i15 = "\\o{1,5}" +macro.i16 = "\\o{1,6}" +macro.i17 = "\\o{1,7}" +macro.i18 = "\\o{1,8}" +macro.i19 = "\\o{1,9}" +macro.i21 = "\\o{2,1}" +macro.i31 = "\\o{3,1}" +macro.i41 = "\\o{4,1}" +macro.i51 = "\\o{5,1}" +macro.i61 = "\\o{6,1}" +macro.i71 = "\\o{7,1}" +macro.i81 = "\\o{8,1}" +macro.i91 = "\\o{9,1}" +macro.img = "\\image" +macro.endquote = "\\endquotation" +macro.relatesto = "\\relates" + +spurious = "Missing comma in .*" \ + "Missing pattern .*" diff --git a/tools/qdoc3/doc/files/qt.qdocconf b/tools/qdoc3/doc/files/qt.qdocconf new file mode 100644 index 0000000..942d023 --- /dev/null +++ b/tools/qdoc3/doc/files/qt.qdocconf @@ -0,0 +1,115 @@ +include(compat.qdocconf) +include(macros.qdocconf) +include(qt-cpp-ignore.qdocconf) +include(qt-html-templates.qdocconf) +include(qt-defines.qdocconf) + +project = Qt +versionsym = +version = %VERSION% +description = Qt Reference Documentation +url = http://qt.nokia.com/doc/4.6 + +edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ + QtXmlPatterns QtTest +edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \ + QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \ + QtDesigner QtAssistant QAxContainer Phonon \ + QAxServer QtUiTools QtTest QtDBus +edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest +edition.DesktopLight.groups = -graphicsview-api + +qhp.projects = Qt + +qhp.Qt.file = qt.qhp +qhp.Qt.namespace = com.trolltech.qt.460 +qhp.Qt.virtualFolder = qdoc +qhp.Qt.indexTitle = Qt Reference Documentation +qhp.Qt.indexRoot = + +# Files not referenced in any qdoc file (last four are needed by qtdemo) +# See also extraimages.HTML +qhp.Qt.extraFiles = classic.css \ + images/qt-logo.png \ + images/taskmenuextension-example.png \ + images/coloreditorfactoryimage.png \ + images/dynamiclayouts-example.png \ + images/stylesheet-coffee-plastique.png + +qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.6.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0 +qhp.Qt.subprojects = classes overviews examples +qhp.Qt.subprojects.classes.title = Classes +qhp.Qt.subprojects.classes.indexTitle = Qt's Classes +qhp.Qt.subprojects.classes.selectors = class fake:headerfile +qhp.Qt.subprojects.classes.sortPages = true +qhp.Qt.subprojects.overviews.title = Overviews +qhp.Qt.subprojects.overviews.indexTitle = All Overviews and HOWTOs +qhp.Qt.subprojects.overviews.selectors = fake:page,group,module +qhp.Qt.subprojects.examples.title = Tutorials and Examples +qhp.Qt.subprojects.examples.indexTitle = Qt Examples +qhp.Qt.subprojects.examples.selectors = fake:example + +language = Cpp + +headerdirs = $QTDIR/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/tools/assistant/lib \ + $QTDIR/tools/assistant/compat/lib \ + $QTDIR/tools/designer/src/uitools \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib \ + $QTDIR/tools/qtestlib/src \ + $QTDIR/tools/qdbus/src +sourcedirs = $QTDIR/src \ + $QTDIR/doc/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/tools/assistant/lib \ + $QTDIR/tools/assistant/compat/lib \ + $QTDIR/tools/designer/src/uitools \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib \ + $QTDIR/tools/qtestlib/src \ + $QTDIR/tools/qdbus + +excludedirs = $QTDIR/src/3rdparty/clucene \ + $QTDIR/src/3rdparty/des \ + $QTDIR/src/3rdparty/freetype \ + $QTDIR/src/3rdparty/harfbuzz \ + $QTDIR/src/3rdparty/kdebase \ + $QTDIR/src/3rdparty/libjpeg \ + $QTDIR/src/3rdparty/libmng \ + $QTDIR/src/3rdparty/libpng \ + $QTDIR/src/3rdparty/libtiff \ + $QTDIR/src/3rdparty/md4 \ + $QTDIR/src/3rdparty/md5 \ + $QTDIR/src/3rdparty/patches \ + $QTDIR/src/3rdparty/sha1 \ + $QTDIR/src/3rdparty/sqlite \ + $QTDIR/src/3rdparty/webkit/JavaScriptCore \ + $QTDIR/src/3rdparty/webkit/WebCore \ + $QTDIR/src/3rdparty/wintab \ + $QTDIR/src/3rdparty/zlib \ + $QTDIR/doc/src/snippets \ + $QTDIR/src/3rdparty/phonon/gstreamer \ + $QTDIR/src/3rdparty/phonon/ds9 \ + $QTDIR/src/3rdparty/phonon/qt7 \ + $QTDIR/src/3rdparty/phonon/waveout + +sources.fileextensions = "*.cpp *.qdoc *.mm" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp" + +exampledirs = $QTDIR/doc/src \ + $QTDIR/examples \ + $QTDIR/examples/tutorials \ + $QTDIR \ + $QTDIR/qmake/examples \ + $QTDIR/src/3rdparty/webkit/WebKit/qt/docs +imagedirs = $QTDIR/doc/src/images \ + $QTDIR/examples +outputdir = $QTDIR/doc/html +tagfile = $QTDIR/doc/html/qt.tags +base = file:$QTDIR/doc/html diff --git a/tools/qdoc3/doc/images/happy.gif b/tools/qdoc3/doc/images/happy.gif new file mode 100644 index 0000000..a4597f6 Binary files /dev/null and b/tools/qdoc3/doc/images/happy.gif differ diff --git a/tools/qdoc3/doc/images/happyguy.jpg b/tools/qdoc3/doc/images/happyguy.jpg new file mode 100644 index 0000000..e860479 Binary files /dev/null and b/tools/qdoc3/doc/images/happyguy.jpg differ diff --git a/tools/qdoc3/doc/images/qt-logo.png b/tools/qdoc3/doc/images/qt-logo.png new file mode 100644 index 0000000..14ddf2a Binary files /dev/null and b/tools/qdoc3/doc/images/qt-logo.png differ diff --git a/tools/qdoc3/doc/images/training.jpg b/tools/qdoc3/doc/images/training.jpg new file mode 100644 index 0000000..c2ce5c3 Binary files /dev/null and b/tools/qdoc3/doc/images/training.jpg differ diff --git a/tools/qdoc3/doc/qdoc-manual.qdoc b/tools/qdoc3/doc/qdoc-manual.qdoc new file mode 100644 index 0000000..e2f670c --- /dev/null +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -0,0 +1,8695 @@ +/**************************************************************************** +** +** 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 documentation 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$ +** +****************************************************************************/ + +/*! + \page index.html + \nextpage QDoc Manual + + \title QDoc Manual - Table of Contents + + \list + \o \l{QDoc Manual} + \o \l{QDoc Commands} + \list + \o \l{Markup Commands} + \o \l{Text Formatting Commands} + \o \l{Document Structuring Commands} + \o \l{Verbatim Code Commands} + \o \l{Quoting External Code Commands} + \list + \o \l{Example File} + \endlist + \o \l{Linking Commands} + \o \l{Graphic Commands} + \o \l{Container Commands} + \o \l{Document Contents Commands} + \o \l{Miscellaneous Commands} + \list + \o \l{signalandslots.qdocinc} + \o \l{objectmodel.qdocinc} + \o \l{layoutmanagement.qdocinc} + \endlist + \o \l{Topical Commands} + \o \l{Contextual Commands} + \o \l{Navigation Commands} + \o \l{Status Commands} + \o \l{Thread Support Commands} + \o \l{Relating Commands} + \o \l{Grouping Commands} + \o \l{Title Commands} + \endlist + \o \l{QDoc Configuration} + \list + \o \l{General Variables} + \o \l{Creating Help Project Files} + \o \l{C++ Specific Variables} + \o \l{HTML Specific Variables} + \o \l{Supporting Derived Projects} + \o \l{QDoc Compatibility} + \o \l{qt.qdocconf} + \o \l{minimum.qdocconf} + \endlist + \o \l{QDoc Commands - Alphabetical List} + \endlist +*/ + +/*! + \page 01-qdoc-manual.html + \contentspage QDoc Manual - Table of Contents + \previouspage QDoc Manual - Table of Contents + \nextpage QDoc Commands + + \title QDoc Manual + + QDoc is the internal tool used by Qt Development Frameworks for generating + documentation. This document is a reference for QDoc command syntax and + configuration. + + \section1 Overview + + \list I + \o \section2 \l {QDoc Commands} + + \l {QDoc Commands - Alphabetical List}{A complete alphabetical + list}. + + There are two main categories of commands for QDoc: markup + commands and meta-commands. + + The markup commands indicate the generated documentation's + appearance and logical structure. The meta-commands provide + information about the document as well as the documented + item. The meta-commands can be further categorized as topical + commands and contextual commands. + + \list + \o \l {Markup Commands} + \list + \o \l {Text Formatting Commands}{Text Formatting} + \o \l {Document Structuring Commands}{Document Structuring} + \o \l {Verbatim Code Commands}{Verbatim Code} + \o \l {Quoting External Code Commands}{Quoting External Code} + \o \l {Linking Commands}{Linking} + \o \l {Graphic Commands}{Graphic} + \o \l {Container Commands}{Container} + \o \l {Document Contents Commands}{Document Contents} + \o \l {Miscellaneous Commands}{Miscellaneous} + \endlist + \o \l {Topical Commands} + \o \l {Contextual Commands} + \list + \o \l {Navigation Commands}{Navigation} + \o \l {Status Commands}{Status} + \o \l {Thread Support Commands}{Thread Support} + \o \l {Relating Commands}{Relating} + \o \l {Grouping Commands}{Grouping} + \o \l {Title Commands}{Title} + \endlist + \endlist + \endlist + + \list II + \o \section2 \l {QDoc Configuration} + + When running QDoc to generate the documentation, you must + specify a configuration file on the command line. The + configuration file is a list of entries of entries of the form + "variable = value". + + \list + \o \l {Configuration Variables} + \o \l {Configuration File Examples} + \endlist + + Some particular configuration variables allow you to use QDoc + to support Qt-based projects; i.e to make projects, such as Qt + Solutions, contain references to the online Qt documentation. + + \list + \o \l {Supporting Derived Projects} + \endlist + + QDoc is a tool that constantly evolves to suit our needs, for + that reason there are some compatibility issues between old and + new practices. + + \list + \o \l {QDoc Compatibility} + \endlist + \endlist +*/ + +/*! + \page 02-qdoc-commands.html + \previouspage QDoc Manual + \contentspage QDoc Manual - Table of Contents + \nextpage Markup Commands + + \title QDoc Commands + + There are two main categories of commands for QDoc: markup + commands and meta-commands. + + The markup commands indicate the generated documentation's visual + appearance and logical structure. The meta-commands provide + information about the documentation unit as well as the documented + item. The meta-commands can be further categorized as topical + commands and contextual commands. + + \section1 Alphabetical List + + A complete \l{QDoc Commands - Alphabetical List } + {alphabetical list of the QDoc commands}. + + \section1 Categories + + \list + \o \l {Markup Commands} + \o \l {Topical Commands} + \o \l {Contextual Commands} + \endlist +*/ + +/*! + \page 03-qdoc-commands-markup.html + \contentspage QDoc Manual - Table of Contents + \previouspage QDoc Commands + \nextpage Text Formatting Commands + + \title Markup Commands + + The markup commands indicate the generated documentation's visual + appearance and logical structure. + + \section1 Alphabetical List + + \l {04-qdoc-commands-textformatting.html#backslash}{\\\\}, + \l {04-qdoc-commands-textformatting.html#a}{\\a}, + \l {11-qdoc-commands-documentcontents.html#abstract}{\\abstract}, + \l {06-qdoc-commands-verbatimcode.html#badcode}{\\badcode}, + \l {04-qdoc-commands-textformatting.html#bold}{\\bold}, + \l {11-qdoc-commands-documentcontents.html#brief}{\\brief}, + \l {04-qdoc-commands-textformatting.html#c}{\\c}, + \l {09-qdoc-commands-graphic.html#caption}{\\caption}, + \l {05-qdoc-commands-documentstructuring.html#chapter}{\\chapter}, + \l {06-qdoc-commands-verbatimcode.html#code}{\\code}, + \l {07-0-qdoc-commands-quoting.html#codeline}{\\codeline}, + \l {07-0-qdoc-commands-quoting.html#dots}{\\dots}, + \l {12-0-qdoc-commands-miscellaneous.html#else}{\\else}, + \l {12-0-qdoc-commands-miscellaneous.html#endif}{\\endif}, + \l {12-0-qdoc-commands-miscellaneous.html#expire}{\\expire}, + \l {11-qdoc-commands-documentcontents.html#footnote}{\\footnote}, + \l {12-0-qdoc-commands-miscellaneous.html#generatelist}{\\generatelist}, + \l {10-qdoc-commands-container.html#header}{\\header}, + \l {04-qdoc-commands-textformatting.html#i}{\\i}, + \l {12-0-qdoc-commands-miscellaneous.html#if}{\\if}, + \l {09-qdoc-commands-graphic.html#image}{\\image}, + \l {12-0-qdoc-commands-miscellaneous.html#include}{\\include}, + \l {09-qdoc-commands-graphic.html#inlineimage}{\\inlineimage}, + \l {08-qdoc-commands-linking.html#keyword}{\\keyword}, + \l {08-qdoc-commands-linking.html#l}{\\l}, + \l {11-qdoc-commands-documentcontents.html#legalese}{\\legalese}, + \l {10-qdoc-commands-container.html#list}{\\list}, + \l {12-0-qdoc-commands-miscellaneous.html#meta}{\\meta}, + \l {06-qdoc-commands-verbatimcode.html#newcode}{\\newcode}, + \l {10-qdoc-commands-container.html#o}{\\o}, + \l {06-qdoc-commands-verbatimcode.html#oldcode}{\\oldcode}, + \l {12-0-qdoc-commands-miscellaneous.html#omit}{\\omit}, + \l {05-qdoc-commands-documentstructuring.html#part}{\\part}, + \l {07-0-qdoc-commands-quoting.html#printline}{\\printline}, + \l {07-0-qdoc-commands-quoting.html#printto}{\\printto}, + \l {07-0-qdoc-commands-quoting.html#printuntil}{\\printuntil}, + \l {11-qdoc-commands-documentcontents.html#quotation}{\\quotation}, + \l {07-0-qdoc-commands-quoting.html#quotefile}{\\quotefile}, + \l {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\raw}, + \l {10-qdoc-commands-container.html#row}{\\row}, + \l {08-qdoc-commands-linking.html#sa}{\\sa}, + \l {05-qdoc-commands-documentstructuring.html#sectionOne}{\\section1}, + \l {05-qdoc-commands-documentstructuring.html#sectionTwo}{\\section2}, + \l {05-qdoc-commands-documentstructuring.html#sectionThree}{\\section3}, + \l {05-qdoc-commands-documentstructuring.html#sectionFour}{\\section4}, + \l {07-0-qdoc-commands-quoting.html#skipline}{\\skipline}, + \l {07-0-qdoc-commands-quoting.html#skipto}{\\skipto}, + \l {07-0-qdoc-commands-quoting.html#skipuntil}{\\skipuntil}, + \l {07-0-qdoc-commands-quoting.html#snippet}{\\snippet}, + \l {04-qdoc-commands-textformatting.html#sub}{\\sub}, + \l {04-qdoc-commands-textformatting.html#sup}{\\sup}, + \l {10-qdoc-commands-container.html#table}{\\table}, + \l {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents}, + \l {08-qdoc-commands-linking.html#target}{\\target}, + \l {04-qdoc-commands-textformatting.html#tt}{\\tt}, + \l {04-qdoc-commands-textformatting.html#underline}{\\underline}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\unicode}, + \l {11-qdoc-commands-documentcontents.html#warning}{\\warning} + + \section1 Categories + \list + \o \l {Text Formatting Commands} + \o \l {Document Structuring Commands} + \o \l {Verbatim Code Commands} + \o \l {Quoting External Code Commands} + \o \l {Linking Commands} + \o \l {Graphic Commands} + \o \l {Container Commands} + \o \l {Document Contents Commands} + \o \l {Miscellaneous Commands} + \endlist + +*/ + +/*! + \page 04-qdoc-commands-textformatting.html + \contentspage QDoc Manual - Table of Contents + \previouspage Markup Commands + \nextpage Document Structuring Commands + + \title Text Formatting Commands + + The text formatting commands indicate how the regular text in the + documentation is rendered. + + \section1 Alphabetical List + + \l {04-qdoc-commands-textformatting.html#backslash}{\\\\}, + \l {04-qdoc-commands-textformatting.html#a}{\\a}, + \l {04-qdoc-commands-textformatting.html#bold}{\\bold}, + \l {04-qdoc-commands-textformatting.html#c}{\\c}, + \l {04-qdoc-commands-textformatting.html#i}{\\i}, + \l {04-qdoc-commands-textformatting.html#sub}{\\sub}, + \l {04-qdoc-commands-textformatting.html#sup}{\\sup}, + \l {04-qdoc-commands-textformatting.html#tt}{\\tt}, + \l {04-qdoc-commands-textformatting.html#underline}{\\underline} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + + \o \bold \\\\ \target backslash + \o \bold {The \\\\ command expands to a single backslash.} + + QDoc commands always start with a backslash alone. To + display an actual backslash in the text you need to type + two of the kind. If you want to display two backslashes, + you need to type four, and so forth. For example: + + \code + / *! + The \\\\ command is useful if you want a + backslash to appear verbatim, for example, + writing C:\\windows\\home\\. + * / + \endcode + + will be rendered as + + \quotation + The \\\\ command is useful if you want a + backslash to appear verbatim, for example, + writing C:\\windows\\home\\. + \endquotation + + However, if you want your text to appear in a typewriter + font as well, you can use the \l {c}{\\c} command instead, + which accepts and renders the backslash as any other + character. For example: + + \code + / *! + The \\c command is useful if you want a + backslash to appear verbatim, and the word + that contains it written in a typewriter font, + like this: \c {C:\windows\home\}. + * / + \endcode + + will be rendered as + + \quotation + The \\c command is useful if you want a + backslash to appear verbatim, and the word + that contains it written in a typewriter font, + like this: \c {C:\windows\home\}. + \endquotation + + \row + \o \bold \\a \target a + \o \bold {The \\a command indicates that the next word + is a parameter when documenting functions.} + + Warnings are emitted when function parameters are + undocumented or misspelled, so whenever you write + documentation for functions you should make sure you + mention all the parameters and precede each of these by the + \\a command. The parameter is then rendered in italic. For + example: + + \code + / *! + Constructs a line edit containing the text + \a contents. + + The \a parent parameter is sent to the + QWidget constructor. + * / + + QLineEdit::QLineEdit(const QString &contents, QWidget *parent) + :QWidget(parent) + { + ... + } + + \endcode + + will be rendered as + + \quotation + \bold {QLineEdit::QLineEdit ( const QString & + contents, QWidget *parent )} + + Constructs a line edit containing the text \a contents. + + The \a parent parameter is sent to the QWidget + constructor. + + \endquotation + + The \\a command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. However, a parameter + is always a single word, so braces are rarely + necessary. And for the same reason, parentheses seldom + occur. + + \row + \o \bold \\c \target c + \o \bold {The \\c command can be used to render variables, + user-defined classes and C++ keywords like \c int, + \c for, etc.} + + The command renders its argument using a typewriter font. For + example: + + \code + / *! + The \c AnalogClock class provides a clock widget with hour + and minute hands that is automatically updated every + few seconds. + * / + \endcode + + will be rendered as + + \quotation + The \c AnalogClock class provides a clock widget with hour + and minute hands that is automatically updated every + few seconds. + \endquotation + + The \\c command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + The \\c command accepts the special character \c \ within + its argument, i.e. it renders it as a normal character. So + if you want to use nested commands, you must use the \l + {tt}{teletype (\\tt)} command instead. + + See also \l {tt}{\\tt} and \l {code}{\\code}. + + \row + \o \bold \\tt \target tt + \o \bold {The \\tt command can be used to render variables, + user-defined classes and C++ keywords like \c int, \c + for, etc.} + + The \\tt command behaves just like the \l {c}{\\c} command, + except that \\tt parses QDoc commands (like \l {i}{\\i}, \l + {bold}{\\bold} and \l {underline}{\\underline}) contained + within its argument. + + The command renders its argument using a monospace + font. For example: + + \code + / *! + After \c setupUi() populates the main container with + child widgets it scans the main container's list of + slots for names with the form + \tt{on_\i{objectName}_\i{signalName}().} + * / + \endcode + + will be rendered as + + \quotation + After \c setupUi() populates the main container with + child widgets it scans the main container's list of + slots for names with the form + \tt{on_\i{objectName}_\i{signalName}().} + \endquotation + + The \\tt command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + See also \l {c}{\\c}. + + \row + \o \bold \\bold \target bold + \o \bold {The \\bold command renders its argument using + a bold font.} + + For example: + + \code + / *! + This is regular text; \bold {this text is + rendered using the \\bold command}. + * / + \endcode + + will be rendered as + + \quotation + This is regular text; \bold {this text is rendered using + the \\bold command}. + \endquotation + + The command follows the same conventions as the \l {i}{\\i} + command for \l {argument}{punctuation, parentheses and use + of braces} for the argument. + + \row + \o \bold \\i \target i + \o \bold {The \\i command renders its argument in italic.} + + \warning This is preliminary functionality. For + more information, see the \l + {26-qdoc-commands-compatibility.html#i-versus-e}{compatibility} + section. + + \target argument + Normally, a command argument ends at the next whitespace [1], + but braces can be used to group words [2]. For example: + + \code + / *! + Here, we render \i {a few words} in italic. + * / + \endcode + + will be rendered as + + \quotation + Here, we render \i {a few words} in italic. + \endquotation + + If you want to use other QDoc commands within an argument + that contains spaces, you always need to enclose the + argument with braces. But QDoc is smart enough to count + parentheses [3], so you don't need braces in cases like this: + + \code + / *! + An argument can sometimes contain whitespaces, + for example: \i QPushButton(tr("A Brand New Button")) + * / + \endcode + + will be rendered as + + \quotation + An argument can sometimes contain whitespaces, + for example: \i QPushButton(tr("A Brand New Button")) + \endquotation + + Finally, trailing punctuation is not included in an + argument [4], nor is 's [5] + + \raw HTML + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    QDoc SyntaxGenerated Documentation
    1A variation of a command button is a \i menu + button.A variation of a command button is a menu + button.
    2The QPushButton widget provides a + \i {command button}.The QPushButton widget provides a + command button.
    3Another class of buttons are option buttons + \i (see QRadioButton).Another class of buttons are option buttons + (see QRadioButton).
    4A push button emits the signal \i clicked().A push button emits the signal clicked().
    5The \i QPushButton's checked property is + false by default.The QPushButton's checked property is + false by default.
    + \endraw + + \row + \o \bold \\sub \target sub + \o \bold {The \\sub command renders its argument lower + than the baseline of the regular text, using a smaller font.} + + For example: + + \code + / *! + Definition (Range): Consider the sequence + {x\sub n}\sub {n > 1} . The set + + {x\sub 2, x\sub 3, x\sub 4, ...} = {x\sub n ; n = 2, 3, 4, ...} + + is called the range of the sequence. + * / + \endcode + + will be rendered as + + \quotation + Definition (Range): Consider the sequence + {x\sub n}\sub {n > 1} . The set + + {x\sub 2, x\sub 3, x\sub 4, ...} = {x\sub n ; n = 2, 3, 4, ...} + + is called the range of the sequence. + \endquotation + + The \\sub command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + \row + \o \bold \\sup \target sup + \o \bold {The \\sup command renders its argument higher than + the baseline of the regular text, using a smaller font.} + + For example: + + \code + / *! + The series + + 1 + a + a\sup 2 + a\sup 3 + a\sup 4 + ... + + is called the \i {geometric series}. + * / + \endcode + + will be rendered as + + \quotation + The series + + 1 + a + a\sup 2 + a\sup 3 + a\sup 4 + ... + + is called the \i {geometric series}. + \endquotation + + The \\sup command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation, parentheses + and use of braces} for the argument. + + \row + \o \bold \\underline \target underline + \o \bold {The \\underline command renders its argument underlined.} + + For example: + + \code + / *! + The \underline {F}ile menu gives the users the possibility + to open, and edit, an existing file, save a new or modified + file, and exit the application. + * / + \endcode + + will be rendered as + + \quotation + The \underline {F}ile menu gives the users the possibility + to open, and edit, an existing file, save a new or modified + file, and exit the application. + \endquotation + + The \\underline command follows the same conventions as the + \l {i}{\\i} command for \l {argument}{punctuation, + parentheses and use of braces} for the argument. \endtable +*/ + +/*! + \page 05-qdoc-commands-documentstructuring.html + \previouspage Text Formatting Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Verbatim Code Commands + + \title Document Structuring Commands + + The document structuring commands divide the documentation into + sections. In total, there are six levels of sections in QDoc: \c + \part, \c \chapter, \c \section1, \c \section2, \c \section3 and + \c \section4. \c \section1 to \c \section4 correspond to the + traditional section, subsection, subsubsection and + subsubsubsection. + + \section1 Alphabetical List + + \l {05-qdoc-commands-documentstructuring.html#chapter}{\\chapter}, + \l {05-qdoc-commands-documentstructuring.html#part}{\\part}, + \l {05-qdoc-commands-documentstructuring.html#sectionOne}{\\section1}, + \l {05-qdoc-commands-documentstructuring.html#sectionTwo}{\\section2}, + \l {05-qdoc-commands-documentstructuring.html#sectionThree}{\\section3}, + \l {05-qdoc-commands-documentstructuring.html#sectionFour}{\\section4} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\part \target part + \o \bold {The \\part command is intended for use in + larger documents, and divides the document into parts.} + + In general a document structuring command considers + everything that follows it until the first line break as + its argument. The argument is rendered as the unit's + title. If the title needs to be spanned over several lines, + make sure that each line (except the last one) is ended + with a backslash. + + In total, there are six levels of sections in QDoc: \c + \part, \c \chapter, \c \section1, \c \section2, \c + \section3 and \c \section4. \c \section1 to \c \section4 + correspond to the traditional section, subsection, + subsubsection and subsubsubsection. + + There is a strict ordering of the section units: + + \code + part + | + chapter + | + section1 + | + section2 + | + section3 + | + section4 + \endcode + + For example, a \c section1 unit can only appear as the top + level section or inside a \c chapter unit. Skipping a + section unit, for example from \c part to \c section1, is + not allowed. + + You can \i begin with either of the three: \c part, \c + chapter or \c section1. For example: + + + \code + / *! + \part Basic Qt + + This is the first part. + + + \chapter Getting Started + + This is the first part's first chapter. + + + \section1 Hello Qt + + This is the first chapter's first section. + + + \section1 Making Connections + + This is the first chapter's second section. + + + \section1 Using the Reference Documentation + + This is the first chapter's third section. + + + \chapter Creating Dialogs + + This is the first part's second chapter. + + + \section1 Subclassing QDialog + + This is the second chapter's first section. + + ... + + + \part Intermediate Qt + + This is the second part. + + + \chapter Layout Management + + This is the second part's first chapter. + + + \section1 Basic Layouts + + This is the first chapter's first section. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + +

    Basic Qt

    +
    +

    This is the first part.

    + + +

    Getting Started

    +
    + This is the first part's first chapter.

    + + +

    Hello Qt

    +
    +

    This is the first chapter's first section.

    + + +

    Making Connections

    +
    +

    This is the first chapter's second section.

    + + +

    Using the Reference Documentation

    +
    +

    This is the first chapter's third section.

    + + +

    Creating Dialogs

    +
    +

    This is the first part's second chapter.

    + + +

    Subclassing QDialog

    +
    +

    This is the second chapter's first section.

    + + ... + + +

    Intermediate Qt

    +
    +

    This is the second part.

    + + +

    Layout Management

    +
    +

    This is the second part's first chapter.

    + + +

    Basic Layouts

    +
    +

    This is the first chapter's first section.

    + + ... + + \endraw + \endquotation + + Each section level is a logical unit within the + document. Its title will appear on the table of contents + generated by the \l + {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents} command. For example: + + \code + / *! + Contents: + + \tableofcontents + + ... + * / + \endcode + + will expand to + + \quotation + \raw HTML +

    Contents:

    + + + + ... + \endraw + \endquotation + + \row + \o \bold \\chapter \target chapter + \o \bold {The \\chapter command is intended for use in + larger documents, and divides the document into chapters.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \row + \o \bold \\section1 \target sectionOne + \o \bold {The \\section1 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + \row + \o \bold \\section2 \target sectionTwo + \o \bold {The \\section2 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \row + \o \bold \\section3 \target sectionThree + \o \bold {The \\section3 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \row + \o \bold \\section4 \target sectionFour + \o \bold {The \\section4 command starts a new section.} + + See \l{part}{\\part} for an explanation of the various + section units, command argument and rendering. + + \endtable +*/ + +/*! + \page 06-qdoc-commands-verbatimcode.html + \previouspage Document Structuring Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Quoting External Code Commands + + \title Verbatim Code Commands + + The following commands are used to render verbatim code within the + documentation. The code is rendered on a new line, using a + typewriter font and the standard indentation. + + \bold{Note:} Although all of these commands can be used to present + C++ code, the \l{07-0-qdoc-commands-quoting.html#snippet}{\\snippet} + and \l{07-0-qdoc-commands-quoting.html#codeline}{\\codeline} commands + should be used in preference to + the others when presenting valid code. This allows auxilliary tools + for Qt language bindings to substitute the relevant code snippets in + place of the C++ ones. + + \section1 Alphabetical List + + \l {06-qdoc-commands-verbatimcode.html#badcode}{\\badcode}, + \l {06-qdoc-commands-verbatimcode.html#code}{\\code}, + \l {06-qdoc-commands-verbatimcode.html#newcode}{\\newcode}, + \l {06-qdoc-commands-verbatimcode.html#oldcode}{\\oldcode} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\code \target code + \o \bold {The \\code command and the corresponding + \\endcode command delimit a piece of verbatim code.} + + Whereas the \l {c}{\\c} command can be used for short code + fragments within a sentence, the \\code command is for + longer code snippets and renders the code verbatim in a + separate paragraph using a typewriter font and the standard + indentation. + + When processing any of the \\code, \l {badcode}{\\badcode}, + \l {newcode}{\\newcode} and \l {oldcode}{\\oldcode} + commands, QDoc basically removes all indentation that is + common for the verbatim code blocks within a \c{/}\c{*!} ... + \c{*}\c{/} comment before it adds the standard + indentation. For that reason the recommended style is to + use 8 spaces for the verbatim code contained within these + commands (note that this doesn't apply to externally + quoted code using the \l {quotefromfile}{\\quotefromfile} + or \l {quotefile}{\\quotefile} command). + + For example: + + \code + / *! + \code + #include + #include + + int main(int argc, char *argv[]) + { + ... + } + \ endcode + * / + \endcode + + will be rendered as + + \code + #include + #include + + int main(int argc, char *argv[]) + { + ... + } + \endcode + + Other QDoc commands are disabled within + \\code... \\endcode, and the special character '\\' is + accepted and rendered like the rest of the code. + + You need to type the code manually between the \\code and + \\endcode commands. If you want to include code snippets + from a particular file, use the \l + {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile} + command instead. + + See also \l {c}{\\c}, \l + {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile}, + \l {badcode}{\\badcode}, \l {newcode}{\\newcode} and \l + {oldcode}{\\oldcode}. + + \row + \o \bold \\badcode \target badcode + \o \bold {The \\badcode command and the corresponding + \\endcode command delimit a piece of code that doesn't + compile or is wrong for some other reason.} + + The \\badcode command is similar the \l {code}{\\code} + command, but renders the code using a grey font instead of + black (the default). + + Like the \l {code}{\\code} command, it renders its code on + a new line in the documentation using a typewriter font and + the standard indentation. For example: + + \code + / *! + The statement below is rendered using the + regular \\code command: + + \code + statusbar()->message(tr("Host %1 found").arg(hostName)); + \ endcode + + While the following statement is rendered using + the \\badcode command: + + \badcode + statusbar()->message(tr("Host" + hostName + " found")); + \ endcode + * / + \endcode + + will be rendered as + + \quotation + The statement below is rendered using the + regular \\code command: + + \code + statusbar()->message(tr("Host %1 found").arg(hostName)); + \endcode + + While the following statement is rendered using + the \\badcode command: + + \badcode + statusbar()->message(tr("Host" + hostName + " found")); + \endcode + \endquotation + + Other QDoc commands are disabled within + \\badcode... \\endcode, and the special character '\\' is + accepted and rendered like the rest of the code. + + See also \l {code}{\\code}, \l {newcode}{\\newcode} and \l + {oldcode}{\\oldcode}. + + \row + \o \bold \\newcode \target newcode + \o \bold {The \\newcode command, and the associated \\oldcode + and \\endcode commands, indicate how to port a piece of + code to a new version of an API.} + + The \\newcode command, and its companion the \\oldcode + command, is a convenience combination of the \l + {code}{\\code} and \l {badcode}{\\badcode} commands: The + combination provides a text relating the two code snippets + to each other. The command requires a preceding \\oldcode + statement. + + Like the \l {code}{\\code} and \l {badcode}{\\badcode} + commands, the \\newcode command renders its code on a new + line in the documentation using a typewriter font and the + standard indentation. For example: + + \code + / *! + \oldcode + if (printer->setup(parent)) + ... + \newcode + QPrintDialog dialog(printer, parent); + if (dialog.exec()) + ... + \ endcode + * / + \endcode + + is rendered like this: + + \quotation + \oldcode + if (printer->setup(parent)) + ... + \newcode + QPrintDialog dialog(printer, parent); + if (dialog.exec()) + ... + \endcode + \endquotation + + Other QDoc commands are disabled within + \\oldcode ... \\endcode, and the '\\' character doesn't need + to be escaped. + + \row + \o \bold \\oldcode \target oldcode + \o \bold {The \\oldcode command requires a corresponding + \\newcode statement; otherwise QDoc fails to parse the command + and emits a warning.} + + See also \l {newcode}{\\newcode} and \l {badcode}{\\badcode}. + \endtable +*/ + +/*! + \page 07-0-qdoc-commands-quoting.html + \previouspage Verbatim Code Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Linking Commands + + \title Quoting External Code Commands + + The following commands enable quoting from files in the + documentation: You can make QDoc include the complete contents of + a file, or you can quote specific parts of the file and skip + others. The typical use of the latter is to quote a file chunk by + chunk. + + \bold{Note:} Although all of these commands can be used to present + C++ code, the \l{#snippet}{\\snippet} and \l{#codeline}{\\codeline} + commands should be used in preference to + the others when presenting valid code. This allows auxilliary tools + for Qt language bindings to substitute the relevant code snippets in + place of the C++ ones. + + \section1 Alphabetical List + + \l {07-0-qdoc-commands-quoting.html#codeline}{\\codeline}, + \l {07-0-qdoc-commands-quoting.html#dots}{\\dots}, + \l {07-0-qdoc-commands-quoting.html#printline}{\\printline}, + \l {07-0-qdoc-commands-quoting.html#printto}{\\printto}, + \l {07-0-qdoc-commands-quoting.html#printuntil}{\\printuntil}, + \l {07-0-qdoc-commands-quoting.html#quotefile}{\\quotefile}, + \l {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile}, + \l {07-0-qdoc-commands-quoting.html#skipline}{\\skipline}, + \l {07-0-qdoc-commands-quoting.html#skipto}{\\skipto}, + \l {07-0-qdoc-commands-quoting.html#skipuntil}{\\skipuntil}, + \l {07-0-qdoc-commands-quoting.html#snippet}{\\snippet} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\quotefile \target quotefile + \o \bold {The \\quotefile command expands to the complete + contents of the file given as argument.} + + The command considers the rest of the line as part of its + argument, make sure to follow the file name with a line + break. + + The file's contents is rendered in a separate paragraph, + using a typewriter font and the standard indentation. The + code is shown verbatim. + + For example: + + \code + / *! + This is a simple "Hello world" example: + + \quotefile examples/main.cpp + + It contains only the bare minimum you need + to get a Qt application up and running. + * / + \endcode + + will be rendered as + + \quotation + This is a simple "Hello world" example: + + \quotefile examples/main.cpp + + It contains only the bare minimum you need to get a Qt + application up and running. + \endquotation + + \warning If you use the \l {QDoc + Compatibility}{compat.qdocconf} file this command is called + \\include. + + See also \l {quotefromfile}{\\quotefromfile} and \l + {code}{\\code}. + + \row + \o \bold \\quotefromfile \target quotefromfile + \o \bold {The \\quotefromfile command opens the file + given as argument for quoting.} + + The command considers the rest of the line as part of its + argument, make sure to follow the file name with a line + break. + + The command is intended for use when quoting parts from + file with the walkthrough commands: \l + {printline}{\\printline}, \l {printto}{\\printto}, \l + {printuntil}{\\printuntil}, \l {skipline}{\\skipline}, \l + {skipto}{\\skipto}, \l {skipuntil}{\\skipuntil}. This + enables you to quote specific portions of a file. For + example: + + \code + / *! + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + + \skipto main + \printuntil app(argc, argv) + + First we create a QApplication object using + the \c argc and \c argv parameters. + + \skipto QPushButton + \printuntil resize + + Then we create a QPushButton, and give it a reasonable + size using the QWidget::resize() function. + + ... + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + + \skipto main + \printuntil app(argc, argv) + + First we create a QApplication object using the \c argc + and \c argv parameters. + + \skipto QPushButton + \printuntil resize + + Then we create a QPushButton, and give it a reasonable + size using the QWidget::resize() function. + + ... + \endquotation + + (\l {Example File}{The complete example file...}) + + QDoc remembers which file it's quoting, and the current + position within that file (see \l {file}{\\printline} for + more information). There is no need to "close" the file. + + Earlier we called this command \\quotefile. For more + information, see the \l + {26-qdoc-commands-compatibility.html#quotefromfile-versus-quotefile} + {compatibility} section. + + See also \l {quotefile}{\\quotefile}, \l {code}{\\code} and + \l {dots}{\\dots}. + + \row + \o \bold \\printline \target printline + \o \bold {The \\printline command expands to the line + from the current position to the next non-blank line of + the current souce file.} + + To ensure that the documentation always is synchronized + with the source file, a substring of the line must be + specified as an argument to the command. Note that the + command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. + + The line from the source file is rendered as a separate + paragraph, using a typewriter font and the standard + indentation. The code is shown verbatim. + + For example: + + \code + / *! + There has to be exactly one QApplication object + in every GUI application that uses Qt. + + \quotefromfile examples/main.cpp + + \printline QApplication + + This line includes the QApplication class + definition. QApplication manages various + application-wide resources, such as the + default font and cursor. + + \printline QPushButton + + This line includes the QPushButton class + definition. The QPushButton widget provides a command + button. + + \printline main + + The main function... + * / + \endcode + + will be rendered as + + \quotation + There has to be exactly one QApplication object + in every GUI application that uses Qt. + + \quotefromfile examples/main.cpp + + \printline QApplication + + This line includes the QApplication class + definition. QApplication manages various + application-wide resources, such as the + default font and cursor. + + \printline QPushButton + + This line includes the QPushButton class + definition. The QPushButton widget provides a command + button. + + \printline main + + The main function... + \endquotation + + (\l {Example File}{The complete example file...}) + + \target file + + QDoc reads the file sequentially. To move the current + position forward you can use either of the \l + {skipline}{\\skip...} commands. To move the current + position backward, you can use the \l + {quotefromfile}{\\quotefromfile} command again. + + \target substring + + If the substring argument is surrounded by slashes it is + interpreted as a \l {regular expression}. + + For example: + + \code + / *! + \quotefromfile widgets/scribble/mainwindow.cpp + + \skipto closeEvent + \printuntil /^\}/ + + Close events are sent to widgets that the users want to + close, usually by clicking \c File|Exit or by clicking + the \c X title bar button. By reimplementing the event + handler, we can intercept attempts to close the + application. + * / + \endcode + + will be rendered as + + \quotation + \quotefromfile widgets/scribble/mainwindow.cpp + + \skipto closeEvent + \printuntil /^\}/ + + Close events are sent to widgets that the users want to + close, usually by clicking \c File|Exit or by clicking + the \c X title bar button. By reimplementing the event + handler, we can intercept attempts to close the + application. + \endquotation + + (\l {widgets/scribble}{The complete example file...}) + + The regular expression \c /^\}/ makes QDoc print until the + first '}' character occurring at the beginning of the line + without indentation. /.../ encloses the regular expression, + and '^' means the beginning of the line. The '}' character + must be escaped since it is a special character in regular + expressions. + + QDoc will emit a warning if the specified substring or + regular expression cannot be located, i.e. if the source + code has changed. + + See also \l {printto}{\\printto} and \l + {printuntil}{\\printuntil}. + + \row + \o \bold \\printto \target printto + \o \bold {The \\printto command expands to all the lines + from the current position up to and \i excluding the + next line containing a given substring.} + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. The command also follows the same conventions for \l + {file}{positioning} and \l {substring}{argument} as the \l + {printline}{\\printline} command. + + The lines from the source file are rendered in a separate + paragraph, using a typewriter font and the standard + indentation. The code is shown verbatim. + + For example: + + \code + / *! + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \printto hello + + First we create a QApplication object using the \c argc and + \c argv parameters... + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printto hello + + First we create a QApplication object using the \c argc + and \c argv parameters... + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {printline}{\\printline} and \l + {printuntil}{\\printuntil}. + + \row + \o \bold \\printuntil \target printuntil + \o \bold {The \\printuntil command expands to all the lines + from the current position up to and \i including the next line + containing a given substring.} + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. The command also follows the same conventions for \l + {file}{positioning} and \l {substring}{argument} as the \l + {printline}{\\printline} command. + + The lines from the source file are rendered in a separate + paragraph, using a typewriter font and the standard + indentation. The code is shown verbatim. + + For example: + + \code + / *! + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil hello + + First we create a QApplication object using the + \c argc and \c argv parameters, then we create + a QPushButton. + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within the + \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil hello + + First we create a \l + {http://qt.nokia.com/doc/4.0/qapplication}{QApplication} + object using the \c argc and \c argv parameters, then we + create a \l + {http://qt.nokia.com/doc/4.0/qpushbutton}{QPushButton}. + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {printline}{\\printline} and \l + {printto}{\\printto}. + + \row + \o \bold \\skipline \target skipline + \o \bold {The \\skipline command ignores the next non-blank + line in the current source file.} + + Doc reads the file sequentially, and the \\skipline command + is used to move the current position (omitting a line of + the source file). See the remark about \l {file}{file + positioning} above. + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. The command also follows the same conventions for \l + {substring}{argument} as the \l {printline}{\\printline} + command, and it is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command. For example: + + \code + / *! + QPushButton is a GUI push button that the user + can press and release. + + \quotefromfile examples/main.cpp + \skipline QApplication + \printline QPushButton + + This line includes the QPushButton class + definition. For each class that is part of the + public Qt API, there exists a header file of + the same name that contains its definition. + * / + \endcode + + will be rendered as + + \quotation + \l + QPushButton is a GUI push button that the user + can press and release. + + \quotefromfile examples/main.cpp + \skipline QApplication + \printline QPushButton + + This line includes the QPushButton class + definition. For each class that is part of the public + Qt API, there exists a header file of the same name + that contains its definition. + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {skipto}{\\skipto}, \l + {skipuntil}{\\skipuntil} and \l {dots}{\\dots}. + + \row + \o \bold \\skipto \target skipto + \o \bold {The \\skipto command ignores all the lines from the + current position up to and \i excluding the next line + containing a given substring.} + + QDoc reads the file sequentially, and the \\skipto command + is used to move the current position (omitting one or + several lines of the source file). See the remark about \l + {file}{file positioning} above. + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. + + The command also follows the same conventions for \l + {substring}{argument} as the \l {printline}{\\printline} + command, and it is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command. For example: + + \code + / *! + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil } + + First we create a QApplication object. There + has to be exactly one such object in + every GUI application that uses Qt. Then + we create a QPushButton, resize it to a reasonable + size... + * / + \endcode + + will be rendered as + + \quotation + The whole application is contained within + the \c main() function: + + \quotefromfile examples/main.cpp + \skipto main + \printuntil } + + First we create a QApplication object. There has to be + exactly one such object in every GUI application that + uses Qt. Then we create a QPushButton, resize it to a + reasonable size ... + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {skipline}{\\skipline}, \l + {skipuntil}{\\skipuntil} and \l {dots}{\\dots}. + + \row + \o \bold \\skipuntil \target skipuntil + \o \bold {The \\skipuntil command ignores all the lines from + the current position up to and \i including the next line + containing a given substring.} + + QDoc reads the file sequentially, and the \\skipuntil + command is used to move the current position (omitting one + or several lines of the source file). See the remark about + \l {file}{file positioning} above. + + The command considers the rest of the line as part of its + argument, make sure to follow the substring with a line + break. + + The command also follows the same conventions for \l + {substring}{argument} as the \l {printline}{\\printline} + command, and it is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command. For example: + + \code + / *! + The first thing we did in the \c main() function + was to create a QApplication object \c app. + + \quotefromfile examples/main.cpp + \skipuntil show + \dots + \printuntil } + + In the end we must remember to make \c main() pass the + control to Qt. QCoreApplication::exec() will return when + the application exits... + * / + \endcode + + will be rendered as + + \quotation + The first thing we did in the \c main() function was to + create a QApplication object \c app. + + \quotefromfile examples/main.cpp + \skipuntil show + \dots + \printuntil } + + In the end we must remember to make \c main() pass the + control to Qt. QCoreApplication::exec() + will return when the application exits... + \endquotation + + (\l {Example File}{The complete example file...}) + + See also \l {skipline}{\\skipline}, \l {skipto}{\\skipto} + and \l {dots}{\\dots}. + + \row + \o \bold \\dots \target dots + \o \bold {The \\dots command indicates that parts of the + source file have been omitted when quoting a file.} + + The command is used in conjunction with the \l + {quotefromfile}{\\quotefromfile} command, and should be + stated on its own line. The dots are rendered on a new + line, using a typewriter font. For example: + + \code + / *! + \quotefromfile examples/main.cpp + \skipto main + \printuntil { + \dots + \skipuntil exec + \printline } + * / + \endcode + + will be rendered as + + \quotefromfile examples/main.cpp + \skipto main + \printuntil { + \dots + \skipuntil exec + \printline } + + (\l {Example File}{The complete example file...}) + + The default indentation is 4 spaces, but this can be + adjusted using the command's optional argument. For + example: + + \code + / *! + \dots 0 + \dots + \dots 8 + \dots 12 + \dots 16 + * / + \endcode + + will be rendered as + + \dots 0 + \dots + \dots 8 + \dots 12 + \dots 16 + + See also \l {skipline}{\\skipline}, \l + {skipto}{\\skipto} and \l {skipuntil}{\\skipuntil}. + + \row + \o \bold \\snippet \target snippet + \o \bold {The \\snippet command causes a code snippet to be included + verbatim as preformatted text, which may be syntax highlighted.} + + Each code snippet are referenced by the file that holds it and by + a unique identifier for that file. Snippet files are typically + stored in a \c{snippets} directory inside the documentation + directory (e.g., \c{$QTDIR/doc/src/snippets}). + + For example, the following documentation references a snippet in + a file residing in a subdirectory of the documentation directory: + + \code + \snippet snippets/textdocument-resources/main.cpp Adding a resource + \endcode + + The text following the file name is the unique identifier for the + snippet. This is used to delimit the quoted code in the relevant + snippet file as shown in the following example that corresponds to + the above \c{\\snippet} command: + + \dots + \code + QImage image(64, 64, QImage::Format_RGB32); + image.fill(qRgb(255, 160, 128)); + + //! [Adding a resource] + document->addResource(QTextDocument::ImageResource, + QUrl("mydata://image.png"), QVariant(image)); + //! [Adding a resource] + \endcode + \dots + \row + \o \bold \\codeline \target codeline + \o \bold{The \\codeline command inserts a blank line of preformatted + text. It is used to insert gaps between snippets without closing + the current preformatted text area and opening a new one.} + \endtable +*/ + +/*! + \page 07-1-example.html + \previouspage Quoting External Code Commands + \contentspage QDoc Manual - Table of Contents + + \title Example File + + \quotefile examples/main.cpp +*/ + +/*! + \page 08-qdoc-commands-linking.html + \previouspage Quoting External Code Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Graphic Commands + + \title Linking Commands + + The linking commands make it possible to create hyperlinks to + classes, functions, header files and examples. They also make it + possible to link to targets within a document, as well as to other + documents and URLs. + + \section1 Alphabetical List + + \l {08-qdoc-commands-linking.html#keyword}{\\keyword}, + \l {08-qdoc-commands-linking.html#l}{\\l}, + \l {08-qdoc-commands-linking.html#sa}{\\sa}, + \l {08-qdoc-commands-linking.html#target}{\\target} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\l \target l + \o \bold {The \\l command is used to create hyperlinks. } + + The command's general syntax is + + \code + \l {link target}{link text} + \endcode + + For example: + + \code + / *! + Read the \l {http://qt.nokia.com/doc/4.0/} + {Qt's Reference Documentation} carefully. + * / + \endcode + + will be rendered as + + \quotation + Read the \l {http://qt.nokia.com/doc/4.0/} + {Qt's Reference Documentation} carefully. + \endquotation + + If the link target is equivalent to the link text, the + second argument can be omitted. + + For example, if you have documentation like: + + \code + / *! + \target assertions + + Assertions make some statement about the text at the + point where they occur in the regexp but they do not + match any characters. + + ... + + Regexps are built up from expressions, quantifiers, and + \l {assertions}{assertions}. + * / + \endcode + + you can rewrite it as + + \code + / *! + \target assertions + + Assertions make some statement about the text at the + point where they occur in the regexp but they do not + match any characters. + + ... + + Regexps are built up from expressions, quantifiers, and + \l assertions. + * / + \endcode + + For the one-parameter version the braces can often + be omitted. See the \l {i}{\\i} command for the \l + {argument}{argument conventions}. + + The \\l command supports several kinds of links: + + \list + \o \c {\l QWidget} - a defined \l {class}{\\class} + \o \c {\l QWidget::sizeHint()} - a defined member + function (\l {fn}{\\fn}) + \o \c {\l } - a defined \l {headerfile}{\\headerfile} + \o \c {\l widgets/wiggly} - a defined + \l {example-command}{\\example} + \o \c {\l {QWidget Class Reference}} - a defined \l {title}{\\title} + \o \c {\l {Introduction}}- a defined \l{part}{\\part}, + \l{chapter}{\\chapter} or \l {sectionOne}{\\section...} + \o \c {\l fontmatching} - a defined \l {target}{\\target} + \o \c {\l {Shared Classes}} - a defined \l {keyword}{\\keyword} + \o \c {\l network.html} - a defined \l {page}{\\page} + \o \c {\l http://www.trolltech.com/} - a URL + \endlist + + QDoc also tries to make a link out of any words that don't + resemble any normal English words, for example Qt class + names or functions, like QWidget or QWidget::sizeHint(). In + these cases, the \\l command can actually be omitted, but + by using the command, you ensure that QDoc will emit a + warning if it cannot find the link target. In addition, if + you only want the function name to appear in the link, you + can use the following syntax: + + \list + \o \c {\l {QWidget::}{sizeHint()}} + \endlist + + See also \l {sa}{\\sa}, \l {target}{\\target} and \l + {keyword}{\\keyword}. + + \row + \o \bold \\sa \target sa + \o \bold {The \\sa command defines a list of links that will + be rendered in a separate "See also" section at the bottom + of the documentation.} + + The command takes a comma-separated list of links as its + argument. If the line ends with a comma, you can continue + on a second line. The general syntax is: + + \code + \sa {the first link}, {the second link}, + {the third link}, ... + \endcode + + QDoc will automatically try to generate "See also" links + interconnecting a property's various functions. For + example, an setVisible() function will automatically get a + link to visible() and vice versa. + + In general, QDoc will generate "See also" links that + interconnect the functions that access the same + property. It recognizes four different syntax versions: + + \list + \o \c property() + \o \c setProperty() + \o \c isProperty() + \o \c hasProperty() + \endlist + + The \\sa command supports the same kind + of links as the \l {l}{\\l} command. For example: + + \code + / *! + Appends the actions \a actions to this widget's + list of actions. + + \sa removeAction(), QMenu, addAction() + * / + void QWidget::addActions(QList actions) + { + ... + } + \endcode + + will be rendered as + + \quotation + \bold {void QWidget::addActions ( QList + \i actions )} + + Appends the actions \i actions to this widget's + list of actions. + + See also \l {QWidget::removeAction()}{removeAction()}, + \l QMenu, and \l {QWidget::addAction()}{addAction()}. + \endquotation + + See also \l {l}{\\l}, \l {target}{\\target} and \l + {keyword}{\\keyword}. + + \row + \o \bold \\target \target target + \o \bold {The \\target command defines an explicit point in the + documentation that you can later link to using the \l {l}{\\l} + and \l {sa}{\\sa} commands.} + + The command considers the rest of the line as part of its + argument, make sure to follow the target name with a line + break. + + For example: + + \code + / *! + \target capturing parentheses + \section1 Capturing Text + + Parentheses allow us to group elements together so that + we can quantify and capture them. + + ... + * / + \endcode + + can be referenced with + + \list + \o \c {\l {capturing parentheses}} + (from elsewhere in the same comment) + \o \c {\l qregexp.html#capturing-parentheses} + (from anywhere else) + \endlist + + within a documentation unit, and with + + \list + \o \c {\l http://www.trolltech.com/4.0/doc/html/qregexp.html#capturing-parentheses} + \endlist + + on a more global scale. + + If the target name does't contain any spaces, the brackets can + be omitted as well. + + See also \l {l}{\\l}, \l {sa}{\\sa} and \l + {keyword}{\\keyword}. + + \row + \o \bold \\keyword \target keyword + \o \bold {The \\keyword command defines an explicit point in the + documentation that you can later link to using the \l {l}{\\l} + and \l {sa}{\\sa} commands.} + + Keywords must be unique within the entire set of + documentation processed in on QDoc run. The command + considers the rest of the line as part of its argument, + make sure to follow the keyword with a line break. + + The \\keyword command is similar to \l {target}{\\target}, + but stronger. A keyword can be referenced from anywhere + using a simple syntax. For example: + + \code + / *! + \class QRegExp + \reentrant + \brief The QRegExp class provides pattern + matching using regular expressions. + \ingroup tools + \ingroup misc + \ingroup shared + \mainclass + + \keyword regular expression + + Regular expressions, or "regexps", provide a way to + find patterns within text. + + ... + * / + \endcode + + can be referenced like this + + \code + / *! + When a string is surrounded by slashes, it's + interpreted as a \l regular expression. + * / + \endcode + + which will be rendered as + + \quotation + When a string is surrounded by slashes, it's + interpreted as a \l {regular expression}. + \endquotation + + If the keyword does't contain any spaces, the brackets can + be omitted as well. + + See also \l {l}{\\l}, \l {sa}{\\sa} and \l + {target}{\\target}. + \endtable +*/ + +/*! + \page 09-qdoc-commands-graphic.html + \previouspage Linking Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Container Commands + + \title Graphic Commands + + The graphic commands makes it possible to include images in the + documentation. The images can be rendered as separate paragraphs, + or within running text. + + \section1 Alphabetical List + + \l {09-qdoc-commands-graphic.html#caption}{\\caption}, + \l {09-qdoc-commands-graphic.html#image}{\\image}, + \l {09-qdoc-commands-graphic.html#inlineimage}{\\inlineimage} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\image \target image + \o \bold {The \\image command expands to the image specified by its + argument, and renders it centered as a separate paragraph.} + + The \\image command replaces the old \\img command. For more + information, see the \l + {26-qdoc-commands-compatibility.html#image-versus-img} + {compatibility} section. + + The command takes two arguments. The first is the name of + the image file. The second argument is optional and is a + simple description of the image equivalent to the HTML + alt="" in an image tag. The description is used for + tooltips, and when a browser doesn't support images like + the Lynx text browser. + + The command considers the rest of the line after the file + name its second argument, make sure that you follow the + filename or description with a line break. Braces are only + necessary if the description spans several lines. + + For example: + + \code + / *! + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. + + \image happyguy.jpg "Happy guy" + + Qt provides single-source portability across Microsoft + Windows, Mac OS X, Linux, and all major commercial Unix + variants. It is also available for embedded devices. + * / + \endcode + + will be rendered as + + \quotation + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. + + \image happyguy.jpg image "Happy guy" + + Qt provides single-source portability across Microsoft + Windows, Mac OS X, Linux, and all major commercial Unix + variants. It is also available for embedded devices. + \endquotation + + See also \l {inlineimage}{\\inlineimage} and \l + {caption}{\\caption}. + + \row + \o \bold \\inlineimage \target inlineimage + \o \bold {The \\inlineimage command expands to the image + specified by its argument; the image is rendered inline + with the rest of the text.} + + The command takes two arguments. The first is the name of + the image file. The second argument is optional and is a + simple description of the image equivalent to the HTML + alt="" in an image tag. The description is used for + tooltips, and when a browser doesn't support images like + the Lynx text browser. + + The most common use of the \\inlineimage command is in + lists and tables. For example: + + \code + / *! + \list 1 + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \endlist + * / + \endcode + + will be rendered as + + \list 1 + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \endlist + + And + + \code + / *! + \table + \header + \o Trolltech + \o Trolltech + \row + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \row + \o \inlineimage happy.gif Oh so happy! + \o \inlineimage happy.gif Oh so happy! + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + + + + + + + +
    TrolltechTrolltech
    Oh so happy! + Oh so happy! +
    Oh so happy! + Oh so happy! +
    + \endraw + + The command can also be used to insert an image + inline with the regular text. For example: + + \code + / *! + \inlineimage training.jpg Training by Trolltech + The Qt Programming course is offered as a + five day Open Enrollment Course. The classes + are open to the public.While the course is open + to anyone who wants to learn, attendees should + have significant experience in C++ development + to derive maximum benefit from the course. + * / + \endcode + + will be rendered as + + \quotation + \inlineimage training.jpg Training by Trolltech + The Qt Programming course is offered as a + five day Open Enrollment Course. The classes + are open to the public.While the course is open + to anyone who wants to learn, attendees should + have significant experience in C++ development + to derive maximum benefit from the course. + \endquotation + + See also \l {image}{\\image} and \l {caption}{\\caption}. + + \row + \o \bold \\caption \target caption + \o \bold {The \\caption command provides a caption for an image.} + + The command follows the same conventions for parentheses and use + of braces for its \l argument as the \l {i}{\\i} command. + + \warning This is preliminary functionality. The + command is not fully implemented. + + See also \l {image}{\\image} and \l + {inlineimage}{\\inlineimage} + + \endtable +*/ + +/*! + \page 10-qdoc-commands-container.html + \previouspage Graphic Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Document Contents Commands + + \title Container Commands + + The container commands create tables and lists with associated + items and contents. A list is rendered left aligned as a separate + paragraph. A table is rendered centered as a separate paragraph, + and its width depends on its content. + + \section1 Alphabetical List + + \l {10-qdoc-commands-container.html#header}{\\header}, + \l {10-qdoc-commands-container.html#list}{\\list}, + \l {10-qdoc-commands-container.html#o}{\\o}, + \l {10-qdoc-commands-container.html#omitvalue}{\\omitvalue}, + \l {10-qdoc-commands-container.html#row}{\\row}, + \l {10-qdoc-commands-container.html#table}{\\table}, + \l {10-qdoc-commands-container.html#value}{\\value} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\table \target table + \o \bold {The \\table command and the corresponding \\endtable + command delimit the contents of a table.} + + The command accepts a single argument specifying the + table's width in percentage: + + \code + / *! + \table 100 % + + ... + + \endtable + * / + \endcode + + The code above ensures that the table will fill all + available space. If the table's width is smaller than 100 %, + the table will be centered in the generated documentation. + + A table can contain headers, rows and columns. A row starts + with a \l {row}{\\row} command and consists of cells, which + starts with a \l {o}{\\o} command. There is also a \l + {header}{\\header} command which is a special kind of row + with a special formatting. For example: + + \code + / *! + \table + \header + \o Qt Core Feature + \o Brief Description + \row + \o \l {Signal and Slots} + \o Signals and slots are used for communication + between objects. + \row + \o \l {Layout Management} + \o The Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets. + \row + \o \l {Drag and Drop} + \o Drag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + + + + + + + + + + + + +
    Qt Core FeatureBrief Description
    + + Signals and Slots + Signals and slots are used for communication + between objects.
    + + Layout ManagementThe Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets.
    + + Drag and DropDrag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications.
    + \endraw + + You can also make cells span several rows and columns. For + example: + + \code + / *! + \table + \header + \o {3,1} This header cell spans three columns + but only one row. + \row + \o {2, 1} This table cell spans two columns + but only one row + \o {1, 2} This table cell spans only one column, + but two rows. + \row + \o A regular table cell + \o A regular table cell + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + + + + + + + +
    + This header cell spans three columns but only one row +
    + This table cell spans two columns but only one row + + This table cell spans only one column, but two rows. +
    A regular table cellA regular table cell
    + \endraw + + See also \l {header}{\\header}, \l {row}{\\row} and \l {o}{\\o}. + + \row + \o \bold \\header \target header + \o \bold {The \\header command indicates that the following + table cells are the current table's column headers.} + + The command can only be used within the \l{table} + {\\table...\\endtable} commands. A header can contain + several cells. A cell is created with the \l {o}{\\o} + command. + + A header cell's text is centered within the table cell and + rendered using a bold font. For example: + + \code + / *! + \table + \header + \o Qt Core Feature + \o Brief Description + \row + \o \l {Signal and Slots} + \o Signals and slots are used for communication + between objects. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + +
    Qt Core FeatureBrief Description
    + + Signals and Slots + Signals and slots are used for communication + between objects.
    + \endraw + + See also \l {table}{\\table}, \l {row}{\\row} and \l {o}{\\o}. + + \row + \o \bold \\row \target row + \o \bold {The \\row command indicates that the following table + cells belong to the same row in the current table.} + + The command can only be used within the \l{table} + {\\table...\\endtable} commands. A row can contain + several cells. A cell is created with the \l {o}{\\o} + command. + + The background cell color of each row alternate between two + shades of grey, making it easier to distinguish the rows + from each other. The cells' contents is left aligned. + + For example: + + \code + / *! + \table + \header + \o Qt Core Feature + \o Brief Description + \row + \o \l {Signal and Slots} + \o Signals and slots are used for communication + between objects. + \row + \o \l {Layout Management} + \o The Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets. + \row + \o \l {Drag and Drop} + \o Drag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + + + + + + + + + + + + +
    Qt Core FeatureBrief Description
    + + Signals and Slots + Signals and slots are used for communication + between objects.
    + + Layout ManagementThe Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets.
    + + Drag and DropDrag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications.
    + \endraw + + See also \l {table}{\\table}, \l {header}{\\header} and \l + {o}{\\o}. + + \row + \o \bold \\value \target value + \o \bold {The \\value command starts the documentation of a C++ enum + item}. + + The command's first argument is the enum item. Then follows + its associated description. The description argument ends + at the next blank line or \\value. The arguments are + rendered within a table. + + The documentation will be located in the associated class, + header file or namespace documentation. See the \l + {enum}{\\enum} documentation for an example. + + See also \l {enum}{\\enum} and \l {omitvalue}{\\omitvalue}. + + \row + \o \bold \\omitvalue \target omitvalue + \o \bold {The \\omitvalue command excludes a C++ enum item + from the documentation}. + + The command's only argument is the name of the enum item + that will be omitted. See the \l {enum}{\\enum} + documentation for an example. + + See also \l {enum}{\\enum} and \l {value}{\\value}. + + \row + \o \bold \\list \target list + \o \bold {The \\list command and the corresponding \\endlist + command delimit a list of items.} + + You need to create each list item explicitly using the \l + {o}{\\o} command. A list can contain one or more items; it + can also be nested. For example: + + \code + / *! + \list + \o Qt Reference Documentation: Getting Started + \list + \o How to Learn Qt + \o Installation + \list + \o Qt/X11 + \o Qt/Windows + \o Qt/Mac + \o Qt/Embedded + \endlist + \o Tutorial and Examples + \endlist + \endlist + * / + \endcode + + will be rendered as + + \list + \o Qt Reference Documentation: Getting Started + \list + \o How to Learn Qt + \o Installation + \list + \o Qt/X11 + \o Qt/Windows + \o Qt/Mac + \o Qt/Embedded + \endlist + \o Tutorial and Examples + \endlist + \endlist + + The \\list command takes an optional argument providing + alternative appearances for the list items. For example: + + \code + / *! + \list + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + * / + \endcode + + will render the list items with bullets (the default): + + \list + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + If you provide 'A' as an argument to the \\list command, + the bullets are replaced with characters following in + alphabetical order: + + \list A + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + If you replace 'A' with '1', the list items are rendered + with numbers following in ascending order: + + \list 1 + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + + \endlist + + If you provide 'i' as the argument, the default bullets are + replaced with roman numerals: + + \list i + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + Or finally, you can make the list items appear with roman + numbers following in ascending order if you provide 'I' as + the optional argument: + + \list I + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + You can also make the listing start at any character or + number by simply provide the number or character you want + to start at. For example: + + \code + / *! + \list G + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + * / + \endcode + + will be rendered as + + \list G + \o How to Learn Qt + \o Installation + \o Tutorial and Examples + \endlist + + See also \l {o}{\\o}. + + \row + \o \bold \\o \target o + \o \bold {The \\o command announce a table or list item.} + + Earlier we used the \l {i}{\\i} command for this purpose. For more + information see the \l + {26-qdoc-commands-compatibility.html#o-versus-i}{compatibility} + section. + + The command can only be used within the \l{table} + {\\table...\\endtable} or \l{list}{\\list... \\endlist} + commands. + + It considers everything until the next occurrence + of the \\o command, or the currently applicable \l + {table}{\\endtable} or \l {list}{\\endlist} command, as its + argument. For examples, see \l {table}{\\table} and \l + {list}{\\list}. + + If the command is used within a table, you can in addition + specify how many rows or columns the item should span. For + example: + + \code + / *! + \table + \header + \o {3,1} This header cell spans three columns + but only one row. + \row + \o {2, 1} This table item spans two columns + but only one row + \o {1, 2} This table item spans only one column, + but two rows. + \row + \o A regular table item + \o A regular table item + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + + + + + + + +
    + This header cell spans three columns but only one row +
    + This table item spans two columns but only one row + + This table item spans only one column, but two rows. +
    A regular table itemA regular table item
    + \endraw + + If not specified, the item will span one column and one row. + + See also \l {table}{\\table}, \l {header}{\\header}, + \l {list}{\\list} and \l {o}{\\o}. + \endtable +*/ + +/*! + \page 11-qdoc-commands-documentcontents.html + \previouspage Container Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Miscellaneous Commands + + \title Document Contents Commands + + The document contents commands identify parts of the documentation, + i.e. parts with a special rendering, conceptual meaning or + function. + + \section1 Alphabetical List + + \l {11-qdoc-commands-documentcontents.html#abstract}{\\abstract}, + \l {11-qdoc-commands-documentcontents.html#brief}{\\brief}, + \l {11-qdoc-commands-documentcontents.html#footnote}{\\footnote}, + \l {11-qdoc-commands-documentcontents.html#legalese}{\\legalese}, + \l {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents}, + \l {11-qdoc-commands-documentcontents.html#quotation}{\\quotation}, + \l {11-qdoc-commands-documentcontents.html#warning}{\\warning} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\abstract \target abstract + \o \bold {The \\abstract command and the corresponding \\endabstract + command delimit a document's abstract section.} + + The abstract section is rendered as an indented italicized + paragraph. + + \warning This is preliminary funcionality. The + command is not fully implemented. Currently, the abstract + section is rendered as a regular HTML paragraph. For + example: + + \code + / *! + \abstract + Qt by Trolltech is a C++ toolkit for cross-platform + GUI application development. Qt provides + single-source portability across Microsoft Windows, + Mac OS X, Linux, and all major commercial Unix + variants. It is also available for embedded + devices. + \endabstract + * / + \endcode + + will be rendered as + + \abstract + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. Qt provides single-source + portability across Microsoft Windows, Mac OS X, Linux, + and all major commercial Unix variants. It is also + available for embedded devices. + \endabstract + + \row + \o \bold \\quotation \target quotation + \o \bold { The \\quotation command and the corresponding + \\endquotation command delimit a quotation remark.} + + This command replaces the old \\quote command. For more + information see the \l + {26-qdoc-commands-compatibility.html#quotation-versus-quote} + {compatibility} section. + + The remark is rendered as a separate centered + paragraph. For example: + + \code + / *! + While the prospect of a significantly broader market is + good news for Firstlogic, the notion also posed some + challenges. Dave Dobson, director of technology for the La + Crosse, Wisconsin-based company, said: + + + \quotation + As our solutions were being adopted into new + environments, we saw an escalating need for easier + integration with a wider range of enterprise + applications. + \endquotation + * / + \endcode + + will be rendered as + + While the prospect of a significantly broader market is + good news for Firstlogic, the notion also posed some + challenges. Dave Dobson, director of technology for the La + Crosse, Wisconsin-based company, said: + + \quotation + As our solutions were being adopted into new + environments, we saw an escalating need for easier + integration with a wider range of enterprise + applications. + \endquotation + + \row + \o \bold \\footnote \target footnote + \o \bold {The \\footnote command and the corresponding + \\endfootnote command delimit a footnote.} + + The footnote follows the standard conventions, rendered at the + bottom of the page. + + \warning This is preliminary funcionality. The + command is not fully implemented. + + For example: + + \code + / *! + In Qt 4 we have tried to simplify the constructors of + QObject/QWidget subclasses. This makes subclassing + easier, at the same time as it helps make the Qt + library more efficient. + + \footnote + Constructors no longer take a "const char *name" + parameter. If you want to specify a name for a QObject, + you must call QObject::setObjectName() after + construction. The object name is now a QString. + \endfootnote + + QWidget's WFlags data type has been split in two: + Qt::WindowFlags specifies low-level window flags (the + type of window and the frame style), whereas + Qt::WidgetAttribute specifies various higher-level + attributes about the widget (e.g., + WA_StaticContents). + * / + \endcode + + will be rendered as + + \quotation + In Qt 4 we have tried to simplify the constructors of + QObject/QWidget subclasses. This makes subclassing + easier, at the same time as it helps make the Qt + library more efficient. + + \footnote + Constructors no longer take a "const char *name" + parameter. If you want to specify a name for a QObject, + you must call QObject::setObjectName() after + construction. The object name is now a QString. + \endfootnote + + QWidget's WFlags data type has been split in two: + Qt::WindowFlags specifies low-level window flags (the + type of window and the frame style), whereas + Qt::WidgetAttribute specifies various higher-level + attributes about the widget (e.g., + WA_StaticContents). + \endquotation + + \row + \o \bold \\tableofcontents \target tableofcontents + \o \bold {The \\tableofcontents command generates a + table displaying the titles of the current documentation + unit's parts, chapters, sections, etc.} + + The command accepts a single optional argument: + + \code + \tableofcontents sectionN + \endcode + + where \c sectionN is the deepest section to include (by + default all sections are included). + + For example, it the documentation unit's structure looks + something like this: + + \quotation + \raw HTML + +

    Basic Qt

    +
    +

    This is the first part.

    + + +

    Getting Started

    +
    + This is the first part's first chapter.

    + + +

    Hello Qt

    +
    +

    This is the first chapter's first section.

    + + +

    Making Connections

    +
    +

    This is the first chapter's second section.

    + + +

    Using the Reference Documentation

    +
    +

    This is the first chapter's third section.

    + + +

    Creating Dialogs

    +
    +

    This is the first part's second chapter.

    + + +

    Subclassing QDialog

    +
    +

    This is the second chapter's first section.

    + + ... + + +

    Intermediate Qt

    +
    +

    This is the second part.

    + + +

    Layout Management

    +
    +

    This is the second part's first chapter.

    + + +

    Basic Layouts

    +
    +

    This is the first chapter's first section.

    + + ... + + \endraw + \endquotation + + Then + + \code + / *! + Contents: + + \tableofcontents + + ... + * / + \endcode + + will expand to + + \quotation + \raw HTML +

    Contents:

    + + + + ... + \endraw + \endquotation + + Each table entry becomes a link to the corresponding part, + chapter or section. + + \row + \o \bold \\brief \target brief + \o \bold {The \\brief command introduces a one-sentence + description of a class, namespace, header file, property + or variable.} + + The brief text is used to introduce the documentation of + the associated object, and in lists generated using the \l + {generatelist}{\\generatelist} command. + + The \\brief command can be used in two significant + different ways: \l {brief class}{One for classes, + namespaces and header files}, and \l {brief property}{one + for properties and variables}. + + \target brief property + + When the \\brief command is used to describe a property or + a variable, the brief text must only be a sentence fragment + and start with "whether" (for boolean properties and + variables) or "the" (for any other property or variable). + + For example the boolean QWidget::isWindow property: + + \code + / *! + \property QWidget::isActiveWindow + \brief whether this widget's window is the active window + + The active window is the window that contains the widget that + has keyboard focus. + + When popup windows are visible, this property is true + for both the active window \e and for the popup. + + \sa activateWindow(), QApplication::activeWindow() + * / + \endcode + + and the QWidget::geometry property + + \code + / *! + \property QWidget::geometry + \brief the geometry of the widget relative to its parent and + excluding the window frame + + When changing the geometry, the widget, if visible, + receives a move event (moveEvent()) and/or a resize + event (resizeEvent()) immediately. + + ... + + \sa frameGeometry(), rect(), ... + * / + \endcode + + The latter will be rendered as + + \quotation + \raw HTML +

    geometry : + QRect +

    + \endraw + + This property holds the geometry of the widget relative + to its parent and excluding the window frame. + + ... + + Access functions: + \list + \o \bold {const QRect & geometry () const} + \o \bold {void setGeometry ( int x, int y, int w, int h )} + \o \bold {void setGeometry ( const QRect & )} + \endlist + + See also \l + {QWidget::frameGeometry()}{frameGeometry()}, \l + {QWidget::rect()}{rect()}, ... + \endquotation + + \target brief class + + When the \\brief command is used to describe a class, the + brief text should be a complete sentence and must start + like this: + + \code + The class is|provides|contains|specifies... + \endcode + + and likewise when the command is used for namespaces or + header files. + + \warning The brief statement is used as the first + paragraph of the detailed description. Do not repeat the + sentence. + + For example: + + \code + / *! + \class PreviewWindow + \brief The PreviewWindow class is a custom widget + displaying the names of its currently set + window flags in a read-only text editor. + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the + setWindowFlags() function. It is also provided with a + QPushButton that closes the window. + + ... + + \sa QWidget + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    PreviewWindow Class Reference

    + \endraw + + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. \l {preview window}{More...} + + \raw HTML +

    Properties

    + \endraw + + \list + \o 52 properties inherited from QWidget + \o 1 property inherited from QObject + \endlist + + \raw HTML +

    Public Functions

    + \endraw + + \list + \o \l {constructor}{PreviewWindow}(QWidget *parent = 0) + \o void \l {function}{setWindowFlags}(Qt::WindowFlags flags) + \endlist + + \list + \o 183 public functions inherited from QWidget + \o 28 public functions inherited from QObject + \endlist + + \raw HTML +

    Public Slots

    + \endraw + + \list + \o 17 public slots inherited from QWidget + \o 1 public slot inherited from QObject + \endlist + + \raw HTML +

    Additional Inherited Members

    + \endraw + + \list + \o 1 signal inherited from QWidget + \o 1 signal inherited from QObject + \o 4 static public members inherited from QWidget + \o 4 static public members inherited from QObject + \o 39 protected functions inherited from QWidget + \o 7 protected functions inherited from QObject + \endlist + + \target preview window + + \raw HTML +
    +

    Detailed Description

    + \endraw + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the \l + {function}{setWindowFlags()} function. It is also + provided with a QPushButton that closes the window. + + ... + + See also QWidget. + + \raw HTML +
    +

    Member Function Documentation

    + \endraw + + \target constructor + \raw HTML +

    PreviewWindow(QWidget *parent = 0)

    + \endraw + + Constructs a preview window widget with \i parent. + + \target function + \raw HTML +

    setWindowFlags(Qt::WindowFlags flags)

    + \endraw + + Sets the widgets flags using the + QWidget::setWindowFlags() function. + + Then runs through the available window flags, + creating a text that contains the names of the flags + that matches the flags parameter, displaying + the text in the widgets text editor. + \endquotation + + Using \\brief with a namespace can for example look like this: + + \code + / *! + \namespace Qt + + \brief The Qt namespace contains miscellaneous identifiers + used throughout the Qt library. + * / + \endcode + + and finally using \\brief with a header file can look + something like this: + + \code + / *! + \headerfile + \title Global Qt Declarations + + \brief The header file provides basic + declarations and is included by all other Qt headers. + + \sa + * / + \endcode + + See also \l{property}{\\property}, \l{class}{\\class}, + \l{namespace}{\\namespace} and \l{headerfile}{\\headerfile}. + + \row + \o \bold \\legalese \target legalese + \o \bold {The \\legalese command, and the corresponding \\endlegalese + command, delimit a licence agreement.} + + If the \\endlegalese command is omitted, QDoc will still + process the \\legalese command but considers the rest of + the documentation page as the license agreement. + + Ideally, the license documentation is located where the + licensed code is used. + + Later the documentation identified by the \\legalese + command can be accumulated into a list using the \l + {generatelist}{\\generatelist} command with the \c legalese + argument. This is useful to generate an overview of all the + licenses associated with the source code. + + For example: + + \code + \ * ! + ... + + On X11, Qt also supports drops via the Motif Drag \& + Drop Protocol. The implementation incorporates some + code that was originally written by Daniel Dardailler, + and adapted for Qt by Matt Koss \ and + Trolltech. Here is the original copyright notice: + + \legalese + \code + + Copyright 1996 Daniel Dardailler. + + Permission to use, copy, modify, distribute, and sell + this software for any purpose is hereby granted without + fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this + permission notice appear in supporting documentation, + and that the name of Daniel Dardailler not be used in + advertising or publicity pertaining to distribution of + the software without specific, written prior + permission. Daniel Dardailler makes no representations + about the suitability of this software for any + purpose. It is provided "as is" without express or + implied warranty. + + Modifications Copyright 1999 Matt Koss, under the same + license as above. + + \ endcode + \endlegalese + * / + \endcode + + will be rendered as + + \quotation + ... + + On X11, Qt also supports drops via the Motif Drag \& + Drop Protocol. The implementation incorporates some + code that was originally written by Daniel Dardailler, + and adapted for Qt by Matt Koss \ and + Trolltech. Here is the original copyright notice: + + \legalese + \code + + Copyright 1996 Daniel Dardailler. + + Permission to use, copy, modify, distribute, and sell + this software for any purpose is hereby granted without + fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this + permission notice appear in supporting documentation, + and that the name of Daniel Dardailler not be used in + advertising or publicity pertaining to distribution of + the software without specific, written prior + permission. Daniel Dardailler makes no representations + about the suitability of this software for any + purpose. It is provided "as is" without express or + implied warranty. + + Modifications Copyright 1999 Matt Koss, under the same + license as above. + + \endcode + \endlegalese + \endquotation + + \row + \o \bold \\warning \target warning + \o \bold {The \\warning command renders a "Warning:" prefix to + the command's argument.} + + For example: + + \code + / *! + Qt::HANDLE is a platform-specific handle type + for system objects. This is equivalent to + \c{void *} on Windows and Mac OS X, and to + \c{unsigned long} on X11. + + \warning Using this type is not portable. + * / + \endcode + + will be rendered as + + \quotation + Qt::HANDLE is a platform-specific handle type + for system objects. This is equivalent to + \c{void *} on Windows and Mac OS X, and to + \c{unsigned long} on X11. + + \warning Using this type is not portable. + \endquotation + \endtable +*/ + +/*! + \page 12-0-qdoc-commands-miscellaneous.html + \previouspage Document Contents Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Topical Commands + + \title Miscellaneous Commands + + These commands provide miscellaneous functions + connected to the visual appearance of the documentation, and to the + process of generating the documentation. + + \section1 Alphabetical List + + \l {12-0-qdoc-commands-miscellaneous.html#else}{\\else}, + \l {12-0-qdoc-commands-miscellaneous.html#endif}{\\endif}, + \l {12-0-qdoc-commands-miscellaneous.html#expire}{\\expire}, + \l {12-0-qdoc-commands-miscellaneous.html#generatelist}{\\generatelist}, + \l {12-0-qdoc-commands-miscellaneous.html#if}{\\if}, + \l {12-0-qdoc-commands-miscellaneous.html#include}{\\include}, + \l {12-0-qdoc-commands-miscellaneous.html#meta}{\\meta}, + \l {12-0-qdoc-commands-miscellaneous.html#omit}{\\omit}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\raw}, + \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\unicode} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\expire \target expire + \o \bold {The \\expire command allows you to define an expiration + date for your documentation.} + + When using the \\expire command, QDoc will emit a warning + when the current date is larger than the specified + date. The command accepts one argument; the argument's + format is yyyy-mm-dd. For example: + + \code + / *! + \page porting.html + + \title Porting to Qt 3.x + + \expire 2004-12-31 + + This document describes porting applications from Qt + 2.x to Qt 3.x. + + The Qt 3.x series is not binary compatible with the + 2.x series. + ... + * / + \endcode + + If you run QDoc on 4 July 2005, it will emit the warning + + \quotation + porting.qdoc:6: Documentation expired 185 days ago + \endquotation + + \row + \o \bold \\generatelist \target generatelist + \o \bold {The \\generatelist command expands to a list of + various documentation or links to documentation.} + + For example in the Qt Reference Documentation: + + \code + / *! + \page classes.html + \title All Qt Classes (main index) + + For a shorter list that only includes the most + frequently used classes, see \l{Qt's Main Classes}. For + a list of Qt 3 support classes, see \l{Qt3Support + Classes}. + + \generatelist classes + * / + \endcode + + is used to generate \l {All Qt Classes (main index)}. + + The command accepts the following arguments: + + \target table example + + \list + \o \c annotatedclasses + + The \c annotatedclasses argument provides a table + containing the names of all the classes, and a + description of each class. Each class name is a link to + the class's reference documentation. + + For example: + + \quotation + \raw HTML + + + + + + + + + + + + + + + + +
    + + QDial + Rounded range control (like a speedometer + or potentiometer)
    + + QDialog + The base class of dialog windows
    + + QDir + Access to directory structures and their + contents
    + \endraw + \endquotation + + A class is identified within the documentation by the + the \l {class}{\\class} command, and the descriptions + are based on the argument of the \l {brief}{\\brief} + commands in the class documentation. + + \target list example + + \o \c classes + + The \c classes argument provides a complete alphabetical + list of the classes. Each class name is a link to the + class's reference documentation. + + For example: + + \quotation + \raw HTML +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    QAbstractButtonQAbstractExtensionManagerQAbstractItemModel
    QAbstractEventDispatcherQAbstractFormBuilderQAbstractItemView
    QAbstractExtensionFactoryQAbstractItemDelegateQAbstractListModel

    + \endraw + \endquotation + + A class is identified within the documentation by the + the \l {class}{\\class} command. + + \o \c classesbymodule + + This particular argument requests an additional argument, + i.e. a specification of the module. + + For example: + + \code + / *! + \page qtgui.html + \contentspage Qt Classes by Module + \previouspage QtCore Classes + \nextpage QtNetwork Classes + + \title QtGui Classes + + \keyword QtGui + + \generatelist {classesbymodule QtGui} + * / + \endcode + + Together, these arguments provide a table containing the + classes considered members of the specified module, + accompanied with a brief description. Each class name is + a link to the class's reference documentation. + + The generated table is rendered similarily to the one + generated when using the \l {table example}{\c + annotatedclasses} argument. + + For the basic classes in Qt, a class's module is + determined by its location, i.e. its directory. However, + for extensions, like ActiveQt and Qt Designer, a class + is related to a module with the \l + {inmodule}{\\inmodule} command. + + \o \c classesbyedition + + This particular argument requests an additional argument, + i.e. a specification of the edition. + + For example: + + \code + / *! + \page console-edition-classes.html + \title Qt Console Edition Classes + + \generatelist{classesbyedition Console} + * / + \endcode + + Together, these arguments provide a table containing the + classes considered members of the specified edition, + accompanied with a brief description. Each class name is + a link to the class's reference documentation. + + The edition a given class can be found in is determined by + the module it belongs to. + + \o \c compatclasses + + The \c compatclasses argument provides a complete and + alphabetical list of the support classes. A support + class is identified within the documentation by the \l + {compat}{\\compat} command. Each class name is a link to + the class's reference documentation. The list is + rendered similarily to the list generated by the \l + {list example}{\c classes} argument. + + \warning The \c classesbymodule argument will at some + point replace the this argument. + + \o \c functionindex + + The \c functionindex argument provides a complete + alphabetical list of all the documented member + functions. + + For example: + + \quotation + \raw HTML +

    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 

    + +

    DTDHandler: QXmlReader

    + +

    QAXCLASS: global

    + +

    QAXFACTORY_BEGIN: global

    + +

    QAXFACTORY_DEFAULT: global

    + +

    QAXFACTORY_END: global

    + + \endraw + + ... + \endquotation + + \o \c legalese + + The \c legalese argument provides a complete list of all + the licenses. The licenses are identified within the + documentation using the \l {legalese}{\\legalese} + command. + + For example: + + \quotation + \raw HTML +
    +

    + Copyright (c) 1989 The Regents of the + University of California. All rights reserved. +

    + +

    + Redistribution and use in source and binary + forms are permitted provided that the above + copyright notice and this paragraph are + duplicated in all such forms and that any + documentation, advertising materials, and other + materials related to such distribution and use + acknowledge that the software was developed by + the University of California, Berkeley... +

    + + + +
    +

    + Copyright (c) 1991 by AT&T. +

    + +

    + Permission to use, copy, modify, and distribute + this software for any purpose without fee is + hereby granted, provided that this entire notice + is included in all copies of any software which + is or includes a copy or modification of this + software and in all copies of the supporting + documentation for such software... +

    + + +
    + \endraw + ... + \endquotation + + \o \c mainclasses + + The \c mainclasses argument provides a complete + alphabetical list of the main classes. Each class name + is a link to the class's reference documentation. A + class is related to the group of main classes by using + the \l {mainclass}{\\mainclass} command. + + The list is rendered similarily to the list generated by + the \l {list example}{\c classes} argument. + + \o \c overviews + + The \c overviews argument provides a complete + alphabetical overview of the documentation. Each list + entry is a link to the respective documentation page. + + The list includes pages declared using commands like \l + {page}{\\page} and \l {group}{\\group}. The list omits + examples and classes, and only lists the first page of + documentation that contains two or more pages using + commands like \l {nextpage}{\\nextpage}. + + For example: + + \quotation + \raw HTML + + \endraw + \endquotation + + \o \c related + + The \c related argument is used in combination with the + \l {group}{\\group} command to list all the overviews + related to the given group. Each list entry is a link to + the respective documentation page. + + \o \c relatedinline + + The \c related argument is used in combination with the + \l {group}{\\group} command to collect all documentation + related to the given group. The various documentation + snippets are copied directly into the group page. + + \o \c service + + The \c service argument provides a complete alphabetical + list of the services. Each service name is a link to the + service's reference documentation. + + A service is identified within the documentation by the + \l {service}{\\service} command. + + \endlist + + + \row + \o \bold \\if \target if + \o \bold {The \\if command and the corresponding \\endif command + enclose parts of a QDoc comment that only will be included if + the condition specified by the command's argument is true.} + + The command reads the rest of the line and parses it as an + C++ #if statement. For example: + + \code + / *! + \if defined(opensourceedition) + + \bold{Note:} This edition is for the development of + \l{Qt Open Source Edition}{Free and Open Source} + software only; see \l{Qt Commercial Editions}. + + \endif + * / + \endcode + + This QDoc comment will only be rendered if the \c + opensourceedition preprocessor symbol is defined, and + specified in the \l {definesvariable}{defines} variable in + the configuration file to make QDoc process + the code within #ifdef and #endif: + + \code + defines = opensourceedition + \endcode + + You can also define the preprocessor symbol manually on the + command line. For more information see the documentation of + the \l {definesvariable}{defines} variable. + + See also \l{endif}{\\endif}, \l{else}{\\else}, \l + {definesvariable}{defines} and \l falsehoods. + + \row + \o \bold \\endif \target endif + \o \bold {The \\endif command and the corresponding \\if command + enclose parts of a QDoc comment that will be included if + the condition specified by the \l {if}{\\if} command's + argument is true.} + + For more information, see the documentation of the \l + {if}{\\if} command. + + See also \l{if}{\\if}, \l{else}{\\else}, \l + {definesvariable}{defines} and \l falsehoods. + + \row + \o \bold \\else \target else + \o \bold {The \\else command specifies an alternative if the + condition in the \l {if}{\\if} command is false.} + + The \\else command can only be used within \l + {if}{\\if...\\endif} commands, but is useful when there is + only two alternatives. For example: + + \code + / *! + The Qt 3 support library is provided to keep old + source code working. + + In addition to the \c Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + + \if !defined(QT3_SUPPORT) + \if defined(QT3_SUPPORTWARNINGS) + The compiler emits a warning when a + compatibility function is called. (This works + only with GCC 3.2+ and MSVC 7.) + \else + To use the Qt 3 support library, you need to + have the line QT += qt3support in your .pro + file (qmake automatically define the + QT3_SUPPORT symbol, turning on compatibility + function support). + + You can also define the symbol manually (e.g., + if you don't want to link against the \c + Qt3Support library), or you can define \c + QT3_SUPPORT_WARNINGS instead, telling the + compiler to emit a warning when a compatibility + function is called. (This works only with GCC + 3.2+ and MSVC 7.) + \endif + \endif + * / + \endcode + + If the \c QT3_SUPPORT is defined, the comment will be rendered + as + + \quotation + The Qt 3 support library is provided to keep old source + code working. + + In addition to the Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + \endquotation + + If \c QT3_SUPPORT isn't defined but \c QT3_SUPPORT_WARNINGS + is, the comment will be rendered as + + \quotation + The Qt 3 support library is provided to keep old source + code working. + + In addition to the Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + + The compiler emits a warning when a compatibility + function is called. (This works only with GCC 3.2+ and + MSVC 7.) + \endquotation + + If none of the symbols are defined, the comment will be + rendered as + + \quotation + The Qt 3 support library is provided to keep old + source code working. + + In addition to the \c Qt3Support classes, Qt 4 provides + compatibility functions when it's possible for an old + API to cohabit with the new one. + + To use the Qt 3 support library, you need to have the + line QT += qt3support in your .pro file (qmake + automatically define the QT3_SUPPORT symbol, turning on + compatibility function support). + + You can also define the symbol manually (e.g., if you + don't want to link against the \c Qt3Support library), + or you can define \c QT3_SUPPORT_WARNINGS instead, + telling the compiler to emit a warning when a + compatibility function is called. (This works only with + GCC 3.2+ and MSVC 7.) + \endquotation + + See also \l{if}{\\if}, \l{endif}{\\endif}, \l + {definesvariable}{defines} and \l falsehoods. + + \row + \o \bold \\include \target include + \o \bold {The \\include command expands to the contents of the + file specified by the command's argument.} + + \warning This is preliminary functionality. For more + information, see the \l + {26-qdoc-commands-compatibility.html#include-versus-input} + {compatibility} section. + + The command takes a file name as an argument, and is + useful when some piece of the documentation is used + repeatedly: Move the repetetive text into a separate file, + and use the \\include command whenever you want to insert + the separate documentation. + + The contents of such a file should follow QDoc syntax, + excluding the enclosing \c{/}\c{*!} ... \c{*}\c{/} marks. + To ensure that QDoc won't attempt to read the file as a + stand-alone piece of documentation, we recommend that you + use the \c .qdocinc extension. + + For example: + + \code + / *! + \page corefeatures.html + \title Core Features + + \include examples/signalandslots.qdocinc + \include examples/objectmodel.qdocinc + \include examples/layoutmanagement.qdocinc + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Core Features

    + \endraw + + \include examples/signalandslots.qdocinc + \include examples/objectmodel.qdocinc + \include examples/layoutmanagement.qdocinc + \endquotation + + Here is the actual \c .qdocinc files: \l + signalandslots.qdocinc, \l objectmodel.qdocinc, \l + layoutmanagement.qdocinc + + \row + \o \bold \\meta \target meta + \o \bold {The \\meta command is the QDoc equivalent to the HTML + \c meta tag.} + + The command accepts two arguments: The first argument (the + following word) is equivalent to the HTML meta tag's \i + name variable, and the second argument (the rest of the + line) is equivalent to the tag's \i contents variable. + + For example: + + \code + / *! + \meta author Summerfield + + \section1 Automatic Dialogs + + \abstract + This article shows how to maintain sets of + "attributes" (QVariant values), and how to allow + users to view and edit them using dialogs that are + created dynamically based on the attributes and + their types. + \endabstract + + The Attributes class described in this article holds a + set of QVariants, and can create a dialog to present + the QVariants to the user in an appropriate way. + + ... + * / + \endcode + + will be included in the generated HTML page as + + \code + + ... + + ... + + \endcode + + \row + \o \bold \\omit \target omit + \o \bold {The \\omit command and the correspondning \\endomit + command delimit parts of the documentation that + you want QDoc to skip.} + + For example: + + \code + / *! + \table + \row + \o Basic Widgets + \o Basic GUI widgets such as buttons, comboboxes + and scrollbars. + + \omit + \row + \o Component Model + \o Interfaces and helper classes for the Qt + Component Model. + \endomit + + \row + \o Database Classes + \o Database related classes, e.g. for SQL databases. + \endtable + * / + \endcode + + will be rendered as + + \raw HTML + + + + + + + + + + + +
    Basic WidgetsBasic GUI widgets such as buttons, comboboxes + and scrollbars.
    Database ClassesDatabase related classes, e.g. for SQL databases.
    + \endraw + + + \row + \o \bold \\raw \target raw + \o \bold {The \\raw command and the corresponding + \\endraw command delimit a block of raw mark-up language code.} + + The command takes an argument specifying the code's format; + currently the only supported format is HTML. + + The \\raw command is useful if you want some special HTML + effects in your documentation. For example: + + \code + / *! + Qt has some predefined QColor objects. For example: + + \raw HTML + + +

    + Blue(#0000ff), + dark blue(#000080) and + cyan(#00ffff). + \endraw + * / + \endcode + + will be rendered as + + \quotation + Qt has some predefined QColor objects. For example: + + \raw HTML + + +

    + Blue(#0000ff), + dark blue(#000080) and + cyan(#00ffff). + \endraw + \endquotation + + \row + \o \bold \\unicode \target unicode + \o \bold {The \\unicode command allows you to insert an + arbitrary Unicode character in the document.} + + The command takes an argument specifying the character as + an integer. By default, base 10 is assumed, unless a '0x' + or '0' prefix is specified (for base 16 and 8, + respectively). For example: + + \code + O G\unicode{0xEA}nio e as Rosas + + \unicode 0xC0 table en famille avec 15 \unicode 0x20AC par jour + + \unicode 0x3A3 \i{a}\sub{\i{i}} + \endcode + + will be rendered as + + \quotation + O G\unicode{0xEA}nio e as Rosas + + \unicode 0xC0 table en famille avec 15 \unicode 0x20AC par jour + + \unicode 0x3A3 \i{a}\sub{\i{i}} + \endquotation + + The \\raw command follows the same conventions as the \l + {i}{\\i} command for \l {argument}{punctuation and use of + braces} for the argument. + \endtable +*/ + +/*! + \page 12-1-signalandslots.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + + \title signalandslots.qdocinc + + \quotefile examples/signalandslots.qdocinc +*/ + +/*! + \page 12-2-objectmodel.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + + \title objectmodel.qdocinc + + \quotefile examples/objectmodel.qdocinc +*/ + +/*! + \page 12-3-layoutmanagement.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + + \title layoutmanagement.qdocinc + + \quotefile examples/layoutmanagement.qdocinc +*/ + +/*! + \page 13-qdoc-commands-topical.html + \previouspage Miscellaneous Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Contextual Commands + + \title Topical Commands + + The topical commands tell QDoc what is being documented + (i.e. existing units like classes, functions and examples), and + some of the commands allows you to create extra pages. + + \section1 Alphabetical List + + \l {13-qdoc-commands-topical.html#class}{\\class}, + \l {13-qdoc-commands-topical.html#enum}{\\enum}, + \l {13-qdoc-commands-topical.html#example-command}{\\example}, + \l {13-qdoc-commands-topical.html#externalpage}{\\externalpage}, + \l {13-qdoc-commands-topical.html#fn}{\\fn}, + \l {13-qdoc-commands-topical.html#group}{\\group}, + \l {13-qdoc-commands-topical.html#headerfile}{\\headerfile}, + \l {13-qdoc-commands-topical.html#macro}{\\macro}, + \l {13-qdoc-commands-topical.html#module}{\\module}, + \l {13-qdoc-commands-topical.html#namespace}{\\namespace}, + \l {13-qdoc-commands-topical.html#page}{\\page}, + \l {13-qdoc-commands-topical.html#property}{\\property}, + \l {13-qdoc-commands-topical.html#service}{\\service}, + \l {13-qdoc-commands-topical.html#typedef}{\\typedef}, + \l {13-qdoc-commands-topical.html#variable}{\\variable}, + + \section1 General Description + + When QDoc is processing a comment, it will try to connect the + documentation to the source code. For that reason it will first + look for the topical commands. If there is no such command, it + will try to tie the documentation to the immediately following + code. If there is no topical command, and the documentation cannot + be tied to following code, the documentation is simply lost. + + \target topical argument + + The documented unit's name is passed as the unique argument for + all the topical commands. The argument's naming convention is the + documented unit's complete name. For example: + + \code + \enum QComboBox::InsertPolicy + \endcode + + Functions is a special case, the argument's naming convention for + the \l {fn}{\\fn} command is that of the function's definition + outside the class definition. For example: + + \code + \fn void PreviewWindow::setWindowFlags() + \endcode + + A topical command can appear anywhere in a comment, but must stand + alone on its own line. If the argument spans several lines, make + sure that each line (except the last one) is ended with a + backslash. In addition QDoc counts parentheses, which means that + if it encounters a '(' it considers everything until the closing + ')' as its argument. + + If a topical command is repeated with different arguments, the + same documentation will appear for both the units. For example: + + \code + / *! + \fn void PreviewWindow::setWindowFlags() + \fn void ControllerWindow::setWindowFlags() + + Sets the widgets flags using the QWidget::setWindowFlags() + function. + + Then runs through the available window flags, creating a text + that contains the names of the flags that matches the flags + parameter, displaying the text in the widgets text editor. + * / + \endcode + + The \c PreviewWindow::setWindowFlags() and \c + ControllerWindow::setWindowFlags() functions will get the same + documentation. + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\class \target class + \o \bold {The \\class command tells QDoc that a class is + part of the public API, and lets you enter a detailed + description.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument, and supports + nested classes, for example: + + \code + / *! + \class QMap::iterator + + \brief The QMap::iterator class provides an STL-style + non-const iterator for QMap and QMultiMap. + + QMap features both \l{STL-style iterators} and + \l{Java-style iterators}. The STL-style iterators ... + * / + \endcode + + The generated HTML documentation for the specified class is + put in \c classname.html. For example, the + documentation for the \c PreviewWindow class is located in + \c previewwindow.html. + + \target framework + + In addition to render the detailed description, the \\class + comand will generate the documentation framework, i.e. a + list of the class's types, properties, functions, signals + and slots with empty documentation. + + The command is typically accompanied with a \l + {brief}{\\brief} command, a \l {mainclass}{\\mainclass} + command, an \l {ingroup}{\\ingroup} command and a \l + {sa}{\\sa} command. For example: + + \code + / *! + \class PreviewWindow + \brief The PreviewWindow class is a custom widget + displaying the names of its currently set + window flags in a read-only text editor. + + \mainclass + \ingroup miscellaneous + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the \l + {function}{setWindowFlags()} function. It is also + provided with a QPushButton that closes the window. + + ... + + \sa QWidget + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    PreviewWindow Class Reference

    + \endraw + + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. \l {preview window}{More...} + + \raw HTML +

    Properties

    + \endraw + + \list + \o 52 properties inherited from QWidget + \o 1 property inherited from QObject + \endlist + + \raw HTML +

    Public Functions

    + \endraw + + \list + \o \l {constructor}{PreviewWindow}(QWidget *parent = 0) + \o void \l {function}{setWindowFlags}(Qt::WindowFlags flags) + \endlist + + \list + \o 183 public functions inherited from QWidget + \o 28 public functions inherited from QObject + \endlist + + \raw HTML +

    Public Slots

    + \endraw + + \list + \o 17 public slots inherited from QWidget + \o 1 public slot inherited from QObject + \endlist + + \raw HTML +

    Additional Inherited Members

    + \endraw + + \list + \o 1 signal inherited from QWidget + \o 1 signal inherited from QObject + \o 4 static public members inherited from QWidget + \o 4 static public members inherited from QObject + \o 39 protected functions inherited from QWidget + \o 7 protected functions inherited from QObject + \endlist + + \target preview window + + \raw HTML +
    +

    Detailed Description

    + \endraw + + The PreviewWindow class is a custom widget displaying + the names of its currently set window flags in a + read-only text editor. + + The PreviewWindow class inherits QWidget. The widget + displays the names of its window flags set with the \l + {function}{setWindowFlags()} function. It is also + provided with a QPushButton that closes the window. + + ... + + See also QWidget. + + \raw HTML +
    +

    Member Function Documentation

    + \endraw + + \target constructor + \raw HTML +

    PreviewWindow(QWidget *parent = 0)

    + \endraw + + Constructs a preview window widget with \i parent. + + \target function + \raw HTML +

    setWindowFlags(Qt::WindowFlags flags)

    + \endraw + + Sets the widgets flags using the + QWidget::setWindowFlags() function. + + Then runs through the available window flags, + creating a text that contains the names of the flags + that matches the flags parameter, displaying + the text in the widgets text editor. + \endquotation + + \row + \o \bold \\enum \target enum + \o \bold {The \\enum command allows you to document a C++ enum.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The enum items are documented using the \l {value}{\\value} + command. If an item isn't documented, QDoc will emit a + warning. This can be avoided using the \l + {omitvalue}{\\omitvalue} command excluding an item from the + documentation. The enum documentation will be located in + the associated class, header file or namespace + documentation. + + For example: + + \code + enum Corner { + TopLeftCorner = 0x00000, + TopRightCorner = 0x00001, + BottomLeftCorner = 0x00002, + BottomRightCorner = 0x00003 + #if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN) + ,TopLeft = TopLeftCorner, + TopRight = TopRightCorner, + BottomLeft = BottomLeftCorner, + BottomRight = BottomRightCorner + #endif + }; + \endcode + + In case of the Qt::Corner enum, + + \code + / *! + \enum Qt::Corner + + This enum type specifies a corner in a rectangle: + + \value TopLeftCorner + The top-left corner of the rectangle. + \value TopRightCorner + The top-right corner of the rectangle. + \value BottomLeftCorner + The bottom-left corner of the rectangle. + \value BottomRightCorner + The bottom-right corner of the rectangle. + + \omitvalue TopLeft + \omitvalue TopRight + \omitvalue BottomLeft + \omitvalue BottomRight + * / + \endcode + + this associated QDoc comment will be rendered as + + \quotation + \raw HTML +

    enum Qt::Corner

    + +

    This enum type specifies a corner in a rectangle:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ConstantValueDescription
    Qt::TopLeftCorner0x00000The top-left corner of the rectangle.
    Qt::TopRightCorner0x00001The top-right corner of the rectangle.
    Qt::BottomLeftCorner0x00002The bottom-left corner of the rectangle.
    Qt::BottomRightCorner0x00003The bottom-right corner of the rectangle.
    + \endraw + \endquotation + + in qt.html. + + See also \l {value}{\\value} and \l {omitvalue}{\\omitvalue}. + + \row + \o \bold \\example \target example-command + \o \bold {The \\example command allows you to document an + example.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. In particular + the command's argument is the example's path relative to + the paths listed in the \l exampledirs configuration + variable. + + The documentation will be located in \i + {path-to-example}.html, and QDoc will add a list of all the + example files at the top of this documentation page. + + For example, if \l exampledirs contain \c + $QTDIR/examples/widgets/imageviewer, then + + \code + / *! + \example widgets/imageviewer + \title ImageViewer Example + \subtitle + + The example shows how to combine QLabel and QScrollArea + to display an image. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Image Viewer Example

    + \endraw + + Files: + \list + \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-cpp.html} + {widgets/imageviewer/imageviewer.cpp} + \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-h.html} + {widgets/imageviewer/imageviewer.h} + \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-main-cpp.html} + {widgets/imageviewer/main.cpp} + \endlist + + The example shows how to combine QLabel and QScrollArea + to display an image. + + ... + \endquotation + + in widgets-imageviewer.html. + + \row + \o \bold \\fn \target fn + \o \bold {The \\fn command allows you to document a function.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. In particular + it is important that the return type of the function, + whether it is \c const or not and the complete set of + arguments with type are included in the argument. If the + referenced function doesn't exist, QDoc will emit a + warning. + + Also, the \\fn command is QDoc's default command, i.e. when + no topical command can be found within a QDoc comment, QDoc + tries to tie the documentation to the following code as if + it was function documentation. + + This means that the command normally isn't necessary since + the recommended style is to write the function + documentation directly before the function implementation + in the \c .cpp file. In fact, it should only be used for + inline functions implemented in the \c .h file. + + For example: + + \code + / *! + \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const + + Returns true if this toolbar is dockable in the given + \a area; otherwise returns false. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const +

    + \endraw + + Returns true if this toolbar is dockable in the given + \a area; otherwise returns false. + \endquotation + + See also \l {overload}{\\overload}. + + \row + \o \bold \\group \target group + \o \bold {The \\group command creates a separate page that + lists the classes belonging to the group specified by the + command's argument.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. The \\group + command is typically followed by a \l {title}{\\title} + command and a short introduction to the group. The + generated HTML documentation for the specified group is put + in \i{group}.html. + + A class can be related to a group by using the \l + {ingroup}{\\ingroup} command. In addition, overviews can be + related to a group using the same command, but these must + be listed explicitly using the \l + {generatelist}{\\generatelist} command (see example below). + + Each class is listed with a link to the class reference + page and a brief description based on the classes' \l + {brief}{\\brief} texts. For example: + + \code + / *! + \group io + + \title Input/Output and Networking + + These classes are used to handle input and output to + and from external devices, processes, files etc. as + well as manipulating files and directories. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML + +

    Input/Output and Networking

    + +

    These classes are used to handle input and output + to and from external devices, processes, files etc. as + well as manipulating files and directories.

    + +

    +

    + + + + + + + + + + + +
    + QAbstractSocket + + The base functionality common to all socket types +
    + QBuffer + + QIODevice interface for a QByteArray +
    + QClipboard + + Access to the window system clipboard +
    + \endraw + \endquotation + + in io.html. + + Note that overviews related to the given group, must be + listed explicitly using the \l + {generatelist}{\\generatelist} command with the \c related + argument. For example: + + \code + / *! + \group architecture + + \title Architecture + + These documents describe aspects of Qt's architecture + and design, including overviews of core Qt features and + technologies. + + \generatelist{related} + * / + \endcode + + See also \l {ingroup}{\\ingroup} and \l + {generatelist}{\\generatelist}. + + \row + \o \bold \\headerfile \target headerfile + \o \bold {The \\headerfile command allows you to document + global functions, types and macros declared in a header file.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument, and the + generated HTML documentation for the specified header file + is put in \i{headerfilename}.html. + + A function, type or macro can be associated with a + headerfile using the \l {relates}{\\relates} command. + + If the referenced header file doesn't exist, the + \\headerfile command will still create a documentation page + for a header file with the referenced file's name. + + For example: + + \code + / *! + \headerfile + + \title Generic Algorithms + + \brief The header file provides + generic template-based algorithms. + + Qt provides a number of global template functions in \c + that work on containers and perform + well-know algorithms. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    <QtAlgorithms> - + Generic Algorithms

    +

    The header file provides generic + template-based algorithms. + More... +

    + +

    Functions

    +
    +
    + \endraw + + \target header + + \raw HTML +

    Detailed Description

    +

    The header file provides generic + template-based algorithms.

    + \endraw + + Qt provides a number of global template functions in \c + that work on containers and perform + well-know algorithms. + + ... + \endquotation + + in qtalgorithms.html. + + \row + \o \bold \\macro \target macro + \o \bold {The \\macro command allows you to document a C++ macro.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + QDoc recognizes three different macro syntax: function-like + macros like Q_ASSERT(), declaration-style macros like + Q_PROPERTY() and macros without parentheses like Q_OBJECT. + + The \\macro command must be followed by a \l + {relates}{\\relates} command which attaches the + documentation to that of a related class, header file. or + namespace. Otherwise the documentation will be lost. + + For example: + + \code + / *! + \macro void Q_ASSERT(bool test) + \relates + + Prints a warning message containing the source code + file name and line number if \a test is false. + + ... + + \sa Q_ASSERT_X(), qFatal(), {Debugging Techniques} + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    void Q_ASSERT ( bool test )

    + \endraw + + Prints a warning message containing the source code + file name and line number if \a test is false. + + ... + + See also Q_ASSERT_X(), qFatal() and \l {Debugging + Techniques}. + \endquotation + + in qtglobal.html. And + + \code + / *! + \macro Q_PROPERTY(...) + \relates QObject + + This macro declares a QObject property. The syntax is: + + ... + + \sa {Qt's Property System} + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Q_PROPERTY ( ... )

    + \endraw + + This macro declares a QObject property. The syntax is: + + ... + + See also \l {Qt's Property System}. + \endquotation + + in qobject.html. And + + \code + / *! + \macro Q_OBJECT + \relates QObject + + The Q_OBJECT macro must appear in the private section + of a class definition that declares its own signals and + slots or that uses other services provided by Qt's + meta-object system. + + ... + + \sa {Meta-Object System}, {Signals and Slots}, {Qt's + Property System} + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Q_OBJECT

    + \endraw + + The Q_OBJECT macro must appear in the private section + of a class definition that declares its own signals and + slots or that uses other services provided by Qt's + meta-object system. + + ... + + See also \l {Meta-Object System}, \l {Signals and + Slots} and \l {Qt's Property System}. + \endquotation + + in qobject.html. + + \row + \o \bold \\module \target module + \o \bold {The \\module creates a separate page that lists the + classes belonging to the module specified by the command's + argument.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + A class can be related to a module using the \l + {inmodule}{\\inmodule} command. + + The \\module command is typically followed by the \l + {title}{\\title} and \l {brief}{\\brief} commands. Each + class is listed with a link to the class reference page and + a brief description based on the classes' \l + {brief}{\\brief} texts. + + For example: + + \code + / *! + \module QtNetwork + + \title QtNetwork Module + + \brief The QtNetwork module offers classes that allow + you to write TCP/IP clients and servers. + + The network module provides classes to make network + programming easier and portable. It offers both + high-level classes such as QHttp and QFtp that + implement specific application-level protocols, and + lower-level classes such as QTcpSocket, QTcpServer, and + QUdpSocket. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    QtNetwork Module

    + \endraw + + The QtNetwork module offers classes that allow you to + write TCP/IP clients and servers.\l {module + details}{More...} + + \raw HTML +

    +

    + + + + + + + + + + + + +
    + QAbstractSocket + + The base functionality common to all socket types +
    + QFtp + + Implementation of the FTP protocol +
    ......
    + +


    + \endraw + + \target module details + + \raw HTML +

    Detailed Description

    + +

    + The QtNetwork module offers classes that allow you to + write TCP/IP clients and servers. +

    + +

    + The network module provides classes to make network + programming easier and portable. It offers both + high-level classes such as QHttp and QFtp that + implement specific application-level protocols, and + lower-level classes such as QTcpSocket, QTcpServer, and + QUdpSocket. +

    + \endraw + + ... + + \endquotation + + in qtnetwork.html. + + See also \l {inmodule}{\\inmodule} + + \row + \o \bold \\namespace \target namespace + \o \bold {The \\namespace command allows you to document a C++ + namespace.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + QDoc will generate the same additional links and + documentation for all the members of the namespace as it + does for \l {framework}{classes}. The documentation for + the specified namespace is put in \i + {namespace}.html. + + For example: + + \code + / *! + \namespace Qt + + \brief The Qt namespace contains miscellaneous + identifiers used throughout the Qt library. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Qt Namespace Reference

    +

    The Qt namespace contains miscellaneous + identifiers used throughout the Qt library. + More... +

    + +
    #include <Qt>
    + + + +

    Types

    + +
    + \endraw + + \target name + + \raw HTML +

    Detailed Description

    +

    The Qt namespace contains miscellaneous identifiers + used throughout the Qt library.

    + \endraw + + ... + \endquotation + + in qt.html. + + \row + \o \bold \\page \target page + \o \bold {The \\page command allows you to create a stand-alone + documentation page.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The page's title can be set using the \l {title}{\\title} + command. For example: + + \code + / *! + \page aboutqt.html + + \title About Qt + + Qt by Trolltech is a C++ toolkit for cross-platform GUI + application development. Qt provides single-source + portability across Microsoft Windows, Mac OS X, Linux, + and all major commercial Unix variants. (A version of + Qt 4 for embedded Linux will be available in + August/September 2005.) + + Qt provides application developers with all the + functionality needed to build applications with + state-of-the-art graphical user interfaces. Qt is fully + object-oriented, easily extensible, and allows true + component programming. + + ... + * / + \endcode + + will be rendered in its own HTML file: \l{About Qt}. + + \row + \o \bold {\\externalpage} \target externalpage + \o \bold {The \\externalpage command gives a title to + an external URL.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + For example: + + \code + / *! + \externalpage http://www.trolltech.com/products/embedded/index.html + \title Qtopia Core + * / + \endcode + + The QDoc comment above allows you to link to the Qtopia + Core webpage by simply linking to the given title. For + example: + + \code + / *! + The broad scope of the \l {Qtopia Core} API enables it to + be used across a wide variety of development projects. + * / + \endcode + + will be rendered as + + \quotation + The broad scope of the \l + {http://www.trolltech.com/products/embedded/index.html}{Qtopia + Core} API enables it to be used across a wide variety + of development projects. + \endquotation + + To achieve the same result without using the + \\externalpage command, you would have to hard code the + adress into your documentation: + + \code + / *! + The broad scope of the \l + {http://www.trolltech.com/products/embedded/index.html}{Qtopia + Core} API enables it to be used across a wide variety + of development projects. + * / + \endcode + + The \\externalpage command makes it easier to maintain the + documentation. If the adress changes, you only need to change the + argument of the \\externalpage command. + + \row + \o \bold \\property \target property + \o \bold {The \\property command allows you to document a Qt + property.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + A property is defined using the Q_PROPERTY() macro. The + macro takes as arguments the property's name and its set, + reset and get functions. For example: + + \code + Q_PROPERTY(QString state READ state WRITE setState) + \endcode + + The set, reset and get functions don't need to be + documented, documenting the property is sufficient. QDoc + will generate a list of the access function that will + appear in the property documentation which in turn will be + located in the documentation of the class that defines the + property. + + The \\property command is typically accompanied with a \l + {brief}{\\brief} command. In the case of a property, the + \l {brief}{\\brief} command's argument is a sentence + fragment that will be included in a one-sentence + description of the property generated by QDoc. The command + follows the same rules for the \l {brief + property}{description} as the \l {variable}{\\variable} + command. + + For example: + + \code + / *! + \property QPushButton::flat + \brief whether the border is disabled + + This property's default is false. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    flat : bool

    + \endraw + + This property holds whether the border is disabled. + + This property's default is false. + + Access functions: + + \list + \o \bold { bool isFlat () const} + \o \bold { void setFlat ( bool )} + \endlist + + \endquotation + + in qpushbutton.html. And + + \code + / *! + \property QWidget::width + \brief the width of the widget excluding any window frame + + See the \l {Window Geometry} documentation for an + overview of window geometry. + + \sa geometry, height, size + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    width : const int

    + \endraw + + This property holds the width of the widget excluding + any window frame. + + See the \l {Window Geometry} documentation for an + overview of window geometry. + + Access functions: + + \list + \o \bold { int width () const} + \endlist + + See also \l{QWidget::geometry}{geometry}, + \l{QWidget::height}{height}, and \l{QWidget::size}{size}. + \endquotation + + in qwidget.html. + + \row + \o \bold \\service \target service + + \o \bold {The \\service command tells QDoc that a class is a + service class and specifies its alias, i.e. the associated + service's name.} + + The command takes two arguments, the service class's name + and the associated alias. For example: + + \code + / *! + \service TimeService Time + ... + * / + class TimeService : public QCopObjectService + { + ... + } + \endcode + + See also \l {class}{\\class} and \l + {generatelist}{\\generatelist}. + + \row + \o \bold \\typedef \target typedef + \o \bold {The \\typedef command allows you to document a C++ type + definition.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The documentation will be located in the associated class, + header file or namespace documentation. When documenting a + global type definition, the \\typedef command must be + accompanied with a \l {relates}{\\relates} command. For + example: + + \code + / *! + \typedef QObjectList + \relates QObject + + Synonym for QList. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    typedef QObjectList

    + \endraw + + Synonym for QList. + \endquotation + + in qobject.html. Another, although more rare, example is + + \code + / *! + \typedef QMsgHandler + \relates QtGlobal + + This is a typedef for a pointer to a function with the + following signature: + + \code + void myMsgHandler(QtMsgType, const char *); + \ endcode + + \sa QtMsgType, qInstallMsgHandler() + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    typedef QtMsgHandler

    + \endraw + + This is a typedef for a pointer to a function with the + following signature: + + \raw HTML + +
        void myMsgHandler(QtMsgType, const char *);
    +
    + \endraw + + See also QtMsgType and qInstallMsgHandler(). + + \endquotation + + in qtglobal.html. Other type definitions are located in the + documentation of the class that defines it, for example: + + \code + / *! + \typedef QLinkedList::Iterator + + Qt-style synonym for QList::iterator. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    typedef QLinkedList::Iterator

    + \endraw + + Qt-style synonym for QList::iterator. + \endquotation + + in qlinkedlist.html. + + \row + \o \bold \\variable \target variable + \o \bold {The \\variable command allows you to document a + member variable or a constant.} + + The command follows \l {topical argument}{the general + topical command convention} for the argument. + + The \\variable command is typically followed by a \l + {brief}{\\brief} command; QDoc will generate the + documentation for the variable based on the brief + description. The command follows the same rules for the \l + {brief property}{description} as the \l + {property}{\\property} command. + + The documentation will be located in the in the associated + class, header file or namespace documentation. + + In case of a member variable: + + \code + / *! + \variable QStyleOption::palette + \brief the palette that should be used when painting + the control + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    + + QPalette + + QStyleOption::palette +

    + \endraw + + This variable holds the palette that should be used + when painting the control. + \endquotation + + in qstyleoption.html. + + But you can also use the \\variable command to document + constants like for example the \c Type and \c UserType + constants in the QTreeWidgetItem class: + + \code + enum { Type = 0, UserType = 1000 }; + \endcode + + Then + + \code + / *! + \variable QTreeWidgetItem::Type + + The default type for tree widget items. + + \sa UserType, type() + * / + \endcode + + and + + \code + / *! + \variable QTreeWidgetItem::UserType + + The minimum value for custom types. Values below + UserType are reserved by Qt. + + \sa Type, type() + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    + const int QTreeWidgetItem::Type +

    + \endraw + + The default type for tree widget items. + + See also \l {QTreeWidgetItem::UserType}{UserType} and + \l {QTreeWidgetItem::type()}{type()}. + + \raw HTML +

    + const int QTreeWidgetItem::UserType +

    + \endraw + + The minimum value for custom types. Values below + UserType are reserved by Qt. + + See also \l {QTreeWidgetItem::Type}{Type} and + \l{QTreeWidgetItem::type()}{type()}. + + \endquotation + + in qtreewidget.html. + \endtable +*/ + +/*! + \page 14-qdoc-commands-contextualcommands.html + \previouspage Topical Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Navigation Commands + + \title Contextual Commands + + The contextual commands provide QDoc with information, that it + wouldn't figure out otherwise, about the documented object. For + example whether a class is thread-safe or not. + + These commands can appear anywhere within a QDoc comment. + + \section1 Alphabetical List + + \l {16-qdoc-commands-status.html#compat}{\\compat}, + \l {15-qdoc-commands-navigation.html#contentspage}{\\contentspage}, + \l {15-qdoc-commands-navigation.html#indexpage}{\\indexpage}, + \l {19-qdoc-commands-grouping.html#ingroup}{\\ingroup}, + \l {19-qdoc-commands-grouping.html#inmodule}{\\inmodule}, + \l {16-qdoc-commands-status.html#internal}{\\internal}, + \l {19-qdoc-commands-grouping.html#mainclass}{\\mainclass}, + \l {15-qdoc-commands-navigation.html#nextpage}{\\nextpage}, + \l {17-qdoc-commands-thread.html#nonreentrant}{\\nonreentrant}, + \l {16-qdoc-commands-status.html#obsolete}{\\obsolete}, + \l {18-qdoc-commands-relating.html#overload}{\\overload}, + \l {16-qdoc-commands-status.html#preliminary}{\\preliminary}, + \l {15-qdoc-commands-navigation.html#previouspage}{\\previouspage}, + \l {17-qdoc-commands-thread.html#reentrant}{\\reentrant}, + \l {18-qdoc-commands-relating.html#reimp}{\\reimp}, + \l {18-qdoc-commands-relating.html#relates}{\\relates}, + \l {15-qdoc-commands-navigation.html#startpage}{\\startpage}, + \l {17-qdoc-commands-thread.html#threadsafe}{\\threadsafe}, + \l {20-qdoc-commands-title.html#title}{\\title} + + \section1 Categories + \list + \o \l {Navigation Commands} + \o \l {Status Commands} + \o \l {Thread Support Commands} + \o \l {Relating Commands} + \o \l {Grouping Commands} + \o \l {Title Commands} + \endlist +*/ + +/*! + \page 15-qdoc-commands-navigation.html + \previouspage Contextual Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Status Commands + + \title Navigation Commands + + The navigation commands allow you to link the pages of a multipage + document together. They provide the components of a navigation bar + at the top and bottom of the document. They also provide browser + and search engine support. + + \section1 Alphabetical List + + \l {15-qdoc-commands-navigation.html#contentspage}{\\contentspage}, + \l {15-qdoc-commands-navigation.html#indexpage}{\\indexpage}, + \l {15-qdoc-commands-navigation.html#nextpage}{\\nextpage}, + \l {15-qdoc-commands-navigation.html#previouspage}{\\previouspage}, + \l {15-qdoc-commands-navigation.html#startpage}{\\startpage} + + \section1 General Description + + The QDoc comments below shows a typical example using the + navigation commands. + + \code + / *! + \page basicqt.html + \contentspage {Basic Qt}{Contents} + \nextpage Getting Started + + \indexpage Index + \startpage Basic Qt + + \title Basic Qt + + The Qt toolkit is a C++ class library and a set of tools for + building multiplatform GUI programs using a "write once, + compile anywhere approach". + + Table of contents: + + \list + \o \l {Getting Started} + \o \l {Creating Dialogs} + \o \l {Creating Main Windows} + \endlist + * / + + / *! + \page gettingstarted.html + \previouspage Basic Qt + \contentspage {Basic Qt}{Contents} + \nextpage Creating Dialogs + + \indexpage Index + \startpage Basic Qt + + \title Getting Started + + This chapter shows how to combine basic C++ with the + functionality provided by Qt to create a few small graphical + interface (GUI) applications. + * / + + / *! + \page creatingdialogs.html + \previouspage Getting Started + \contentspage {Basic Qt}{Contents} + + \indexpage Index + \startpage Basic Qt + + \title Creating Dialogs + + This chapter will teach you how to create dialog boxes using Qt. + * / + + / *! + \page index.html + + \indexpage Index + \startpage Basic Qt + + \title Index + + \list + \o \l {Basic Qt} + \o \l {Creating Dialogs} + \o \l {Getting Started} + \endlist + * / + \endcode + + The second page of this multipage document, "Getting Started", + will be rendered as + + \quotation + \raw HTML + + + +

    + [Previous: + Basic Qt] + [Contents] + [Next: + Creating Dialogs] +

    + +

    Getting Started

    + +

    + This chapter shows how to combine basic C++ with the + functionality provided by Qt to create a few small graphical + interface (GUI) applications. +

    + +

    + [Previous: + Basic Qt] + [Contents] + [Next: + Creating Dialogs] +

    + +
    + \endraw + \endquotation + + in creatingdialogs.html. + + In addition, the \l {indexpage}{\\indexpage} and \l + {startpage}{\\startpage} commands specifies links to the page's + index page and start page. These links are used by browsers and + search engines. + + The index page is typically an alphabetical list of the document's + titles and topics, while the start page is the page considered by + the author to be the starting point of a multipage document. + + The links are included in the generated HTML source code but has + no visual effect on the documentation: + + \code + + ... + + + ... + + \endcode + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\previouspage \target previouspage + \o \bold {The \\previouspage command links the current page + to the previous one in an ordered series of documents}. + + The command has two arguments, each enclosed by curly + braces: The first is the link target, i.e. the title of the + previous page, the second is the link text. If the page's + title is equivalent to the link text, the second argument + can be omitted. + + The command must stand alone on its own line. + + In the end, the link is rendered at the top and bottom of + the current page. For an example, see the \l {General + Description} section. + + \row + \o \bold \\nextpage \target nextpage + \o \bold {The \\nextpage command links the current + page to the next page in an ordered series of documents}. + + The command follows the same syntax and argument convention + as the \l {previouspage}{\\previouspage} command. + + For an example, see the \l {General Description} section. + + \row + \o \bold \\startpage \target startpage + \o \bold {The \\startpage command specifies the first document + in a collection of documents.} + + The command must stand alone on its own line, and its + unique argument is the title of the first document. + + QDoc will generate a link to the specified document which + is included in the HTML file but has no visual effect on + the documentation. The generated link type tells browsers + and search engines which document is considered by the + author to be the starting point of the collection. + + For an example, see the \l {General Description} section. + + \row + \o \bold \\contentspage \target contentspage + \o \bold {The \\contentspage command links the current + page to a contents page}. + + The command follows the same syntax and argument convention + as the \l {previouspage}{\\previouspage} command. + + For an example, see the \l {General Description} section. + + \row + \o \bold \\indexpage \target indexpage + \o \bold {The \\indexpage command specifies a document providing + an index for the current document}. + + The command must stand alone on its own line, and its + unique argument is the title of the index document. + + QDoc will generate a link to the specified document which + is included in the HTML file but has no visual effect on + the documentation. The generated link type tells browsers + and search engines which document is considered by the + author to be the index page for the current document. + + For an example, see the \l {General Description} section. + + \endtable +*/ + +/*! + \page 16-qdoc-commands-status.html + \previouspage Navigation Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Thread Support Commands + + \title Status Commands + + The usage commands can indicate whether a documented object is + under development, becoming obsolete, provided for compatibility + reasons or simply not part of the public interface. They can + describe the history of minor versions. And they can also describe + a documented object's ability to handle multithreaded programming. + + \section1 Alphabetical List + + \l {16-qdoc-commands-status.html#compat}{\\compat}, + \l {16-qdoc-commands-status.html#internal}{\\internal}, + \l {16-qdoc-commands-status.html#obsolete}{\\obsolete}, + \l {16-qdoc-commands-status.html#preliminary}{\\preliminary}, + \l {16-qdoc-commands-status.html#since}{\\since} + + \section1 Command Description + + \table + \header + \o Command + \o Description + + \row + \o \bold \\preliminary \target preliminary + \o \bold {The \\preliminary command indicates that the + referenced function is under development.} + + The command must stand on its own line. + + The \\preliminary command expands to a notification in the + function documentation, and marks the function as + preliminary when it appears in lists. For example: + + \code + / *! + \preliminary + + Returns information about the joining properties of the + character (needed for certain languages such as + Arabic). + * / + QChar::Joining QChar::joining() const + { + return ::joining(*this); + } + \endcode + + will be rendered as + + \quotation + \raw HTML +

    + Joining + QChar::joining () const

    + \endraw + + \bold {This function is under development and + is subject to change.} + + Returns information about the joining properties of the + character (needed for certain languages such as + Arabic). + \endquotation + + And the function's entry in QChar's list of functions will + be rendered as + + \quotation + \list + \o ... + \o Joining + \l {http://qt.nokia.com/doc/4.0/qchar.html#Joining-enum} + {joining}() + const \c (preliminary) + \o ... + \endlist + \endquotation + + \row + \o \bold \\obsolete \target obsolete + \o \bold {The \\obsolete command indicates that the referenced + function no longer should be used in new code; + there is no guarantee for how long it will remain in + the library.} + + The command must stand on its own line. + + When generating the reference documentation for a class, + QDoc will create and link to a separate page documenting + its obsolete functions. Usually an equivalent function is + provided as an alternative. + + For example: + + \code + / *! + \fn MyClass::MyObsoleteFunction + \obsolete + + Use MyNewFunction() instead. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Obsolete Members for MyClass

    + \endraw + + \bold {The following class members are obsolete.} They + are provided to keep old source code working. We + strongly advise against using them in new code. + + ... + + \list + \o void MyObsoleteFunction() \c (obsolete) + \o ... + \endlist + + \raw HTML +
    +

    Member Function Documentation

    +

    void MyObsoleteFunction ()

    +

    Use MyNewFunction() instead.

    + \endraw + + ... + \endquotation + + in myclass-obsolete.html + + + \row + \o \bold \\compat \target compat + \o \bold {The \\compat command indicates that the referenced class + or function is part of the support library provided to keep + old source code working.} + + The command must stand on its own line. + + Usually an equivalent function or class is provided as an + alternative. + + If the command is used within the documentation of a class, + the command expands to a warning that the referenced class + is part of the support library. The warning is located on + top of the associated documentation. For example: + + \code + / *! + \class MyQt3SupportClass + \compat + * / + \endcode + + will be rendered as + + \quotation + \bold {This class is part of the Qt 3 support + library.} It is provided to keep old source code + working. We strongly advise against using it in new + code. See the \l + {http://qt.nokia.com/doc/4.0/porting4.html}{Porting + Guide} for more information. + \endquotation + + on the top of the MyQt3SupportClass class reference. + + If the command is used when documenting a function, QDoc + will create and link to a separate page documenting Qt 3 + support members when generating the reference documentation + for the associated class. For example: + + \code + / *! + \fn MyClass::MyQt3SupportMemberFunction + \compat + + Use MyNewFunction() instead. + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Qt 3 Support Members for MyClass

    + \endraw + + \bold {The following class members are part of the Qt + 3 support layer.} They are provided to help you port + old code to Qt 4. We advise against using them in new + code. + + ... + + \list + \o void MyQt3SupportMemberFunction() + \o ... + \endlist + + \raw HTML +
    +

    Member Function Documentation

    +

    void MyQt3SupportMemberFunction ()

    +

    Use MyNewFunction() instead.

    + \endraw + + ... + \endquotation + + in myclass-qt3.html + + + \row + \o \bold \\internal \target internal + \o \bold {The \\internal command indicates that the referenced + function is not part of the public interface.} + + The command must stand on its own line. + + QDoc ignores the documentation as well as the documented + item, when generating the associated class reference + documenation. For example: + + \code + / *! + \internal + + Tries to find the decimal separator. If it can't find + it and the thousand delimiter is != '.' it will try to + find a '.'; + * / + int QDoubleSpinBoxPrivate::findDelimiter + (const QString &str, int index) const + { + int dotindex = str.indexOf(delimiter, index); + if (dotindex == -1 && thousand != dot && delimiter != dot) + dotindex = str.indexOf(dot, index); + return dotindex; + } + \endcode + + in qspinbox.cpp, will not be rendered at all. + + \row + \o \bold \\since \target since + \o \bold {The \\since command tells in which minor release + the associated functionality was added.} + + For example: + + \code + / *! + \since 4.1 + + Returns an icon for \a standardIcon. + + ... + + \sa standardIconImplementation(), standardPixmap() + * / + QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const + { + } + \endcode + + will be rendered as + + \quotation + \raw HTML +

    QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const

    + \endraw + + This function was introduced in Qt version 4.1 + + Returns an icon for \a standardIcon. + + ... + + See also \l + {QStyle::standardIconImplementation()}{standardIconImplementation()} + and \l {QStyle::standardPixmap()}{standardPixmap()}. + \endquotation + + QDoc generates the "Qt" reference from the \l + {25-qdoc-configuration-derivedprojects.html#project}{\c + project} configuration variable. For that reason this + reference will change according to the current + documentation project. + + See also \l + {25-qdoc-configuration-derivedprojects.html#project}{\c + project}. + + \endtable +*/ + +/*! + \page 17-qdoc-commands-thread.html + \previouspage Status Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Relating Commands + + \title Thread Support Commands + + The thread support commands specify the level of support for + multithreaded programming of a class or function. + + \section1 Alphabetical List + + \l {17-qdoc-commands-thread.html#nonreentrant}{\\nonreentrant}, + \l {17-qdoc-commands-thread.html#reentrant}{\\reentrant}, + \l {17-qdoc-commands-thread.html#threadsafe}{\\threadsafe} + + \section1 General Description + + There are three levels of support for multithreaded programming of + a class or function: \c threadsafe, \c reentrant and \c + nonreentrant. + + The default is \c nonreentrant which means that the associated + class or function cannot be called by multiple threads. \c + Reentrant and \c threadsafe are levels primarily used for classes. + + \c Reentrant means that all the functions in the referenced class + can be called simultaneously by multiple threads, provided that + each invocation of the functions reference unique data. While \c + threadsafe means that all the functions in the referenced class + can be called simultaneously by multiple threads even when each + invocation references shared data. + + When a class is declared \c reentrant or \c threadsafe, using the + \l {reentrant}{\\reentrant} and \l {threadsafe}{\\threadsafe} + commands respectively, functions in the referenced class can be + declared \c nonreentrant, using the \l + {nonreentrant}{\\nonreentrant} command, excluding the functions + from the general view. + + For example: + + \code + / *! + \class QLocale + \brief The QLocale class converts between numbers and their + string representations in various languages. + + \reentrant + \ingroup i18n + \ingroup text + \mainclass + + QLocale is initialized with a language/country pair in its + constructor and offers number-to-string and string-to-number + conversion functions similar to those in QString. + + ... + * / + + / *! + \nonreentrant + + Sets the global default locale to \a locale. These values are + used when a QLocale object is constructed with no + arguments. If this function is not called, the system's locale + is used. + + \warning In a multithreaded application, the default locale + should be set at application startup, before any non-GUI + threads are created. + + \sa system() c() + * / + void QLocale::setDefault(const QLocale &locale) + { + default_d = locale.d; + } + \endcode + + will be rendered as + + \quotation + \raw HTML +

    QLocale Class Reference

    + \endraw + + The QLocale class converts between numbers and their string + representations in various languages. More... + + \code + #include + \endcode + + \bold {Note:} All the functions in this class are \l + {threads.html#reentrant}{reentrant}, except \l + {QLocale::setDefault()}{setDefault()}. + + ... + + \raw HTML +
    +

    Member Type Documentation

    + \endraw + + ... + + \raw HTML +

    void QLocale::setDefault ( const QLocale & locale )

    + \endraw + + Sets the global default locale to locale. These values are + used when a QLocale object is constructed with no + arguments. If this function is not called, the system's locale + is used. + + \warning In a multithreaded application, the default locale + should be set at application startup, before any non-GUI + threads are created. + + \warning This function is not reentrant. + + See also \l {QLocale::system()}{system()} and \l + {QLocale::c()}{c()}. + + ... + \endquotation + + As shown above, QDoc generates a notification when a class is + declared reentrant, and lists the exceptions (the declared + nonreentrant functions). A link to the general documentation on \l + {threads.html#reentrant}{reentrancy and thread-safety} is + included. In addition a warning, "\bold Warning: This function is + not reentrant.", is generated in the nonreentrant functions' + documentation. + + QDoc will generate the same notification and warnings when a class + is declared threadsafe. + + For more information see the general documentation on \l + {threads.html#reentrant}{reentrancy and thread-safety}. + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\threadsafe \target threadsafe + \o \bold {The \\threadsafe command indicates that the + associated class or function can be called simultaneously by + multiple threads even when each invocation references + shared data.} + + The command must stand on its own line. + + The generated documentation resulting from using the + \\threadsafe command is similar to the result of using the + \l {reentrant}{\\reentrant} command. For an example, see + the \l {General Description} section. + + See also \l{reentrant}{\\reentrant} and + \l{nonreentrant}{\\nonreentrant}. + + \row + \o \bold \\reentrant \target reentrant + \o \bold {The \\reentrant command indicates that the associated + class or function can be called simultaneously + by multiple threads, provided that each invocation of the + functions reference unique data.} + + The command must stand on its own line. + + For an example, see the \l {General Description} section. + + See also \l{nonreentrant}{\\nonreentrant} and + \l{threadsafe}{\\threadsafe}. + + \row + \o \bold \\nonreentrant \target nonreentrant + \o \bold {The \\nonreentrant command indicates that the + associated class or function cannot be called by + multiple threads.} + + The command must stand on its own line. + + For an example, see the \l {General Description} section. + + See also \l{reentrant}{\\reentrant} and + \l{threadsafe}{\\threadsafe}. + + \endtable +*/ + +/*! + \page 18-qdoc-commands-relating.html + \previouspage Thread Support Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Grouping Commands + + \title Relating Commands + + The relation commands discribe how the documented object relates + to its context: Whether it is an overloaded function, a + reimplemented function or a global function related to a specified + class or header file. + + \section1 Alphabetical List + + \l {18-qdoc-commands-relating.html#overload}{\\overload}, + \l {18-qdoc-commands-relating.html#reimp}{\\reimp}, + \l {18-qdoc-commands-relating.html#relates}{\\relates}, + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\overload \target overload + \o \bold {The \\overload command indicates that the + function is a secondary overload of its name.} + + The command must stand on its own line. + + For any overloaded function (except constructors), QDoc + expects one primary version of the function and all the + the overloads marked with the \bold{\\overload command}. + The primary version should be fully documented. Each + overload can have whatever extra documentation you want + to add for just that overload. + + From Qt 4.5, you can include the function name plus '()' + as a parameter to the \bold{\\overload} command, which + will include a standard \i{This function overloads...} + line of text with a link to the documentation for the + primary version of the function. + + For example: + + \code + / *! + \overload addAction() + + This convenience function creates a new action with an + \a icon and some \a text. The function adds the newly + created action to the menu's list of actions, and + returns it. + + \sa QWidget::addAction() + * / + QAction *QMenu::addAction(const QIcon &icon, const QString &text) + { + QAction *ret = new QAction(icon, text, this); + addAction(ret); + return ret; + } + \endcode + + will be rendered as + + \quotation + \raw HTML +

    QAction + * QMenu::addAction ( const QIcon & icon, + const QString & text ) +

    + \endraw + + This function overloads \l {http://qt.nokia.com/doc/4.0/qwidget.html#addAction}{addAction()} + + This convenience function creates a new action with an + \i icon and some \i text. The function adds the newly + created action to the menu's list of actions, and + returns it. + + See also + \l {http://qt.nokia.com/doc/4.0/qwidget.html#addAction} + {QWidget::addAction}(). + \endquotation + + If you don't include the function name with the + \bold{\\overlaod} command, then instead of the "This + function overloads..." line with the link to the + documentation for the primary version, you get the old + standard line: + + \quotation + This is an overloaded member function, provided for + convenience. + \endquotation. + + \row + \o \bold \\reimp \target reimp + \o \bold {The \\reimp command indicates that the + referenced function is a reimplementation of a virtual function, + where the reimplementation has no effect on the interface.} + + The command must stand on its own line. + + QDoc will omit the reimplemented function from the class + reference. For example: + + \code + / *! + \reimp + * / + void QToolButton::nextCheckState() + { + Q_D(QToolButton); + if (!d->defaultAction) + QAbstractButton::nextCheckState(); + else + d->defaultAction->trigger(); + } + \endcode + + will not be rendered at all; only a link to the inherited + QAbstractButton::nextCheckState() will appear in the + documentation. + + \row + \o \bold \\relates \target relates + \o \bold {The \\relates command attaches the documentation of + a global function to that of a related class or header file.} + + The command's argument is a class name, an the command (and + its argument) must stand on its own line. + + \code + / *! + \relates QChar + + Reads a char from the stream \a in into char \a chr. + + \sa {Format of the QDataStream operators} + * / + QDataStream &operator>>(QDataStream &in, QChar &chr) + { + quint16 u; + in >> u; + chr.unicode() = ushort(u); + return in; + } + \endcode + + will be rendered with the QChar documentation. + + \endtable +*/ + +/*! + \page 19-qdoc-commands-grouping.html + \previouspage Relating Commands + \contentspage QDoc Manual - Table of Contents + \nextpage Title Commands + + \title Grouping Commands + + The grouping commands relate classes to defined groups and + modules. The groups are used when generating lists of related + classes in the documentation, while the modules are elements of + Qt's structure. + + \section1 Alphabetical List + + \l {19-qdoc-commands-grouping.html#ingroup}{\\ingroup}, + \l {19-qdoc-commands-grouping.html#inmodule}{\\inmodule}, + \l {19-qdoc-commands-grouping.html#mainclass}{\\mainclass}, + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\mainclass \target mainclass + \o \bold {The \\mainclass command relates the documented class to + a group called mainclasses.} + + The command must stand on its own line. + + For example: + + \code + / *! + \class QWidget qwidget.h + \brief The QWidget class is the base class of + all user interface objects. + + \mainclass + + ... + * / + \endcode + + will ensure that the QWidget class is included in the \c + mainclasses group, which means, for example, that the class + will appear on the list created by calling the \l + {generatelist}{\\generatelist} command with the \c + mainclasses argument: + + \l http://qt.nokia.com/doc/4.0/mainclasses.html + + See also \l {generatelist}{\\generatelist}. + + \row + \o \bold \\ingroup \target ingroup + + \o \bold {The \\ingroup command indicates that the given + overview or documented class belongs to a certain group of + related docmentation.} + + A class or overview may belong to many groups. + + The \\ingroup command's argument is a group name, but note + that the command considers the rest of the line as part of + its argument. Make sure that the group name is followed by + a linebreak. For example: + + \code + / *! + \class QDir + \brief The QDir class provides access to directory + structures and their contents. + + \ingroup io + ... + * / + \endcode + + will ensure that the QDir class is included in the \c io + group, which means, for example, that QDir will appear on + the list created by calling the \l {group}{\\group} command + with the \c io argument. + + Note that to list overviews that are related to a given + group, you must generate the list exlicitly by using the \l + {generatelist}{\\generatelist} command with the \c related + argument. + + See also \l {group}{\\group}. + \row + \o \bold \\inmodule \target inmodule + \o \bold {The \\inmodule command relates the documented class + to the module specified by the command's argument.} + + For the basic classes in Qt, a class's module is determined + by its location, i.e. its directory. However, for + extensions, like ActiveQt and Qt Designer, a class needs to + be related to a module explicitly. + + The command's argument is a module name, but note that the + command considers the rest of the line as part of its + argument. Make sure that the module name is followed by a + linebreak. For example: + + \code + /*! + \class QDesignerTaskMenuExtension + \inmodule QtDesigner + * / + \endcode + + will ensure that the QDesignerTaskMenuExtension class is + included in the \c QtDesigner module, which means, for + example, that the class will appear on the list created by + calling the \l {generatelist}{\\generatelist} command with + the \c {{classesbymodule QtDesigner}} argument. + + See also \l {module}{\\module} and \l + {generatelist}{\\generatelist}. + \endtable +*/ + +/*! + \page 20-qdoc-commands-title.html + \previouspage Grouping Commands + \contentspage QDoc Manual - Table of Contents + \nextpage QDoc Configuration + + \title Title Commands + + In general a title command considers everything that follows it + until the first line break as its argument. If the title needs to + be spanned over several lines, make sure to end each line (except + the last one) with a backslash. + + \section1 Alphabetical List + + \l {20-qdoc-commands-title.html#title}{\\title}, + \l {20-qdoc-commands-title.html#subtitle}{\\subtitle} + + \section1 Command Descriptions + + \table + \header + \o Command + \o Description + + \row + \o \bold \\title \target title + \o \bold {The \\title command sets the title for a + documentation page, or allows you to override it.} + + For example: + + \code + / *! + \page signalandslots.html + + \title Signals and Slots + + Signals and slots are used for communication between + objects. The signals and slots mechanism is a central + feature of Qt and probably the part that differs most + from the features provided by other frameworks. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Signal and Slots

    + \endraw + + Signals and slots are used for communication between + objects. The signals and slots mechanism is a central + feature of Qt and probably the part that differs most + from the features provided by other frameworks. + + ... + \endquotation + See also \l {subtitle}{\\subtitle}. + + \row + \o \bold \\subtitle \target subtitle + \o \bold {The \\subtitle command sets a subtitle for a + documentation page.} + + For example: + + \code + / *! + \page qtopiacore-overview.html + + \title Qtopia Core + \subtitle Qt for Embedded Linux + + Qt/Embedded, the embedded Linux port of Qt, is a + complete and self-contained C++ GUI and platform + development tool for Linux-based embedded development. + + ... + * / + \endcode + + will be rendered as + + \quotation + \raw HTML +

    Qtopia Core

    +

    Qt for Embedded Linux

    + \endraw + + Qt/Embedded, the embedded Linux port of Qt, is a + complete and self-contained C++ GUI and platform + development tool for Linux-based embedded development. + + ... + \endquotation + + See also \l {title}{\\title}. + \endtable +*/ + +/*! + \page 21-0-qdoc-configuration.html + \previouspage Title Commands + \contentspage QDoc Manual - Table of Contents + \nextpage General Variables + + \title QDoc Configuration + + \tableofcontents + + \list + \o \l {Supporting Derived Projects} + \o \l {QDoc Compatibility} + \endlist + + When running QDoc to generate the documentation, you must specify + a configuration file on the command line: + + \quotation + \bold {/currentdirectory$ qdoc3 my-documentation.qdocconf} + \endquotation + + \section1 General Description + + The configuration file is a list of entries of entries of the form + \i {"variable = value"}. Using the configuration variables, you + can define where QDoc should find the various source files, images + and examples, where to put generated documentation etc. The + configuration file can also contain directives like \c + include. For an example, see the \l minimum.qdocconf file. + + In addition, you can use some particular configuration variables + to make QDoc support derived projects, i.e make the projects, for + example Qt Solutions, contain links to the online Qt + documentation. These variables are documented in the \l + {Supporting Derived projects} section. In this section you can + also find out how to use these variables to support your derived + projects. + + If some of the variable keys have the same values, they can be set + at the same time. For example: + + \code + {header, source}dirs = kernel + \endcode + + is equivalent to + + \code + headerdirs = kernel + sourcedirs = kernel + \endcode + + A variable's value can be set using either '=' or '+='. The + difference is that '=' overrides any previously set value, while + '+=' only adds the value to the previously set ones. + + In general, some of the variables accepts a list of strings as + their value, while others only accept a single string. If you + provide a variable of the latter type with several strings they + will simply be concatenated. The quotes around the value string + are optional. But applying them allows you to use special + characters like '=' and ' \" ' within the string. For example: + + \code + HTML.postheader = "Home" + \endcode + + If an entry spans many lines, use a backslash at the end of every + line but the last: + + \code + sourcedirs = kernel \ + tools \ + widgets + \endcode + + \section1 Configuration Variables + + \section2 Alphabetical List + + \l {22-qdoc-configuration-generalvariables.html#alias}{alias}, + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoredirectives} + {Cpp.ignoredirectives}, + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoretoken} + {Cpp.ignoretokens}, + \l {22-qdoc-configuration-generalvariables.html#definesvariable}{defines}, + \l {22-qdoc-configuration-generalvariables.html#edition}{edition}, + \l {22-qdoc-configuration-generalvariables.html#exampledirs}{exampledirs}, + \l {22-qdoc-configuration-generalvariables.html#examples}{examples}, + \l {22-qdoc-configuration-generalvariables.html#examples.fileextensions} + {examples.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#extraimages}{extraimages}, + \l {22-qdoc-configuration-generalvariables.html#falsehoods}{falsehoods}, + \l {22-qdoc-configuration-generalvariables.html#headerdirs}{headerdirs}, + \l {22-qdoc-configuration-generalvariables.html#headers}{headers}, + \l {22-qdoc-configuration-generalvariables.html#headers.fileextensions} + {headers.fileextensions}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.footer}{HTML.footer}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.postheader} + {HTML.postheader}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.style}{HTML.style}, + \l {22-qdoc-configuration-generalvariables.html#imagedirs}{imagedirs}, + \l {22-qdoc-configuration-generalvariables.html#images}{images}, + \l {22-qdoc-configuration-generalvariables.html#images.fileextensions} + {images.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#language}{language}, + \l {22-qdoc-configuration-generalvariables.html#macro}{macro}, + \l {22-qdoc-configuration-generalvariables.html#outputdir}{outputdir}, + \l {22-qdoc-configuration-generalvariables.html#outputformats} + {outputformats}, + \l {22-qdoc-configuration-generalvariables.html#slow}{slow}, + \l {22-qdoc-configuration-generalvariables.html#sourcedirs}{sourcedirs}, + \l {22-qdoc-configuration-generalvariables.html#sources}{sources}, + \l {22-qdoc-configuration-generalvariables.html#sources.fileextensions} + {sources.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#spurious}{spurious}, + \l {22-qdoc-configuration-generalvariables.html#tabsize}{tabsize}, + \l {22-qdoc-configuration-generalvariables.html#version}{version}, + \l {22-qdoc-configuration-generalvariables.html#versionsym}{versionsym} + + \section2 Categories + + \list + \o \l {General Variables} + \o \l {C++ Specific Variables} + \o \l {HTML Specific Variables} + \endlist + + \section1 Configuration File Examples + + \list + \o A minimum configuration file: \l minimum.qdocconf + \o The Qt configuration file: \l qt.qdocconf + \endlist +*/ + +/*! + \page 21-1-minimum-qdocconf.html + \previouspage QDoc Configuration + \contentspage QDoc Manual - Table of Contents + + \title minimum.qdocconf + + \quotefile examples/minimum.qdocconf +*/ + +/*! + \page 21-2-qt-qdocconf.html + \previouspage QDoc Configuration + \contentspage QDoc Manual - Table of Contents + + \title qt.qdocconf + + \quotefile files/qt.qdocconf +*/ + +/*! + \page 22-qdoc-configuration-generalvariables.html + \previouspage QDoc Configuration + \contentspage QDoc Manual - Table of Contents + \nextpage Creating Help Project Files + + \title General Variables + + With the general QDoc configuration variables, you can define + where QDoc will find the various source files it needs to generate + the documentation, as well as the directory to put the generated + documentation. You can also do some minor manipulation of QDoc + itself, controlling its output and processing behavior. + + \section1 Alphabetical List + + \l {22-qdoc-configuration-generalvariables.html#alias}{alias}, + \l {22-qdoc-configuration-generalvariables.html#codeindent}{codeindent}, + \l {22-qdoc-configuration-generalvariables.html#definesvariable}{defines}, + \l {22-qdoc-configuration-generalvariables.html#edition}{edition}, + \l {22-qdoc-configuration-generalvariables.html#exampledirs}{exampledirs}, + \l {22-qdoc-configuration-generalvariables.html#examples}{examples}, + \l {22-qdoc-configuration-generalvariables.html#examples.fileextensions} + {examples.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#extraimages}{extraimages}, + \l {22-qdoc-configuration-generalvariables.html#falsehoods}{falsehoods}, + \l {22-qdoc-configuration-generalvariables.html#generateindex}{generateindex}, + \l {22-qdoc-configuration-generalvariables.html#headerdirs}{headerdirs}, + \l {22-qdoc-configuration-generalvariables.html#headers}{headers}, + \l {22-qdoc-configuration-generalvariables.html#headers.fileextensions} + {headers.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#imagedirs}{imagedirs}, + \l {22-qdoc-configuration-generalvariables.html#images}{images}, + \l {22-qdoc-configuration-generalvariables.html#images.fileextensions} + {images.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#language}{language}, + \l {22-qdoc-configuration-generalvariables.html#macro}{macro}, + \l {22-qdoc-configuration-generalvariables.html#outputdir}{outputdir}, + \l {22-qdoc-configuration-generalvariables.html#outputformats} + {outputformats}, + \l {22-qdoc-configuration-generalvariables.html#slow}{slow}, + \l {22-qdoc-configuration-generalvariables.html#sourcedirs}{sourcedirs}, + \l {22-qdoc-configuration-generalvariables.html#sources}{sources}, + \l {22-qdoc-configuration-generalvariables.html#sources.fileextensions} + {sources.fileextensions}, + \l {22-qdoc-configuration-generalvariables.html#spurious}{spurious}, + \l {22-qdoc-configuration-generalvariables.html#tabsize}{tabsize}, + \l {22-qdoc-configuration-generalvariables.html#tagfile}{tagfile}, + \l {22-qdoc-configuration-generalvariables.html#version}{version}, + \l {22-qdoc-configuration-generalvariables.html#versionsym}{versionsym} + + \section1 Variable Descriptions + + \table + + \header + \o Variable + \o Description + + \row + \o \bold alias \target alias + \o \bold {The \c alias variable renames a QDoc command.} + + The general syntax is \tt {alias.\i{original-command-name} + = \i temporary-command-name}. + + For example: + + \code + alias.i = e + \endcode + + renames the built-in command \\i (italics) to \\e. + + The \c alias variable is often used for compatibility + reasons; for more information see the \l {QDoc + Compatibility}{compatibility section}. + + See also \l macro. + + \row + \o \bold codeindent \target codeindent + \o \bold {The \c codeindent variable specifies the level of + indentation that QDoc uses when writing code snippets.} + + QDoc originally used a hard-coded value of four spaces for + code indentation to ensure that code snippets could be easily + distinguished from surrounding text. Since we can use + \l{HTML Specific Variables#HTML.stylesheets}{stylesheets} to + adjust the appearance of certain types of HTML elements, this + level of indentation is not always required. + + \row + \o \bold defines \target definesvariable + \o \bold {The \c defines variable specifies the C++ preprocessor + symbols that QDoc will recognize and respond to.} + + When a preprocessor symbol is specified using the \c + defines variable, you can also use the \l {if}{\\if} + command to enclose documentation that only will be included + if the preprocessor symbol is defined. + + The values of the variable are regular expressions (see + QRegExp for details). By default, no symbol is defined, + meaning that code protected with #ifdef...#endif will be + ignored. + + For example: + + \code + defines = Q_QDOC \ + QT_.*_SUPPORT \ + QT_.*_LIB \ + QT_COMPAT \ + QT3_SUPPORT \ + Q_WS_.* \ + Q_OS_.* \ + Q_BYTE_ORDER \ + __cplusplus + \endcode + + ensures that QDoc will process the code that requires these + symbols to be defined. For example: + + \code + #ifdef Q_WS_WIN + HDC getDC() const; + void releaseDC(HDC) const; + #endif + \endcode + + Since the Q_WS_.* regular expression (specified using the + \c defines variable) matches Q_WS_WIN, QDoc will process + the code within #ifdef and #endif in our example. + + You can also define preprocessor symbols manually on the + command line using the -D option. For example: + + \code + currentdirectory$ qdoc3 -Dconsoleedition qt.qdocconf + \endcode + + In this case the -D option ensures that the \c + consoleedition preprocessor symbol is defined when QDoc + processes the source files defined in the qt.qdocconf file. + + See also \l falsehoods and \l {if}{\\if}. + + \row + \o \bold edition \target edition + \o \bold {The \c edition variable specifies which modules are + included in each edition of a package, and provides QDoc + with information to provide class lists for each edition.} + + This feature is mostly used when providing documentation + for Qt packages. + + The \c edition variable is always used with a particular + edition name to define the modules for that edition: + + \code + edition.Console = QtCore QtNetwork QtSql QtXml + edition.Desktop = QtCore QtGui QtNetwork QtOpenGL QtSql QtXml \ + QtDesigner QtAssistant Qt3Support QAxContainer \ + QAxServer + edition.DesktopLight = QtCore QtGui Qt3SupportLight + \endcode + + In the above examples, the \c Console edition only includes + the contents of four modules. Only the classes from these + modules will be used when the + \l{Miscellaneous Commands#generatelist}{generatelist} command + is used to generate a list of classes for this edition: + + \code + \generatelist{classesbyedition Console} + \endcode + + \row + \o \bold exampledirs \target exampledirs + \o \bold {The \c exampledirs variable specifies the directories + containing the source code of the example files.} + + The \l {examples}{\c examples} and \c exampledirs variables + are used by the \l {quotefromfile}{\\quotefromfile}, \l + {quotefile}{\\quotefile} and \l {example}{\\example} + commands. If both the \l {examples}{\c examples} and \c + exampledirs variables are defined, QDoc will search in + both, first in \l {examples}{\c examples} then in \c + exampledirs. + + QDoc will search through the directories in the specified + order, and accept the first matching file it finds. It will + only search in the specified directories, \i not in + subdirectories. + + For example: + + \code + exampledirs = $QTDIR/doc/src \ + $QTDIR/examples \ + $QTDIR \ + $QTDIR/qmake/examples + + examples = $QTDIR/examples/widgets/analogclock/analogclock.cpp + \endcode + + When processing + + \code + \quotefromfile widgets/calculator/calculator.cpp + \endcode + + QDoc will then see if there exists a file called \c + calculator.cpp listed as a value in the \l {examples}{\c + examples} variable. If it doesn't, it will search in the \c + exampledirs variable, and first see if there exists a file + called + + \code + $QTDIR/doc/src/widgets/calculator/calculator.cpp + \endcode + + If it doesn't, QDoc will continue looking for a file + called + + \code + $QTDIR/examples/widgets/calculator/calculator.cpp + \endcode + + and so forth. + + See also \l examples. + + \row + \o \bold examples \target examples + \o \bold {The \c examples variable allows you to specify individual + example files in addition to those located in the directories + specified by the \l {exampledirs}{\c exampledirs} variable.} + + The \c examples and \l {exampledirs}{\c exampledirs} + variables are used by the \l + {quotefromfile}{\\quotefromfile}, \l + {quotefile}{\\quotefile} and \l {example}{\\example} + commands. If both the \c examples and \l {exampledirs}{\c + exampledirs} variables are defined, QDoc will search in + both, first in \c examples then in \l {exampledirs}{\c + exampledirs}. + + QDoc will search through the values listed for the \c + examples variable, in the specified order, and accept + the first one it finds. + + For an extensive example, see the \l {exampledirs}{\c + exampledirs} command. But note that if you know the file is + listed in the \c examples variable, you don't need to + specify its path: + + \code + \quotefromfile calculator.cpp + \endcode + + See also \l exampledirs. + + \row + \o \bold examples.fileextensions \target examples.fileextensions + \o \bold {The \c examples.fileextensions variable specifies the + file extensions that qdoc will look for when collecting example + files for display in the documentation.} + + The default extensions are *.cpp, *.h, *.js, *.xq, *.svg, *.xml + and *.ui. However, if + + The extensions are given as standard wildcard expressions. + You can add a file extension to the filter using '+='. For + example: + + \code + examples.fileextensions += *.qrc + \endcode + + See also \l{headers.fileextensions}. + + \row + \o \bold extraimages \target extraimages + \o \bold {The \c extraimages variable tells QDoc to incorporate + specific images in the generated documentation.} + + QDoc will not recognize images used within HTML (or any + other markup language). If we want the images to be copied + from the directories specified by \l {imagedirs}{\c + imagedirs} (the images in question must be located in these + directories) to the output directory, we must specify the + images using the \c extraimages variable. + + The general syntax is \tt {extraimages.\i{format} = \i + image}. The file extension is optional. + + For example, in \l qt.qdocconf we use a couple of images + within the HTML.postheader variable which value is pure + HTML. For that reason, these images are specified using the + \c extraimages variable: + + \code + extraimages.HTML = qt-logo + \endcode + + See also \l images and \l imagedirs. + + \row + \o \bold falsehoods \target falsehoods + \o \bold {The \c falsehoods variable defines the truth value of + specified preprocessor symbols as false.} + + If this variable is not set for a preprocessor symbol, QDoc + assumes its truth value is true. The exception is '0', + which value always is false. + + QDoc will recognize, and is able to evaluate, the following + preprocessor syntax: + + \code + #ifdef NOTYET + ... + #endif + + #if defined (NOTYET) + ... + #end if + \endcode + + However, faced with unknown syntax like + + \code + #if NOTYET + ... + #endif + \endcode + + QDoc will evaluate it as true by default, \i unless the + preprocessor symbol is specified within the \c falsehoods + variable entry: + + \code + falsehoods = NOTYET + \endcode + + See also \l defines. + + \row + \o \bold generateindex \target generateindex + \o \bold{The \c generateindex variable contains a boolean value that + specifies whether to generate an index file when HTML documentation + is generated.} + + By default, an index file is always generated with HTML documentation, + so this variable is typically only used when disabling this feature + (by setting the value to \c false) or when enabling index generation + for the WebXML output (by setting the value to \c true). + \row + \o \bold headerdirs \target headerdirs + \o \bold {The \c headerdirs variable specifies the directories + containing the header files associated with the \c .cpp source + files used in the documentation.} + + For example: + + \code + headerdirs = $QTDIR/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/extensions/motif \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib + \endcode + + When executed, the first QDoc will do is to read through + the headers specified in the \l {headers}{\c headers} + variable, and the ones located in the directories specified + in the \c headerdir variable (including all + subdirectories), building an internal structure of the + classes and their functions. + + Then it will read through the sources specified in the \l + {sources}{\c sources}, and the ones located in the + directories specified in the \l {sourcedirs}{\c sourcedirs} + varible (including all subdirectories), merging the + documentation with the structure it retrieved from the + header files. + + If both the \c headers and \c headerdirs variables are + defined, QDoc will read through both, first \l {headers}{\c + headers} then \c headerdirs. + + In the specified directories, QDoc will only read the files + with the fileextensions specified in the \l + {headers.fileextensions}{\c headers.fileextensions} + variable. The default extensions are *.ch, *.h, *.h++, + *.hh, *.hpp and *.hxx". The files specified by \l + {headers}{\c headers} will be read independent of their + fileextensions. + + See also \l headers and \l headers.fileextensions. + + \row + \o \bold headers \target headers + \o \bold {The \c headers variable allows you to specify individual + header files in addition to those located in the directories + specified by the \l {headerdirs}{\c headerdirs} variable.} + + For example: + + \code + headers = $QTDIR/src/gui/widgets/qlineedit.h \ + $QTDIR/src/gui/widgets/qpushbutton.h + \endcode + + When processing the \c headers variable, QDoc behaves in the + same way as it does when processing the \l {headerdirs}{\c + headerdirs} variable. For more information, see the \l + {headerdirs}{\c headerdirs} variable. + + See also \l headerdirs. + + \row + \o \bold headers.fileextensions \target headers.fileextensions + \o \bold {The \c headers.fileextensions variable specify the + extension used by the headers.} + + When processing the header files specified in the \l + {headerdirs}{\c headerdirs} variable, QDoc will only read + the files with the fileextensions specified in the \c + headers.fileextensions variable. In this way QDoc avoid + spending time reading irrelevant files. + + The default extensions are *.ch, *.h, *.h++, *.hh, *.hpp + and *.hxx. + + The extensions are given as standard wildcard expressions. + You can add a file extension to the filter using '+='. For + example: + + \code + header.fileextensions += *.H + \endcode + + \warning The above assignment may not work as described. + + See also \l headerdirs. + + \row + \o \bold imagedirs \target imagedirs + \o \bold {The \c imagedirs variable specifies the directories + containing the images used in the documentation.} + + The \l {images}{\c images} and \c imagedirs variables are + used by the \l {image}{\\image} and \l + {inlineimage}{\\inlineimage} commands. If both the \l + {images}{\c images} and \c imagedirs variables are defined, + QDoc will search in both, first in \l {images}{\c images} + then in \c imagedirs. + + QDoc will search through the directories in the specified + order, and accept the first matching file it finds. It will + only search in the specified directories, \i not in + subdirectories. + + For example: + + \code + imagedirs = $QTDIR/doc/src/images \ + $QTDIR/examples + + images = $QTDIR/doc/src/images/calculator-example.png + \endcode + + When processing + + \code + \image calculator-example.png + \endcode + + QDoc will then see if there exists a file called + calculator-example.png listed as a value in the \c images + variable. If it doesn't, it will search in the \c imagedirs + variable, and first see if there exists a file called + + \code + $QTDIR/doc/src/images/calculator-example.png + \endcode + + If it doesn't, QDoc will look for a file called + + \code + $QTDIR/examples/calculator-example.png + \endcode + + You can filter the images in an image directory using the + \l {images.fileextensions}{\c images.fileextensions} + variable. The general idea behind the \l + {images.fileextensions}{\c images.fileextensions} variable + is to enable different image format for different output + format. + + \warning The \l {images.fileextensions}{\c + images.fileextensions} variable's functionality is + preliminay since QDoc at this point only support HTML. + + See also \l images and \l images.fileextensions. + + \row + \o \bold images \target images + \o \bold {The \c images variable allows you to specify individual + image files in addition to those located in the directories + specified by the \l {imagedirs}{\c imagedirs} variable.} + + For example: + + \code + images = $QTDIR/doc/src/images/calculator-example.png + \endcode + + When processing the \c images variable, QDoc behaves in the + same way as it does when processing the \l {imagedirs}{\c + imagedirs} variable. For more information, see the \l + {imagedirs}{\c imagedirs} variable. + + See also \l imagedirs and \l images.fileextensions. + + \row + \o \bold images.fileextensions \target images.fileextensions + \o \bold {The images.fileextensions variable filters the files within + an image directory.} + + The variable's values (the extensions) are given as + standard wildcard expressions. The general syntax is: \tt + {images.fileextensions.\i{format} = *.\i{extension}}. + + The idea is to enable different image format for different + output format. For example: + + \code + images.fileextensions.HTML = *.png + images.fileextensions.LOUT = *.eps + \endcode + + Then, when processing the \l {image}{\\image} and \l + {inlineimage}{\\inlineimage} commands, QDoc will only + search for files with extensions specified in the output + format's associated image extension variable. + + \warning This is preliminary functionality since QDoc at + this point only support HTML. + + The default extensions for HTML are *.png, *.jpg, *.jpeg + and *.gif. + + You can add a file extension to the filter using '+='. For + example: + + \code + images.fileextensions.HTML += *.eps + \endcode + + See also \l imagedirs and \l images. + + \row + \o \bold language \target language + \o \bold {The \c language variable specifies the language of the + source code that is used in the documentation.} + + Currently, C++ is the only language that QDoc + understands. It is also the default language, and doesn't + really need to be specified. But for example in \l + qt.qdocconf: + + \code + language = Cpp + \endcode + + identifies the language of the Qt source code as C++. + + \row + \o \bold macro \target macro + \o \bold {The \c macro variable can be used to create your + own QDoc commands.} + + The general syntax is \tt {macro.\i{command} = + "\i{definition}}". The definition can be described using + QDoc syntax. In addition it is possible to provide an HTML + definition by appending .HTML to the variable. + + For example in \l qt.qdocconf: + + \code + macro.gui = "\\bold" + macro.raisedaster.HTML = "*" + \endcode + + makes sure that the \\gui command renders its argument using a + bold font, and that \\raisedaster renders a '*'. + + \row + \o \bold outputdir \target outputdir + \o \bold {The \c outputdir variable specifies the directory + where QDoc will put the generated documentation.} + + In qt.qdocconf: + + \code + outputdir = $QTDIR/doc/html + \endcode + + locates the generated Qt reference documentation in + $QTDIR/doc/html. For example, the documentation of the + QWidget class is located in + + \code + $QTDIR/doc/html/qwidget.html + \endcode + + The associated images will be put in an \c images subdirectory. + + \warning When running QDoc multiple times using the same output + directory, all files from the previous run will be lost. + + \row + \o \bold outputformats \target outputformats + \o \bold {The \c outputformats variable specifies the format of + the generated documentation.} + + Currently, QDoc only supports the HTML format. It is also + the default format, and doesn't need to be specified. + + \row + \o \bold qhp \target qhp + \o \bold{The \c qhp variable is used to define the information to be + written out to Qt Help Project (\c{qhp}) files.} + + See the \l{Creating Help Project Files} chapter for information + about this process. + + \row + \o \bold slow \target slow + \o \bold {The \c slow variable specifies whether QDoc should do + time-consuming processing, such as syntax highlighting.} + + By default, this setting is false. + + Example: + + \code + slow = true + \endcode + + Another way to turn on "slowness" is to invoke QDoc with the + \c -slow command-line option. + + \row + \o \bold sourcedirs \target sourcedirs + \o \bold {The \c sourcedirs variable specifies the directories + containing the \c .cpp or \c .qdoc files used in + the documentation.} + + For example in \l qt.qdocconf + + \code + sourcedirs = $QTDIR/src \ + $QTDIR/doc/src \ + $QTDIR/extensions/activeqt \ + $QTDIR/extensions/motif \ + $QTDIR/tools/designer/src/lib/extension \ + $QTDIR/tools/designer/src/lib/sdk \ + $QTDIR/tools/designer/src/lib/uilib + \endcode + + When executed, the first QDoc will do is to read through + the headers specified in the \l {header}{\c header} + variable, and the ones located in the directories specified + in the \c headerdir variable (including all + subdirectories), building an internal structure of the + classes and their functions. + + Then it will read through the sources specified in the \l + {sources}{\c sources}, and the ones located in the + directories specified in the \l {sourcedirs}{\c sourcedirs} + varible (including all subdirectories), merging the + documentation with the structure it retrieved from the + header files. + + If both the \c sources and \c sourcedirs variables are + defined, QDoc will read through both, first \l {sources}{\c + sources} then \c sourcedirs. + + In the specified directories, QDoc will only read the files + with the fileextensions specified in the \l + {sources.fileextensions}{\c sources.fileextensions} + variable. The default extensions are *.c++, *.cc, *.cpp and + *.cxx. The files specified by \l {sources}{\c sources} will + be read independent of their fileextensions. + + See also \l sources and \l sources.fileextensions. + + \row + \o \bold sources \target sources + \o \bold {The \c sources variable allows you to specify + individual source files in addition to those located in the + directories specified by the \l {sourcedir}{\c sourcedir} + variable.} + + For example: + + \code + sources = $QTDIR/src/gui/widgets/qlineedit.cpp \ + $QTDIR/src/gui/widgets/qpushbutton.cpp + \endcode + + When processing the \c sources variable, QDoc behaves in the + same way as it does when processing the \l {sourcedirs}{\c + sourcedirs} variable. For more information, see the \l + {sourcedirs}{\c sourcedirs} variable. + + See also \l sourcedirs. + + \row + \o \bold sources.fileextensions \target sources.fileextensions + \o \bold {The \c sources.fileextensions variable filters the + files within a source directory.} + + When processing the source files specified in the \l + {sourcedirs}{\c sourcedirs} variable, QDoc will only read + the files with the fileextensions specified in the \c + sources.fileextensions variable. In this way QDoc avoid + spending time reading irrelevant files. + + The default extensions are *.c++, *.cc, *.cpp and *.cxx. + + The extensions are given as standard wildcard expressions. + You can add a file extension to the filter using '+='. For + example: + + \code + sources.fileextensions += *.CC + \endcode + + \warning The above assignment may not work as described. + + See also \l sourcedirs and \l sources. + + \row + \o \bold spurious \target spurious + \o \bold {The \c spurious variable excludes specified + QDoc warnings from the output.} + + The warnings are specified using standard wildcard + expressions. For example: + + \code + spurious = "Cannot find .*" \ + "Missing .*" + \endcode + + makes sure that warnings matching either of these + expressions, will not be part of the output when running + QDoc. For example would the following warning be omitted + from the output: + + \code + qt-4.0/src/opengl/qgl_mac.cpp:156: Missing parameter name + \endcode + + \row + \o \bold tabsize \target tabsize + \o \bold {The \c tabsize variable defines the size of a tab + character.} + + For example: + + \code + tabsize = 4 + \endcode + + will give the tab character the size of 4 spaces. + + The default value of the variable is 8, and doesn't need to + be specified. + + \row + \o \bold tagfile \target tagfile + \o \bold{The \c tagfile variable specifies the Doxygen tag file to be written + when HTML is generated.} + \row + \o \bold version \target version + \o \bold {The \c version variable specifies the version number of the + documented software.} + + For example: + + \code + version = 4.0.1 + \endcode + + When a version number is specified (using the \tt{\l + version} or \tt {\l versionsym} variables in a \c .qdocconf + file), it is accessible through the corresponding \\version + command for use in the documentation. + + \warning The \\version command's functionality is not + fully implemented; currently it only works within raw HTML + code. + + See also \l versionsym. + + \row + \o \bold versionsym \target versionsym + \o \bold {The \c versionsym variable specifies a C++ + preprocessor symbol that defines the version number + of the documented software.} + + For example in \l qt.qdocconf: + + \code + versionsym = QT_VERSION_STR + \endcode + + QT_VERSION_STR is defined in qglobal.h as follows + + \code + #define QT_VERSION_STR "4.0.1" + \endcode + + When a version number is specified (using the \tt{\l + version} or \tt {\l versionsym} variables in a \c .qdocconf + file), it is accessible through the corresponding \\version + command for use in the documentation. + + \warning The \\version command's functionality is not fully + implemented; currently it only works within raw HTML code. + + See also \l {version}{\\version}. + + \endtable +*/ + +/*! + \page 22-creating-help-project-files.html + \previouspage General Variables + \contentspage QDoc Manual - Table of Contents + \nextpage C++ Specific Variables + + \title Creating Help Project Files + + \section1 Overview + + Starting with Qt 4.4, Qt Assistant uses a different system for managing + Qt documentation that requires QDoc to generate inventories of files in a + format that is similar to the old style DCF format, but with additional + features. + + Instead of hard-coding information about the documentation sets for Qt, + QDoc allows configuration variables to be used to specify which pages are + to be used in each documentation set it generates. These are specified as + subvariables of the \c qch variable with each set declared using a unique + identifier as a subvariable. + + For example, the configuration file for the Qt documentation defines a + \c Qt documentation set by specifying information about the set as + subvariables with the \c{qhp.Qt} prefix: + + \code + qhp.Qt.file = qt.qhp + qhp.Qt.namespace = com.trolltech.qt.440 + qhp.Qt.virtualFolder = qdoc + qhp.Qt.indexTitle = Qt Reference Documentation + qhp.Qt.indexRoot = + qhp.Qt.extraFiles = classic.css images/qt-logo.png + qhp.Qt.filterAttributes = qt 4.4.0 qtrefdoc + qhp.Qt.customFilters.Qt.name = Qt 4.4.0 + qhp.Qt.customFilters.Qt.filterAttributes = qt 4.4.0 + qhp.Qt.subprojects = classes overviews examples + qhp.Qt.subprojects.classes.title = Classes + qhp.Qt.subprojects.classes.indexTitle = Qt's Classes + qhp.Qt.subprojects.classes.selectors = class + qhp.Qt.subprojects.overviews.title = Overviews + qhp.Qt.subprojects.overviews.indexTitle = All Overviews and HOWTOs + qhp.Qt.subprojects.overviews.selectors = fake:page,group,module + qhp.Qt.subprojects.examples.title = Tutorials and Examples + qhp.Qt.subprojects.examples.indexTitle = Qt Examples + qhp.Qt.subprojects.examples.selectors = fake:example + \endcode +*/ + +/*! + \page 23-qdoc-configuration-cppvariables.html + \previouspage Creating Help Project Files + \contentspage QDoc Manual - Table of Contents + \nextpage HTML Specific Variables + + \title C++ Specific Variables + + The C++ specific configuration variables are provided to avoid + erroneous documentation due to non-standard C++ constructs. + + \section1 Alphabetical List + + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoredirectives} + {Cpp.ignoredirectives}, + \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoretoken} + {Cpp.ignoretokens} + + \section1 Variable Descriptions + + \table + + \header + \o Variable + \o Description + + \row + \o \bold Cpp.ignoredirectives \target Cpp.ignoredirectives + \o \bold {The \c Cpp.ignoredirectives variable makes QDoc ignore + the specified non-standard constructs, within C++ source code.} + + If not specified by the \tt {\l Cpp.ignoretokens} or \tt + {\l Cpp.ignoredirectives} variables, non-standard + constructs (typically macros) can result in erroneous + documentation. + + In \l qt.qdocconf: + + \code + Cpp.ignoredirectives = Q_DECLARE_INTERFACE \ + Q_DECLARE_OPERATORS_FOR_FLAGS \ + Q_DECLARE_PRIVATE \ + Q_DECLARE_PUBLIC \ + Q_DISABLE_COPY \ + Q_DUMMY_COMPARISON_OPERATOR \ + Q_ENUMS \ + Q_FLAGS \ + Q_INTERFACES \ + __attribute__ + \endcode + + makes sure that when processing the code below, for + example, QDoc will simply ignore the 'Q_ENUMS' and + 'Q_FLAGS' expressions: + + \code + class Q_CORE_EXPORT Qt { + Q_OBJECT + Q_ENUMS(Orientation TextFormat BackgroundMode + DateFormat ScrollBarPolicy FocusPolicy + ContextMenuPolicy CaseSensitivity + LayoutDirection ArrowType) + Q_ENUMS(ToolButtonStyle) + Q_FLAGS(Alignment) + Q_FLAGS(Orientations) + Q_FLAGS(DockWidgetAreas) + + public: + ... + }; + \endcode + + The Q_OBJECT macro, however, is an exception: QDoc + recognizes this particular non-standard construct, so there + is no need specifying it using the \tt {\l + Cpp.ignoredirectives} variable. + + Regarding the Q_CORE_EXPORT macro; see the documentation of + the \tt {\l Cpp.ignoretokens} variable. + + See also \l Cpp.ignoretokens. + + \row + \o \bold Cpp.ignoretokens \target Cpp.ignoretokens + \o \bold {The \c Cpp.ignoretokens variable makes QDoc ignore + the specified non-standard constructs, within C++ source code.} + + If not specified by the \tt {\l Cpp.ignoretokens} or \tt + {\l Cpp.ignoredirectives} variables, non-standard + constructs (typically macros) can result in erroneous + documentation. + + In \l qt.qdocconf: + + \code + Cpp.ignoretokens = QAXFACTORY_EXPORT \ + QM_EXPORT_CANVAS \ + ... + Q_COMPAT_EXPORT \ + Q_CORE_EXPORT \ + Q_EXPLICIT \ + Q_EXPORT \ + ... + Q_TYPENAME \ + Q_XML_EXPORT + \endcode + + makes sure that when processing the code below, for + example, QDoc will simply ignore the 'Q_CORE_EXPORT' + expression: + + \code + class Q_CORE_EXPORT Qt { + Q_OBJECT + Q_ENUMS(Orientation TextFormat BackgroundMode + DateFormat ScrollBarPolicy FocusPolicy + ContextMenuPolicy CaseSensitivity + LayoutDirection ArrowType) + Q_ENUMS(ToolButtonStyle) + Q_FLAGS(Alignment) + Q_FLAGS(Orientations) + Q_FLAGS(DockWidgetAreas) + + public: + ... + }; + \endcode + + Regarding the Q_OBJECT, Q_ENUMS and Q_FLAGS macros; see the + documentation of the \tt {\l Cpp.ignoredirectives} + variable. + + See also \l Cpp.ignoredirectives. + + \endtable +*/ + + +/*! + \page 24-qdoc-configuration-htmlvariables.html + \previouspage C++ Specific Variables + \contentspage QDoc Manual - Table of Contents + \nextpage Supporting Derived Projects + + \title HTML Specific Variables + + The HTML specific configuration variables define the generated + documentation's style, or define the contents of the + documentation's footer or postheader. The format of the variable + values are raw HTML. + + \section1 Alphabetical List + + \l {24-qdoc-configuration-htmlvariables.html#HTML.footer}{HTML.footer}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.postheader} + {HTML.postheader}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.style}{HTML.style}, + \l {24-qdoc-configuration-htmlvariables.html#HTML.stylesheets}{HTML.stylesheets} + + + \section1 Variable Descriptions + + \table + + \header + \o Variable + \o Description + + \row + \o \bold HTML.footer \target HTML.footer + \o \bold {The \c HTML.footer variable defines the content + of the generated HTML documentation's footer.} + + The footer is rendered at the bottom of the generated + documentation page. + + The variable's value is given as raw HTML code enclosed by + quotation marks. Note that if the value spans several + lines, each line needs to be enclosed by quotation marks. + + For example in \l qt.qdocconf: + + \code + HTML.footer = "


    \n" \ + ... + "
    " + \endcode + + The complete variable entry in \l qt.qdocconf provides the + standard footer of the \l + {http://qt.nokia.com/doc/4.0/index.html}{Qt Reference + Documentation}. + + \row + \o \bold HTML.postheader \target HTML.postheader + \o \bold {The \c HTML.postheader variable defines the content + of the generated HTML documentation's postheader.} + + The header is rendered at the top of the generated + documentation page. + + The variable's value is given as raw HTML enclosed by + quotation marks. Note that if the value spans several + lines, each line needs to be enclosed by quotation marks. + + For example in \l qt.qdocconf: + + \code + HTML.postheader = "" \ + "" \ + "
    " + \endcode + + The complete variable entry in \l qt.qdocconf provides the + standard header of the \l + {http://qt.nokia.com/doc/4.0/index.html}{Qt Reference + Documentation}. + + \row + \o \bold HTML.style \target HTML.style + \o \bold {The HTML.style variable defines the style for + the generated HTML documentation.} + + The variable's value is given as raw HTML enclosed by + quotation marks. Note that if the value spans several + lines, each line needs to be enclosed by quotation marks. + + For example in \l qt.qdocconf: + + \code + HTML.style = "h3.fn,span.fn" \ + "{ margin-left: 1cm; text-indent: -1cm; }\n" \ + "a:link { color: #004faf; text-decoration: none }\n" \ + "a:visited" \ + "{ color: #672967; text-decoration: none }\n" \ + "td.postheader { font-family: sans-serif }\n" \ + "tr.address { font-family: sans-serif }\n" \ + "body { background: #ffffff; color: black; }" + \endcode + + provides the HTML style for the \l + {http://qt.nokia.com/doc/4.0/index.html}{Qt Reference + Documentation}. + + \row + \o \bold HTML.stylesheets \target HTML.stylesheets + \o \bold {The HTML.stylesheets variable defines a list of stylesheets + to use for the generated HTML documentation.} + + Using separate stylesheets for the documentation makes it easier to + customize and experiment with the style used once the contents has + been generated. Typically, it is only necessary to define a single + stylesheet for any set of documentation; for example: + + \code + HTML.stylesheets = classic.css + \endcode + + QDoc expects to find stylesheets in the directory containing the + \l qt.qdocconf file, and it will copy those specified to the output + directory alongside the HTML pages. + \endtable +*/ + +/*! + \page 25-qdoc-configuration-derivedprojects.html + \previouspage HTML Specific Variables + \contentspage QDoc Manual - Table of Contents + \nextpage QDoc Compatibility + + \title Supporting Derived Projects + + \tableofcontents + + Some particular configuration variables allow you to use QDoc to + support Qt-based projects; i.e to make projects, such as Qt Solutions, + contain references to the online Qt documentation. This + means that QDoc will be able to create links to the class reference + documentation, without any explicit linking command. + + \section1 The Configuration Variables + + \section2 Alphabetical List + + \l{25-qdoc-configuration-derivedprojects.html#description}{description}, + \l{25-qdoc-configuration-derivedprojects.html#indexes}{indexes}, + \l{25-qdoc-configuration-derivedprojects.html#project}{project}, + \l{25-qdoc-configuration-derivedprojects.html#url}{url} + + \section2 Variable Descriptions + + \table + \header + \o Variable + \o Description + \row + \o \bold description \target description + \o \bold {The description variable holds a short description of + the associated project.} + + See also \l project. + + \row + \o \bold indexes \target indexes + \o \bold {The \c indexes variable lists the index files + that will be used to generate references.} + + For example. to make a derived Qt project contain links to + the Qt Reference documentation, you need to specify the + associated index file: + + \code + indexes = $QTDIR/doc/html/qt.index + \endcode + + See also \l project and \l url. + + \row + \o \bold project \target project + \o \bold {The \c project variable provides a name for the project + associated with the \c .qdocconf file.} + + The project's name is used to form a file name for the + associated project's \i index file. For example: + + \code + project = QtMotif + \endcode + + This will cause an index file called \c qtmotif.index to be + created. + + See also \l description and \l indexes. + \row + \o \bold url \target url + \o \bold {The \c url variable holds the base URL for the + reference documentation associated with the current project.} + + The URL is stored in the generated index file for the + project. When we use the index on its own, QDoc will use + this as the base URL when constructing links to classes, + functions, and other things listed in the index. + + For example: + + \code + project = Qt + description = Qt Reference Documentation + url = http://qt.nokia.com/doc/4.0 + + ... + \endcode + + This makes sure that whenever \c qt.index is used to generate + references to for example Qt classes, the base URL is + \c http://qt.nokia.com/doc/4.0. + + See also \l indexes. + + \endtable + + \target howto + \section1 How to Support Derived Projects + + This feature makes use of the comprehensive indexes generated by + QDoc when it creates the Qt reference documentation. + + For example, \l qt.qdocconf (the configuration file for Qt) + contains the following variable definitions: + + \code + project = Qt + description = Qt Reference Documentation + url = http://qt.nokia.com/doc/4.0 + + ... + \endcode + + The \l project variable name is used to form a file name for the + index file; in this case the \c qt.index file is created. The \l + url is stored in the index file. Later, when we use the index on + its own, QDoc will use this as the base URL when constructing + links to classes, functions, and other things listed in the index. + + In a mini-project, you can use an index file by defining an \l + indexes configuration variable in your \c .qdocconf file. + + For example, you can create a \c qtmotif.qdocconf file to help you + check the QtMotif documentation (which is part of Qt Solutions): + + \code + include($QTDIR/tools/qdoc3/test/compat.qdocconf) + + project = QtMotif + description = QtMotif Class Documentation + url = http://www.trolltech.com/products/solutions/catalog/4/Migration/qtmotifextension + + indexes = $QTDIR/doc/html/qt.index + + outputdir = html + + headerdirs = src + sourcedirs = src \ + examples + sources.fileextensions = "*.cpp *.qdoc *.doc" + + exampledirs = examples + \endcode + + The code above requires that you run QDoc from the directory that + contains this file. You need to include the compat.qdocconf + file for compatibility reasons; this is further explained in the + \l {QDoc Compatibility} section. + + \bold {To resolve the actual links to Qt classes, the + mini-project's \c .qdocconf file needs to assign a value to the \l + indexes variable; \c $QTDIR/doc/html/qt.index makes sure that you + always use the updated index file for the Qt documentation.} + + The only disadvantages with this approach are the extra file that + QDoc has to generate and the time it takes to do so. Reading the + index back again later isn't instantaneous either, but it's + quicker than processing all the Qt classes each time you need to + write a new document. +*/ + +/*! + \page 26-qdoc-commands-compatibility.html + \previouspage Supporting Derived Projects + \contentspage QDoc Manual - Table of Contents + \nextpage QDoc Commands - Alphabetical List + + \title QDoc Compatibility + + \tableofcontents + + \section1 General Description + + \target reason + + QDoc is a tool that constantly evolves to suit our needs, for that + reason there are some compatibility issues in the transition + between old and new practices. + + To make the transition as smooth and rapid as possible, the + general idea is to adopt the new commands and usage in new + documentation. While waiting for the occurrences of the old + practices to be eliminated from the old parts of the + documentation, you can map the new commands and usage to the old + ones using a compat.qdocconf file. + + A compat.qdocconf file is a separate \c .qdocconf file which you + can include in your main configuration file. It typically contains + the mapping between old and new commands using the \l alias and \l + {22-qdoc-configuration-generalvariables.html#macro}{macro} + configuration variables. + + \section1 Qt Compatibility + + In Qt's documentation there still exist occurrences of old + commands, and the Qt \l {qt.qdocconf}{configuration file} needs to + include the compat.qdocconf file tailored for Qt. For more + detailed information about the commands creating compatibility + issues, see the \l {Command Comments}{command comments}. + + \section2 Qt's current compat.qdocconf file + + \quotefile files/compat.qdocconf + + \section2 Command Comments + + \table + \header + \o New Command + \o Old Command + \o Description + + \row + \o \\i \target i-versus-e + \o \\e + \o Earlier we + used the \\i command to indicate a list or table item, and + the \\e command for rendering in italic. Now we want the + \\i command to render in italic discarding the + \\e command name. + + \bold {We still need to use the \\e command to render in + italic in new documentation for \l {reason}{compatibility + reasons}}. + + \row + \o \\include \target include-versus-input + \o \\input + \o The \\include command was previously used to quote the + complete contents of a source file, now we want to use the + command to include separate documentation. + That is the functionality of the old \\input command + which name we want to discard. + + \bold {We still need to use the \\input command to include + plain text in new documentation for \l + {reason}{compatibility reasons}}. + + \row + \o \\quotefile \target quotefile-versus-include + \o \\include + \o Earlier, we have used the \\quotefile command to + quote from file, i.e. quote parts from file, and the + \\include command to quote the entire file. Since we now want + \\include to include separate documentation, we change the use of + \\quotefile to quote a complete source file. + + \bold {We still need to use the \\include command to quote + the entire contents of a source file in new documentation + for \l {reason}{compatibility reasons}}. + + \row + \o \\quotefromfile \target quotefromfile-versus-quotefile + \o \\quotefile + \o Earlier, we have used the \\quotefile command to + quote from file, i.e. quote parts from file. Since we now want + that command to quote an entire file, we introduce the new + \\quotefromfile command to quote from file. + + \bold {Use \l {quotefromfile}{\\quotefromfile} to quote + parts from a source file in new documentation}. + + \row + \o \\o \target o-versus-i + \o \\i + \o Earlier we used the \\i command to indicate list items + and table items. Since we now want the \\i command to render + in italic instead, we introduce the new \\o command for + this purpose. + + \bold {Use \l {o}{\\o} to indicate list and table items in + new documentation}. + + \row + \o \\quotation \target quotation-versus-quote + \o \\quote + \o These commands are equivalent, and represent a simple name + change. + + \bold {Use \l {quotation}{\\quotation} in new + documentation}. + + \row + \o \\image \target image-versus-img + \o \\img + \o These commands are equivalent, and represent a simple name + change. + + \bold {Use \l {image}{\\image} in new documentation}. + + \endtable +*/ + +/*! + \page 27-qdoc-commmands-alphabetical.html + \previouspage QDoc Compatibility + \contentspage QDoc Manual - Table of Contents + + \title QDoc Commands - Alphabetical List + + \list + + \o \l {04-qdoc-commands-textformatting.html#a}{\\a} + \o \l {11-qdoc-commands-documentcontents.html#abstract}{\\abstract} + \o \l {06-qdoc-commands-verbatimcode.html#badcode}{\\badcode} + \o \l {04-qdoc-commands-textformatting.html#bold}{\\bold} + \o \l {11-qdoc-commands-documentcontents.html#brief}{\\brief} + \o \l {04-qdoc-commands-textformatting.html#c}{\\c} + \o \l {09-qdoc-commands-graphic.html#caption}{\\caption} + \o \l {05-qdoc-commands-documentstructuring.html#chapter}{\\chapter} + \o \l {13-qdoc-commands-topical.html#class}{\\class} + \o \l {06-qdoc-commands-verbatimcode.html#code}{\\code} + \o \l {07-0-qdoc-commands-quoting.html#codeline}{\\codeline}, + \o \l {16-qdoc-commands-status.html#compat}{\\compat} + \o \l {15-qdoc-commands-navigation.html#contentspage}{\\contentspage} + \o \l {07-0-qdoc-commands-quoting.html#dots}{\\dots} + \o \l {12-0-qdoc-commands-miscellaneous.html#else}{\\else} + \o \l {12-0-qdoc-commands-miscellaneous.html#endif}{\\endif} + \o \l {13-qdoc-commands-topical.html#enum}{\\enum} + \o \l {13-qdoc-commands-topical.html#example-command}{\\example} + \o \l {12-0-qdoc-commands-miscellaneous.html#expire}{\\expire} + \o \l {13-qdoc-commands-topical.html#externalpage}{\\externalpage} + \o \l {13-qdoc-commands-topical.html#fn}{\\fn} + \o \l {11-qdoc-commands-documentcontents.html#footnote}{\\footnote} + \o \l {12-0-qdoc-commands-miscellaneous.html#generatelist}{\\generatelist} + \o \l {13-qdoc-commands-topical.html#group}{\\group} + \o \l {10-qdoc-commands-container.html#header}{\\header} + \o \l {13-qdoc-commands-topical.html#headerfile}{\\headerfile} + \o \l {04-qdoc-commands-textformatting.html#i}{\\i} + \o \l {12-0-qdoc-commands-miscellaneous.html#if}{\\if} + \o \l {09-qdoc-commands-graphic.html#image}{\\image} + \o \l {12-0-qdoc-commands-miscellaneous.html#include}{\\include} + \o \l {15-qdoc-commands-navigation.html#indexpage}{\\indexpage} + \o \l {19-qdoc-commands-grouping.html#ingroup}{\\ingroup} + \o \l {19-qdoc-commands-grouping.html#inmodule}{\\inmodule} + \o \l {09-qdoc-commands-graphic.html#inlineimage}{\\inlineimage} + \o \l {16-qdoc-commands-status.html#internal}{\\internal} + \o \l {08-qdoc-commands-linking.html#keyword}{\\keyword} + \o \l {08-qdoc-commands-linking.html#l}{\\l} + \o \l {11-qdoc-commands-documentcontents.html#legalese}{\\legalese} + \o \l {10-qdoc-commands-container.html#list}{\\list} + \o \l {13-qdoc-commands-topical.html#macro}{\\macro} + \o \l {19-qdoc-commands-grouping.html#mainclass}{\\mainclass} + \o \l {12-0-qdoc-commands-miscellaneous.html#meta}{\\meta} + \o \l {13-qdoc-commands-topical.html#module}{\\module} + \o \l {13-qdoc-commands-topical.html#namespace}{\\namespace} + \o \l {15-qdoc-commands-navigation.html#nextpage}{\\nextpage} + \o \l {06-qdoc-commands-verbatimcode.html#newcode}{\\newcode} + \o \l {17-qdoc-commands-thread.html#nonreentrant}{\\nonreentrant} + \o \l {10-qdoc-commands-container.html#o}{\\o} + \o \l {16-qdoc-commands-status.html#obsolete}{\\obsolete} + \o \l {06-qdoc-commands-verbatimcode.html#oldcode}{\\oldcode} + \o \l {12-0-qdoc-commands-miscellaneous.html#omit}{\\omit} + \o \l {10-qdoc-commands-container.html#omitvalue}{\\omitvalue} + \o \l {18-qdoc-commands-relating.html#overload}{\\overload} + \o \l {13-qdoc-commands-topical.html#page}{\\page} + \o \l {05-qdoc-commands-documentstructuring.html#part}{\\part} + \o \l {16-qdoc-commands-status.html#preliminary}{\\preliminary} + \o \l {15-qdoc-commands-navigation.html#previouspage}{\\previouspage} + \o \l {07-0-qdoc-commands-quoting.html#printline}{\\printline} + \o \l {07-0-qdoc-commands-quoting.html#printto}{\\printto} + \o \l {07-0-qdoc-commands-quoting.html#printuntil}{\\printuntil} + \o \l {13-qdoc-commands-topical.html#property}{\\property} + \o \l {11-qdoc-commands-documentcontents.html#quotation}{\\quotation} + \o \l {07-0-qdoc-commands-quoting.html#quotefile}{\\quotefile} + \o \l {07-0-qdoc-commands-quoting.html#quotefromfile}{\\quotefromfile} + \o \l {12-0-qdoc-commands-miscellaneous.html#raw}{\\raw} + \o \l {17-qdoc-commands-thread.html#reentrant}{\\reentrant} + \o \l {18-qdoc-commands-relating.html#reimp}{\\reimp} + \o \l {18-qdoc-commands-relating.html#relates}{\\relates} + \o \l {10-qdoc-commands-container.html#row}{\\row} + \o \l {08-qdoc-commands-linking.html#sa}{\\sa} + \o \l {05-qdoc-commands-documentstructuring.html#sectionOne}{\\section1} + \o \l {05-qdoc-commands-documentstructuring.html#sectionTwo}{\\section2} + \o \l {05-qdoc-commands-documentstructuring.html#sectionThree}{\\section3} + \o \l {05-qdoc-commands-documentstructuring.html#sectionFour}{\\section4} + \o \l {13-qdoc-commands-topical.html#service}{\\service} + \o \l {16-qdoc-commands-status.html#since}{\\since} + \o \l {07-0-qdoc-commands-quoting.html#skipline}{\\skipline} + \o \l {07-0-qdoc-commands-quoting.html#skipto}{\\skipto} + \o \l {07-0-qdoc-commands-quoting.html#skipuntil}{\\skipuntil} + \o \l {07-0-qdoc-commands-quoting.html#snippet}{\\snippet}, + \o \l {15-qdoc-commands-navigation.html#startpage}{\\startpage} + \o \l {04-qdoc-commands-textformatting.html#sub}{\\sub} + \o \l {20-qdoc-commands-title.html#subtitle}{\\subtitle} + \o \l {04-qdoc-commands-textformatting.html#sup}{\\sup} + \o \l {10-qdoc-commands-container.html#table}{\\table} + \o \l {11-qdoc-commands-documentcontents.html#tableofcontents} + {\\tableofcontents} + \o \l {08-qdoc-commands-linking.html#target}{\\target} + \o \l {17-qdoc-commands-thread.html#threadsafe}{\\threadsafe} + \o \l {20-qdoc-commands-title.html#title}{\\title} + \o \l {04-qdoc-commands-textformatting.html#tt}{\\tt} + \o \l {13-qdoc-commands-topical.html#typedef}{\\typedef} + \o \l {04-qdoc-commands-textformatting.html#underline}{\\underline} + \o \l {13-qdoc-commands-topical.html#variable}{\\variable} + \o \l {10-qdoc-commands-container.html#value}{\\value} + \o \l {11-qdoc-commands-documentcontents.html#warning}{\\warning} + \endlist +*/ + +/*! + \externalpage http://qt.nokia.com/about + \title About Qt +*/ diff --git a/tools/qdoc3/doc/qdoc-manual.qdocconf b/tools/qdoc3/doc/qdoc-manual.qdocconf new file mode 100644 index 0000000..26fd09c --- /dev/null +++ b/tools/qdoc3/doc/qdoc-manual.qdocconf @@ -0,0 +1,49 @@ +project = QDoc +description = QDoc3 Manual + +indexes = $QTDIR/doc/html/qt.index + +outputdir = html + +sources = qdoc-manual.qdoc +sourcedirs = $PWD + +exampledirs += $PWD \ + $QTDIR/examples + +imagedirs += images + +extraimages.HTML = qt-logo + +HTML.stylesheets = classic.css + +HTML.style = "h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }\n" \ + "a:link { color: #004faf; text-decoration: none }\n" \ + "a:visited { color: #672967; text-decoration: none }\n" \ + "td.postheader { font-family: sans-serif }\n" \ + "tr.address { font-family: sans-serif }\n" \ + "body { background: #ffffff; color: black; }" + +HTML.postheader = "\n" \ + "\n" \ + "\n" \ + "\n" \ + "
    " \ + "" \ + "" \ + "" \ + "Home: QDoc Manual ·" \ + "" \ + " Qt Reference Documentation" \ + "
    " + +HTML.footer = "


    \n" \ + "\n" \ + "\n" \ + "\n" \ + "\n" \ + "
    Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
    Qt \\version
    " + +spurious += "Missing '\\}'" +spurious += "Cannot use .*" +spurious += "Unexpected .*" -- cgit v0.12 From bf54d63fb1b60ad899d0b14889109278bd04fd9d Mon Sep 17 00:00:00 2001 From: David Boddie Date: Wed, 10 Feb 2010 16:50:22 +0100 Subject: qdoc: Added a build rule for the documentation - disabled by default. Reviewed-by: Trust Me --- tools/qdoc3/qdoc3.pro | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/qdoc3/qdoc3.pro b/tools/qdoc3/qdoc3.pro index 441bf39..7705692 100644 --- a/tools/qdoc3/qdoc3.pro +++ b/tools/qdoc3/qdoc3.pro @@ -105,5 +105,26 @@ SOURCES += apigenerator.cpp \ webxmlgenerator.cpp \ yyindent.cpp +### Documentation for qdoc3 ### + +win32:!win32-g++ { + unixstyle = false +} else :win32-g++:isEmpty(QMAKE_SH) { + unixstyle = false +} else { + unixstyle = true +} + +$$unixstyle { + QDOC = cd $$PWD/doc && $$[QT_INSTALL_BINS]/qdoc3 +} else { + QDOC = cd $$PWD/doc && $$[QT_INSTALL_BINS]/qdoc3.exe + QDOC = $$replace(QDOC, "/", "\\") +} + +docs.commands = $$QDOC qdoc-manual.qdocconf + +QMAKE_EXTRA_TARGETS += docs + target.path = $$[QT_INSTALL_BINS] INSTALLS += target -- cgit v0.12 From 02e9f3f25bdcc1b13ecf9ffaf43716c8f7053e88 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 10 Feb 2010 17:27:07 +0100 Subject: Remove fluxuating tests for QStaticText The QGLWidget tests would fail at random. The use case has been confirmed to work through manual tests, but I haven't found any good way to test them automatically. They have been removed until time permits. --- tests/auto/qstatictext/tst_qstatictext.cpp | 209 ----------------------------- 1 file changed, 209 deletions(-) diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index 92c0008..69e9dc5 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -74,11 +74,6 @@ private slots: void projectedPainter(); void rotatedScaledAndTranslatedPainter(); void transformationChanged(); - - void drawToGLWidget(); - void drawToGLWidgetRepeated(); - void drawToGLWidgetWithCaching(); - void drawToGLWidgetWithCachingRepeated(); }; void tst_QStaticText::init() @@ -437,209 +432,5 @@ void tst_QStaticText::transformationChanged() QCOMPARE(imageDrawStaticText, imageDrawText); } -class MyGLWidget: public QGLWidget -{ -public: - enum PaintEventType { - NormalDrawText, - NormalDrawStaticText, - DrawStaticTextWithCaching - }; - - MyGLWidget(PaintEventType paintEventType, QWidget *parent = 0) - : QGLWidget(parent), m_paintEventType(paintEventType) - { - m_staticText.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - if (m_paintEventType == DrawStaticTextWithCaching) - m_staticText.setUseBackendOptimizations(true); - shown = false; - } - - void paintEvent(QPaintEvent *) - { - QPainter painter(this); - painter.fillRect(rect(), Qt::white); - switch (m_paintEventType) { - case NormalDrawStaticText: - case DrawStaticTextWithCaching: - painter.drawStaticText(QPointF(11, 12), m_staticText); - break; - case NormalDrawText: - painter.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - break; - }; - shown = true; - } - - bool shown; - -private: - QStaticText m_staticText; - PaintEventType m_paintEventType; -}; - -void tst_QStaticText::drawToGLWidget() -{ - QImage imageDrawText; - { - MyGLWidget glWidget(MyGLWidget::NormalDrawText); - glWidget.show(); - while (!glWidget.shown) - QApplication::processEvents(); - imageDrawText = glWidget.grabFrameBuffer(); - } - - QImage imageDrawStaticText; - { - MyGLWidget glWidget(MyGLWidget::NormalDrawStaticText); - glWidget.show(); - while (!glWidget.shown) - QApplication::processEvents(); - imageDrawStaticText = glWidget.grabFrameBuffer(); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("drawToGLWidget_imageDrawText.png"); - imageDrawStaticText.save("drawToGLWidget_imageDrawStaticText.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); -} - -void tst_QStaticText::drawToGLWidgetWithCaching() -{ - QImage imageDrawText; - { - MyGLWidget glWidget(MyGLWidget::NormalDrawText); - glWidget.show(); - while (!glWidget.shown) - QApplication::processEvents(); - imageDrawText = glWidget.grabFrameBuffer(); - } - - QImage imageDrawStaticText; - { - MyGLWidget glWidget(MyGLWidget::DrawStaticTextWithCaching); - glWidget.show(); - while (!glWidget.shown) - QApplication::processEvents(); - imageDrawStaticText = glWidget.grabFrameBuffer(); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("drawToGLWidgetWithCaching_imageDrawText.png"); - imageDrawStaticText.save("drawToGLWidgetWithCaching_imageDrawStaticText.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); -} - -void tst_QStaticText::drawToGLWidgetWithCachingRepeated() -{ - QImage imageDrawText; - MyGLWidget glWidgetNormal(MyGLWidget::NormalDrawText); - - { - glWidgetNormal.show(); - while (!glWidgetNormal.shown) - QApplication::processEvents(); - imageDrawText = glWidgetNormal.grabFrameBuffer(); - } - - QImage imageDrawStaticText; - MyGLWidget glWidgetAbnormal(MyGLWidget::DrawStaticTextWithCaching); - { - - glWidgetAbnormal.show(); - while (!glWidgetAbnormal.shown) - QApplication::processEvents(); - imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText1.png"); - imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText1.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); - - { - glWidgetNormal.shown = false; - glWidgetNormal.update(); - while (!glWidgetNormal.shown) - QApplication::processEvents(); - imageDrawText = glWidgetNormal.grabFrameBuffer(); - } - - { - glWidgetAbnormal.shown = false; - glWidgetAbnormal.update(); - while (!glWidgetAbnormal.shown) - QApplication::processEvents(); - imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText2.png"); - imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText2.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); -} - -void tst_QStaticText::drawToGLWidgetRepeated() -{ - QImage imageDrawText; - MyGLWidget glWidgetNormal(MyGLWidget::NormalDrawText); - - { - glWidgetNormal.show(); - while (!glWidgetNormal.shown) - QApplication::processEvents(); - imageDrawText = glWidgetNormal.grabFrameBuffer(); - } - - QImage imageDrawStaticText; - MyGLWidget glWidgetAbnormal(MyGLWidget::NormalDrawStaticText); - { - - glWidgetAbnormal.show(); - while (!glWidgetAbnormal.shown) - QApplication::processEvents(); - imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText1.png"); - imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText1.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); - - { - glWidgetNormal.shown = false; - glWidgetNormal.update(); - while (!glWidgetNormal.shown) - QApplication::processEvents(); - imageDrawText = glWidgetNormal.grabFrameBuffer(); - } - - { - glWidgetAbnormal.shown = false; - glWidgetAbnormal.update(); - while (!glWidgetAbnormal.shown) - QApplication::processEvents(); - imageDrawStaticText = glWidgetAbnormal.grabFrameBuffer(); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("drawToGLWidgetWithCachingRepeated_imageDrawText2.png"); - imageDrawStaticText.save("drawToGLWidgetWithCachingRepeated_imageDrawStaticText2.png"); -#endif - - QCOMPARE(imageDrawStaticText, imageDrawText); -} - - QTEST_MAIN(tst_QStaticText) #include "tst_qstatictext.moc" -- cgit v0.12 From 510d619f86c3f5464e05ab4d27b3f5eddd7b5135 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 11 Feb 2010 10:29:27 +1000 Subject: Add virtual destructors to QMediaObjectPrivate and QMediaServicePrivate. This reverts aec0628295cda95f2169e3007368797ba6585ee3 and fixes the actual problem, which is the destructors for for classes inheriting QMediaObjectPrivate weren't being called resulting in QPointer destructors also not being called. --- src/multimedia/base/qmediaobject_p.h | 1 + src/multimedia/base/qmediaservice_p.h | 1 + src/multimedia/playback/qmediaplayer.cpp | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/multimedia/base/qmediaobject_p.h b/src/multimedia/base/qmediaobject_p.h index 4bbe06a..ec2f75a 100644 --- a/src/multimedia/base/qmediaobject_p.h +++ b/src/multimedia/base/qmediaobject_p.h @@ -76,6 +76,7 @@ class QMediaObjectPrivate public: QMediaObjectPrivate():metaDataControl(0), notifyTimer(0) {} + virtual ~QMediaObjectPrivate() {} void _q_notify(); diff --git a/src/multimedia/base/qmediaservice_p.h b/src/multimedia/base/qmediaservice_p.h index 5993a7e..7dbcd8a 100644 --- a/src/multimedia/base/qmediaservice_p.h +++ b/src/multimedia/base/qmediaservice_p.h @@ -63,6 +63,7 @@ class QMediaServicePrivate { public: QMediaServicePrivate(): q_ptr(0) {} + virtual ~QMediaServicePrivate() {} QMediaService *q_ptr; }; diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index d3dfbb2..0853597 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -308,8 +308,6 @@ QMediaPlayer::~QMediaPlayer() Q_D(QMediaPlayer); d->provider->releaseService(d->service); - d->videoWidget = 0; - d->videoItem = 0; } QMediaContent QMediaPlayer::media() const -- cgit v0.12 From 7c8835b2dd350978ebb226c15d1a3c9d03f683e2 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 11 Feb 2010 13:20:10 +1000 Subject: Don't call free() on 'this' in DirectShowMediaType. The correct function is freeData(). --- .../mediaservices/directshow/mediaplayer/directshowmediatype.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h index 3ba907e..3cc7307 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h @@ -60,9 +60,9 @@ public: DirectShowMediaType(const AM_MEDIA_TYPE &type) { copy(this, type); } DirectShowMediaType(const DirectShowMediaType &other) { copy(this, other); } DirectShowMediaType &operator =(const AM_MEDIA_TYPE &type) { - free(this); copy(this, type); return *this; } + freeData(this); copy(this, type); return *this; } DirectShowMediaType &operator =(const DirectShowMediaType &other) { - free(this); copy(this, other); return *this; } + freeData(this); copy(this, other); return *this; } ~DirectShowMediaType() { freeData(this); } void clear() { freeData(this); memset(this, 0, sizeof(DirectShowMediaType)); } -- cgit v0.12 From b2b80a93cd5ec39ce5bdcf5836e2b07ccb65389b Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 11 Feb 2010 13:26:31 +1000 Subject: Add support for reading from resource files to Direct Show media service --- .../directshow/mediaplayer/directshowiosource.cpp | 46 +++++++++++++++++++--- .../directshow/mediaplayer/directshowiosource.h | 18 +++++++-- .../mediaplayer/directshowplayerservice.cpp | 10 ++++- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp index bf83dcf..c2fb0d4 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp @@ -45,6 +45,8 @@ #include "directshowmediatype.h" #include "directshowpinenum.h" +#include +#include QT_BEGIN_NAMESPACE @@ -55,15 +57,16 @@ static const GUID directshow_subtypes[] = MEDIASUBTYPE_NULL }; -DirectShowIOSource::DirectShowIOSource(QIODevice *device, DirectShowEventLoop *loop) +DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) : m_ref(1) , m_state(State_Stopped) + , m_reader(0) + , m_loop(loop) , m_graph(0) , m_clock(0) , m_allocator(0) , m_peerPin(0) , m_pinId(QLatin1String("Data")) - , m_reader(device, this, loop) { QVector mediaTypes; @@ -93,6 +96,15 @@ DirectShowIOSource::DirectShowIOSource(QIODevice *device, DirectShowEventLoop *l DirectShowIOSource::~DirectShowIOSource() { Q_ASSERT(m_ref == 0); + + delete m_reader; +} + +void DirectShowIOSource::setDevice(QIODevice *device) +{ + Q_ASSERT(!m_reader); + + m_reader = new DirectShowIOReader(device, this, m_loop); } void DirectShowIOSource::setAllocator(IMemAllocator *allocator) @@ -121,7 +133,7 @@ HRESULT DirectShowIOSource::QueryInterface(REFIID riid, void **ppvObject) } else if (riid == IID_IPin) { *ppvObject = static_cast(this); } else if (riid == IID_IAsyncReader) { - *ppvObject = static_cast(&m_reader); + *ppvObject = static_cast(m_reader); } else { *ppvObject = 0; @@ -571,12 +583,12 @@ HRESULT DirectShowIOSource::EndOfStream() HRESULT DirectShowIOSource::BeginFlush() { - return m_reader.BeginFlush(); + return m_reader->BeginFlush(); } HRESULT DirectShowIOSource::EndFlush() { - return m_reader.EndFlush(); + return m_reader->EndFlush(); } HRESULT DirectShowIOSource::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) @@ -601,3 +613,27 @@ HRESULT DirectShowIOSource::QueryDirection(PIN_DIRECTION *pPinDir) QT_END_NAMESPACE +DirectShowRcSource::DirectShowRcSource(DirectShowEventLoop *loop) + : DirectShowIOSource(loop) +{ +} + +bool DirectShowRcSource::open(const QUrl &url) +{ + m_file.moveToThread(QCoreApplication::instance()->thread()); + + m_file.setFileName(QLatin1Char(':') + url.path()); + + qDebug("qrc file %s", qPrintable(m_file.fileName())); + + if (m_file.open(QIODevice::ReadOnly)) { + qDebug("Size %d", m_file.size()); + qDebug("Sequential %d", int(m_file.isSequential())); + + setDevice(&m_file); + + return true; + } else { + return false; + } +} diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h index a8ed56a..b626473 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h @@ -51,7 +51,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QIODevice; +#include class DirectShowIOSource : public DirectShowMediaTypeList @@ -60,9 +60,10 @@ class DirectShowIOSource , public IPin { public: - DirectShowIOSource(QIODevice *device, DirectShowEventLoop *loop); + DirectShowIOSource(DirectShowEventLoop *loop); ~DirectShowIOSource(); + void setDevice(QIODevice *device); void setAllocator(IMemAllocator *allocator); // IUnknown @@ -126,6 +127,8 @@ private: volatile LONG m_ref; FILTER_STATE m_state; + DirectShowIOReader *m_reader; + DirectShowEventLoop *m_loop; IFilterGraph *m_graph; IReferenceClock *m_clock; IMemAllocator *m_allocator; @@ -134,8 +137,17 @@ private: QString m_filterName; const QString m_pinId; QMutex m_mutex; - DirectShowIOReader m_reader; +}; + +class DirectShowRcSource : public DirectShowIOSource +{ +public: + DirectShowRcSource(DirectShowEventLoop *loop); + + bool open(const QUrl &url); +private: + QFile m_file; }; QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index e9bce71..6e6b2f2 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -247,6 +247,13 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) fileSource->Release(); } + } else if (url.scheme() == QLatin1String("qrc")) { + DirectShowRcSource *rcSource = new DirectShowRcSource(m_loop); + + if (rcSource->open(url) && SUCCEEDED(hr = m_graph->AddFilter(rcSource, L"Source"))) + source = rcSource; + else + rcSource->Release(); } if (!SUCCEEDED(hr)) { @@ -300,7 +307,8 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker) { - IBaseFilter *source = new DirectShowIOSource(m_stream, m_loop); + DirectShowIOSource *source = new DirectShowIOSource(m_loop); + source->setDevice(m_stream); if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) { m_executedTasks = SetSource; -- cgit v0.12 From dc7a0b2842a5866b6248e56d41db0af05f7efbc2 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 11 Feb 2010 13:30:00 +1000 Subject: Fix incorrect buffer size calculation. Was off by one resulting in repeated playback of mp3s being cutt off. --- .../mediaservices/directshow/mediaplayer/directshowioreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp index dcb9a40..54446b8 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp @@ -179,7 +179,7 @@ HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser) return VFW_E_SAMPLE_TIME_NOT_SET; } else { LONGLONG position = startTime / 10000000; - LONG length = ((endTime - startTime) / 10000000) + 1; + LONG length = (endTime - startTime) / 10000000; DirectShowSampleRequest *request = new DirectShowSampleRequest( pSample, dwUser, position, length, buffer); @@ -251,7 +251,7 @@ HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample) return VFW_E_SAMPLE_TIME_NOT_SET; } else { LONGLONG position = startTime / 10000000; - LONG length = ((endTime - startTime) / 10000000) + 1; + LONG length = (endTime - startTime) / 10000000; QMutexLocker locker(&m_mutex); -- cgit v0.12 From 802051dd1eb8dd63e84ac0c241f560d8cdf350c5 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 11 Feb 2010 11:31:36 +0100 Subject: qdoc3: Added curly braces in switch statement for braindead compiler. Also added the \pagekeywords command. Task: QTBUG-7877 --- tools/qdoc3/codeparser.cpp | 5 +++++ tools/qdoc3/htmlgenerator.cpp | 26 ++++++++++++++++---------- tools/qdoc3/node.cpp | 2 +- tools/qdoc3/node.h | 4 ++++ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/tools/qdoc3/codeparser.cpp b/tools/qdoc3/codeparser.cpp index 3ad3372..5ae63ac 100644 --- a/tools/qdoc3/codeparser.cpp +++ b/tools/qdoc3/codeparser.cpp @@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_MAINCLASS Doc::alias(QLatin1String("mainclass")) #define COMMAND_NONREENTRANT Doc::alias(QLatin1String("nonreentrant")) #define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete")) +#define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords")) #define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary")) #define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup")) #define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant")) @@ -170,6 +171,7 @@ QSet CodeParser::commonMetaCommands() << COMMAND_MAINCLASS << COMMAND_NONREENTRANT << COMMAND_OBSOLETE + << COMMAND_PAGEKEYWORDS << COMMAND_PRELIMINARY << COMMAND_INPUBLICGROUP << COMMAND_REENTRANT @@ -230,6 +232,9 @@ void CodeParser::processCommonMetaCommand(const Location &location, else if (command == COMMAND_SINCE) { node->setSince(arg); } + else if (command == COMMAND_PAGEKEYWORDS) { + node->addPageKeywords(arg); + } else if (command == COMMAND_SUBTITLE) { if (node->type() == Node::Fake) { FakeNode *fake = static_cast(node); diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 27716a4..ffd3b5b 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -4378,18 +4378,24 @@ bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, t.setNum(id++); switch (node->type()) { case Node::Fake: - const FakeNode* fake = static_cast(node); - title = fake->fullTitle(); - break; + { + const FakeNode* fake = static_cast(node); + title = fake->fullTitle(); + break; + } case Node::Class: - title = node->name() + " Class Reference"; - break; + { + title = node->name() + " Class Reference"; + break; + } case Node::Namespace: - const InnerNode* inner = static_cast(node); - rawTitle = marker->plainName(inner); - fullTitle = marker->plainFullName(inner); - title = rawTitle + " Namespace Reference"; - break; + { + const InnerNode* inner = static_cast(node); + rawTitle = marker->plainName(inner); + fullTitle = marker->plainFullName(inner); + title = rawTitle + " Namespace Reference"; + break; + } default: title = node->name(); break; diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index f3958c6..ec574f8 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -415,7 +415,7 @@ void InnerNode::deleteChildren() } /*! - Returns true. + Returns true because this is an inner node. */ bool InnerNode::isInnerNode() const { diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 679a9d4..6a540d4 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -183,6 +183,7 @@ class Node QString since() const { return sinc; } QString templateStuff() const { return tpl; } PageType pageType() const { return pageTyp; } + virtual void addPageKeywords(const QString& ) { } void clearRelated() { rel = 0; } @@ -256,6 +257,8 @@ class InnerNode : public Node QStringList primaryKeys(); QStringList secondaryKeys(); + QStringList pageKeywords() { return pageKeywds; } + virtual void addPageKeywords(const QString& t) { pageKeywds << t; } protected: InnerNode(Type type, InnerNode *parent, const QString& name); @@ -268,6 +271,7 @@ class InnerNode : public Node void removeChild(Node *child); void removeRelated(Node *pseudoChild); + QStringList pageKeywds; QStringList inc; NodeList children; NodeList enumChildren; -- cgit v0.12 From 638b4edeba905facb2ae7a841214b048c0010008 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 11 Feb 2010 13:28:09 +0100 Subject: Fixed Mac OS X compile time error by using GLint for temp. The GLint is then returned as an int, which is ok. --- src/opengl/qglshaderprogram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 170b650..2a86c91 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -3084,7 +3084,7 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 * */ int QGLShaderProgram::maxGeometryOutputVertices() const { - int n; + GLint n; glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &n); return n; } -- cgit v0.12 From ebfb42a9ada20c93643b05ebbb73709bd639742d Mon Sep 17 00:00:00 2001 From: Prasanth Ullattil Date: Thu, 11 Feb 2010 14:36:11 +0100 Subject: Wrong cursor shown by the parent window after setOverrideCursor(). When calling QApplication::setOverrideCursor() and then showing a modal dialog, the parent window of the dialog reverts to the default cursor. At this point the parent window is in a disabled state, Windows uses the default cursor for the class. We need to override this behavior by handling WM_SETCURSOR. Task-number: QTBUG-6525 Reviewed-by: Denis Dzyubenko --- src/gui/kernel/qapplication_win.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 3355272..2c6e246 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -2547,6 +2547,17 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = true; break; } +#ifndef QT_NO_CURSOR + case WM_SETCURSOR: { + QCursor *ovr = QApplication::overrideCursor(); + if (ovr) { + SetCursor(ovr->handle()); + RETURN(TRUE); + } + result = false; + break; + } +#endif default: result = false; // event was not processed break; -- cgit v0.12 From 8750eae466f066ebb50a565b8efe90f7ce7ee360 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 11 Feb 2010 15:14:53 +0100 Subject: qdoc3: Completed handling of the new \pagekeywords command. Task: QTBUG-7877 --- tools/qdoc3/htmlgenerator.cpp | 11 ++++++++++- tools/qdoc3/node.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index ca0cd7e..e341a03 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -4384,10 +4384,13 @@ bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, return true; if (node->access() == Node::Private) return false; + if (!node->isInnerNode()) + return false; QString title; QString rawTitle; QString fullTitle; + const InnerNode* inner = static_cast(node); writer.writeStartElement("page"); QXmlStreamAttributes attributes; @@ -4407,7 +4410,6 @@ bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, } case Node::Namespace: { - const InnerNode* inner = static_cast(node); rawTitle = marker->plainName(inner); fullTitle = marker->plainFullName(inner); title = rawTitle + " Namespace Reference"; @@ -4420,6 +4422,13 @@ bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer, writer.writeAttribute("id",t); writer.writeStartElement("pageWords"); writer.writeCharacters(title); + if (!inner->pageKeywords().isEmpty()) { + const QStringList& w = inner->pageKeywords(); + for (int i = 0; i < w.size(); ++i) { + writer.writeCharacters(" "); + writer.writeCharacters(w.at(i).toLocal8Bit().constData()); + } + } writer.writeEndElement(); writer.writeStartElement("pageTitle"); writer.writeCharacters(title); diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 6a540d4..021a052 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -257,7 +257,7 @@ class InnerNode : public Node QStringList primaryKeys(); QStringList secondaryKeys(); - QStringList pageKeywords() { return pageKeywds; } + const QStringList& pageKeywords() const { return pageKeywds; } virtual void addPageKeywords(const QString& t) { pageKeywds << t; } protected: -- cgit v0.12 From 0601f9f764c55390a2cdd71d91c3ea25c57f2a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 11 Feb 2010 17:31:53 +0100 Subject: Fix bug in QDirPrivate::setPath, affecting QDir::cd, cdUp and setPath The changes introduced in 9d713d7e73a88fe8328b55d2ab9af8c215dcb89d made QDirPrivate rely on the order of sub-expression evaluation. In some platform/compiler combinations, the instance of QDirPrivate::Data::path being changed would be the pre-detach one. With this change, that commit is partially reverted. Also, inlined the code in initFileEngine since this makes the actions therein explicit. Reviewed-by: Olivier Goffart --- src/corelib/io/qdir.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index f5d803e..7cfdddf 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -89,8 +89,6 @@ public: QDirPrivate(const QDir *copy = 0); ~QDirPrivate(); - QString initFileEngine(const QString &file); - void updateFileLists() const; void sortFileList(QDir::SortFlags, QFileInfoList &, QStringList *, QFileInfoList *) const; @@ -146,6 +144,7 @@ public: } *data; inline void setPath(const QString &p) { + detach(false); QString path = p; if ((path.endsWith(QLatin1Char('/')) || path.endsWith(QLatin1Char('\\'))) && path.length() > 1) { @@ -155,8 +154,12 @@ public: path.truncate(path.length() - 1); } + delete data->fileEngine; + data->fileEngine = QAbstractFileEngine::create(path); + // set the path to be the qt friendly version so then we can operate on it using just / - data->path = initFileEngine(path); + data->path = data->fileEngine->fileName(QAbstractFileEngine::DefaultName); + data->clear(); } inline void reset() { detach(); @@ -310,15 +313,6 @@ inline void QDirPrivate::updateFileLists() const } } -inline QString QDirPrivate::initFileEngine(const QString &path) -{ - detach(false); - data->clear(); - delete data->fileEngine; - data->fileEngine = QAbstractFileEngine::create(path); - return data->fileEngine->fileName(QAbstractFileEngine::DefaultName); -} - void QDirPrivate::detach(bool createFileEngine) { qAtomicDetach(data); -- cgit v0.12 From 476970c2a1d00cfbf3f8bd6ac4b5c835633641ca Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 12 Feb 2010 15:46:48 +1000 Subject: Emit positionChanged signals whenever playback is interrupted. When stopped, paused, at the end of media, and after a seek. This prevents progress bars stopping just short of the end because the last timed progress updates was 300ms before the end of playback. --- .../mediaplayer/directshowplayercontrol.cpp | 15 +++- .../mediaplayer/directshowplayercontrol.h | 5 +- .../mediaplayer/directshowplayerservice.cpp | 88 ++++++++++++++++++---- .../mediaplayer/directshowplayerservice.h | 4 +- 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp index 587f4b1..b024557 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp @@ -85,6 +85,7 @@ DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *servic , m_error(QMediaPlayer::NoError) , m_streamTypes(0) , m_muteVolume(-1) + , m_position(0) , m_duration(0) , m_playbackRate(0) , m_seekable(false) @@ -114,7 +115,7 @@ qint64 DirectShowPlayerControl::duration() const qint64 DirectShowPlayerControl::position() const { - return m_service->position(); + return const_cast(m_position) = m_service->position(); } void DirectShowPlayerControl::setPosition(qint64 position) @@ -289,6 +290,9 @@ void DirectShowPlayerControl::emitPropertyChanges() emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); } + if (properties & PositionProperty) + emit positionChanged(m_position); + if (properties & DurationProperty) emit durationChanged(m_duration); @@ -379,4 +383,13 @@ void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QStri scheduleUpdate(ErrorProperty); } +void DirectShowPlayerControl::updatePosition(qint64 position) +{ + if (m_position != position) { + m_position = position; + + scheduleUpdate(PositionProperty); + } +} + QT_END_NAMESPACE diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h index 6706bab..dd25d30 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h @@ -102,6 +102,7 @@ public: void updatePlaybackRate(qreal rate); void updateAudioOutput(IBaseFilter *filter); void updateError(QMediaPlayer::Error error, const QString &errorString); + void updatePosition(qint64 position); protected: void customEvent(QEvent *event); @@ -115,7 +116,8 @@ private: DurationProperty = 0x08, PlaybackRateProperty = 0x10, SeekableProperty = 0x20, - ErrorProperty = 0x40 + ErrorProperty = 0x40, + PositionProperty = 0x80 }; enum Event @@ -135,6 +137,7 @@ private: QMediaPlayer::Error m_error; int m_streamTypes; int m_muteVolume; + qint64 m_position; qint64 m_duration; qreal m_playbackRate; bool m_seekable; diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp index 6e6b2f2..57f4bec 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp @@ -184,6 +184,7 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_stream = stream; m_error = QMediaPlayer::NoError; m_errorString = QString(); + m_position = 0; m_duration = 0; m_streamTypes = 0; m_executedTasks = 0; @@ -217,6 +218,7 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_playerControl->updateError(m_error, m_errorString); m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); m_playerControl->updateState(QMediaPlayer::StoppedState); + m_playerControl->updatePosition(m_position); updateStatus(); } @@ -678,6 +680,17 @@ void DirectShowPlayerService::doPause(QMutexLocker *locker) control->Release(); if (SUCCEEDED(hr)) { + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + m_position = position / 10; + } else { + m_position = 0; + } + m_executedTasks |= Pause; QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); @@ -697,23 +710,43 @@ void DirectShowPlayerService::stop() m_pendingTasks &= ~(Play | Pause | Seek); - if (m_executedTasks & Render) { - if (m_executingTask & (Play | Pause | Seek)) { - m_pendingTasks |= Stop; + if ((m_executingTask | m_executedTasks) & (Play | Pause | Seek)) { + m_pendingTasks |= Stop; + + ::SetEvent(m_taskHandle); + + m_loop->wait(&m_mutex); + } + +} - m_loop->wait(&m_mutex); +void DirectShowPlayerService::doStop(QMutexLocker *locker) +{ + if (m_executedTasks & (Play | Pause)) { + if (IMediaControl *control = com_cast(m_graph)) { + control->Stop(); + control->Release(); } - if (m_executedTasks & (Play | Pause)) { - if (IMediaControl *control = com_cast(m_graph)) { - control->Stop(); - control->Release(); - } - m_executedTasks &= ~(Play | Pause); + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + m_position = position / 10; + } else { + m_position = 0; } + + m_executedTasks &= ~(Play | Pause); + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StatusChange))); } m_executedTasks |= Stop; + + m_loop->wake(); } void DirectShowPlayerService::setRate(qreal rate) @@ -774,7 +807,9 @@ qint64 DirectShowPlayerService::position() const seeking->GetCurrentPosition(&position); seeking->Release(); - return position / 10; + const_cast(m_position) = position / 10; + + return m_position; } } return 0; @@ -835,8 +870,15 @@ void DirectShowPlayerService::doSeek(QMutexLocker *locker) &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); locker->relock(); + seeking->GetCurrentPosition(¤tPosition); + m_position = currentPosition / 10; + seeking->Release(); + } else { + m_position = 0; } + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange))); } int DirectShowPlayerService::bufferStatus() const @@ -1034,6 +1076,7 @@ void DirectShowPlayerService::customEvent(QEvent *event) QMutexLocker locker(&m_mutex); updateStatus(); + m_playerControl->updatePosition(m_position); } else if (event->type() == QEvent::Type(DurationChange)) { QMutexLocker locker(&m_mutex); @@ -1044,7 +1087,12 @@ void DirectShowPlayerService::customEvent(QEvent *event) if (m_atEnd) { m_playerControl->updateState(QMediaPlayer::StoppedState); m_playerControl->updateStatus(QMediaPlayer::EndOfMedia); + m_playerControl->updatePosition(m_position); } + } else if (event->type() == QEvent::Type(PositionChange)) { + QMutexLocker locker(&m_mutex); + + m_playerControl->updatePosition(m_position); } else { QMediaService::customEvent(event); } @@ -1089,6 +1137,15 @@ void DirectShowPlayerService::graphEvent(QMutexLocker *locker) m_buffering = false; m_atEnd = true; + if (IMediaSeeking *seeking = com_cast(m_graph)) { + LONGLONG position = 0; + + seeking->GetCurrentPosition(&position); + seeking->Release(); + + m_position = position / 10; + } + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(EndOfMedia))); break; case EC_LENGTH_CHANGED: @@ -1262,15 +1319,16 @@ void DirectShowPlayerService::run() m_executingTask = FinalizeLoad; doFinalizeLoad(&locker); + } else if (m_pendingTasks & Stop) { + m_pendingTasks ^= Stop; + m_executingTask = Stop; + + doStop(&locker); } else if (m_pendingTasks & SetRate) { m_pendingTasks ^= SetRate; m_executingTask = SetRate; doSetRate(&locker); - } else if (m_pendingTasks & Stop) { - m_pendingTasks ^= Stop; - - m_loop->wake(); } else if (m_pendingTasks & Pause) { m_pendingTasks ^= Pause; m_executingTask = Pause; diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h index f9d3232..a5da9a4 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h @@ -126,6 +126,7 @@ private: void doSeek(QMutexLocker *locker); void doPlay(QMutexLocker *locker); void doPause(QMutexLocker *locker); + void doStop(QMutexLocker *locker); void doReleaseAudioOutput(QMutexLocker *locker); void doReleaseVideoOutput(QMutexLocker *locker); void doReleaseGraph(QMutexLocker *locker); @@ -163,7 +164,8 @@ private: Paused, DurationChange, StatusChange, - EndOfMedia + EndOfMedia, + PositionChange }; enum GraphStatus -- cgit v0.12 From 9bca64fc5eee598f97eba1052f1db250c5c7e43b Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 12 Feb 2010 16:51:32 +1000 Subject: Fix corruption of Direct Show event queue. The mutex proctecting the queue was being released and reacquired between when the head and tail are cleared, making it possible to append a new item to a popped, or even deleted tail, resulting in a lost event. --- .../mediaservices/directshow/mediaplayer/directshoweventloop.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp index 4f9a19d..07541c2 100644 --- a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp +++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp @@ -148,13 +148,14 @@ void DirectShowEventLoop::processEvents() DirectShowPostedEvent *post = m_postsHead; m_postsHead = m_postsHead->next; + if (!m_postsHead) + m_postsTail = 0; + locker.unlock(); QCoreApplication::sendEvent(post->receiver, post->event); delete post; locker.relock(); } - - m_postsTail = 0; } QT_END_NAMESPACE -- cgit v0.12 From ab1e94988920c3764e7f6567eb2994666b679e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 12 Feb 2010 10:45:17 +0100 Subject: readdir64 is not available on HP-UX Instead, 64-bit inode numbers in dirent are documented to be truncated. Oh, well. New define QT_NO_READDIR64 allows blacklisting other platforms that support open64 and friends, but not readdir64. Reviewed-by: Thiago Macieira --- mkspecs/common/posix/qplatformdefs.h | 4 +++- mkspecs/hpux-acc-64/qplatformdefs.h | 1 + mkspecs/hpux-acc-o64/qplatformdefs.h | 1 + mkspecs/hpux-acc/qplatformdefs.h | 1 + mkspecs/hpux-g++-64/qplatformdefs.h | 1 + mkspecs/hpux-g++/qplatformdefs.h | 1 + mkspecs/hpuxi-acc-32/qplatformdefs.h | 1 + mkspecs/hpuxi-acc-64/qplatformdefs.h | 1 + mkspecs/hpuxi-g++-64/qplatformdefs.h | 1 + 9 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mkspecs/common/posix/qplatformdefs.h b/mkspecs/common/posix/qplatformdefs.h index e29bc6f..6310257 100644 --- a/mkspecs/common/posix/qplatformdefs.h +++ b/mkspecs/common/posix/qplatformdefs.h @@ -138,7 +138,9 @@ #define QT_OPENDIR ::opendir #define QT_CLOSEDIR ::closedir -#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT) +#if defined(QT_LARGEFILE_SUPPORT) \ + && defined(QT_USE_XOPEN_LFS_EXTENSIONS) \ + && !defined(QT_NO_READDIR64) #define QT_DIRENT struct dirent64 #define QT_READDIR ::readdir64 #define QT_READDIR_R ::readdir64_r diff --git a/mkspecs/hpux-acc-64/qplatformdefs.h b/mkspecs/hpux-acc-64/qplatformdefs.h index f9789a8..c1a9ab8 100644 --- a/mkspecs/hpux-acc-64/qplatformdefs.h +++ b/mkspecs/hpux-acc-64/qplatformdefs.h @@ -77,6 +77,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_OPEN_LARGEFILE diff --git a/mkspecs/hpux-acc-o64/qplatformdefs.h b/mkspecs/hpux-acc-o64/qplatformdefs.h index 5237806..c622d80 100644 --- a/mkspecs/hpux-acc-o64/qplatformdefs.h +++ b/mkspecs/hpux-acc-o64/qplatformdefs.h @@ -78,6 +78,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_SOCKLEN_T diff --git a/mkspecs/hpux-acc/qplatformdefs.h b/mkspecs/hpux-acc/qplatformdefs.h index 9ce08c6..c18ad49 100644 --- a/mkspecs/hpux-acc/qplatformdefs.h +++ b/mkspecs/hpux-acc/qplatformdefs.h @@ -80,6 +80,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_OPEN_LARGEFILE diff --git a/mkspecs/hpux-g++-64/qplatformdefs.h b/mkspecs/hpux-g++-64/qplatformdefs.h index f3fbda5..e9a9e75 100644 --- a/mkspecs/hpux-g++-64/qplatformdefs.h +++ b/mkspecs/hpux-g++-64/qplatformdefs.h @@ -77,6 +77,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #endif // QPLATFORMDEFS_H diff --git a/mkspecs/hpux-g++/qplatformdefs.h b/mkspecs/hpux-g++/qplatformdefs.h index 38e9408..9296ac2 100644 --- a/mkspecs/hpux-g++/qplatformdefs.h +++ b/mkspecs/hpux-g++/qplatformdefs.h @@ -79,6 +79,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_SOCKLEN_T diff --git a/mkspecs/hpuxi-acc-32/qplatformdefs.h b/mkspecs/hpuxi-acc-32/qplatformdefs.h index a0d2464..6aafed2 100644 --- a/mkspecs/hpuxi-acc-32/qplatformdefs.h +++ b/mkspecs/hpuxi-acc-32/qplatformdefs.h @@ -78,6 +78,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_OPEN_LARGEFILE diff --git a/mkspecs/hpuxi-acc-64/qplatformdefs.h b/mkspecs/hpuxi-acc-64/qplatformdefs.h index a0d2464..6aafed2 100644 --- a/mkspecs/hpuxi-acc-64/qplatformdefs.h +++ b/mkspecs/hpuxi-acc-64/qplatformdefs.h @@ -78,6 +78,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_OPEN_LARGEFILE diff --git a/mkspecs/hpuxi-g++-64/qplatformdefs.h b/mkspecs/hpuxi-g++-64/qplatformdefs.h index 288a331..f6789ee 100644 --- a/mkspecs/hpuxi-g++-64/qplatformdefs.h +++ b/mkspecs/hpuxi-g++-64/qplatformdefs.h @@ -77,6 +77,7 @@ #endif #define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 #include "../common/posix/qplatformdefs.h" #undef QT_OPEN_LARGEFILE -- cgit v0.12 From d1cb6591ed94d3999a7c0d2d36e478ffc44350c6 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 12 Feb 2010 11:45:21 +0100 Subject: Add license header to this file --- tools/qdoc3/doc/examples/main.cpp | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tools/qdoc3/doc/examples/main.cpp b/tools/qdoc3/doc/examples/main.cpp index b777754..e2cf6c5 100644 --- a/tools/qdoc3/doc/examples/main.cpp +++ b/tools/qdoc3/doc/examples/main.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** 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 tools applications 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 #include -- cgit v0.12 From c6fa4e8647dd16c6b864fce5047aadaee005b0f9 Mon Sep 17 00:00:00 2001 From: Holger Schroeder Date: Fri, 12 Feb 2010 14:26:06 +0100 Subject: Changes: add functionality for dbus auto start to qt RevBy: TrustMe Details: This is the first part of an implementation that introduces handling of the dbus autoStart flag into qt. This flag determines in the used dbus implementation, if the receiver of a method call will be started if it is not running yet, or if it will not be started. The part from dbus up to QDBusMessage should be fine, but i do not know how to set this flag from the higher layers. Ideally this would be generated from qdbusxml2cpp. Merge-request: 2307 Reviewed-by: Thiago Macieira --- src/dbus/qdbus_symbols_p.h | 5 +++++ src/dbus/qdbusmessage.cpp | 27 ++++++++++++++++++++++++++- src/dbus/qdbusmessage.h | 3 +++ src/dbus/qdbusmessage_p.h | 2 ++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index 9ea05b2..7168e05 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -196,6 +196,8 @@ DEFINEFUNC(void , dbus_free, (void *memory), (memory), ) /* dbus-message.h */ DEFINEFUNC(DBusMessage* , dbus_message_copy, (const DBusMessage *message), (message), return) +DEFINEFUNC(dbus_bool_t , dbus_message_get_auto_start, (DBusMessage *message), + (message), return) DEFINEFUNC(const char* , dbus_message_get_error_name, (DBusMessage *message), (message), return) DEFINEFUNC(const char* , dbus_message_get_interface, (DBusMessage *message), @@ -268,6 +270,9 @@ DEFINEFUNC(DBusMessage* , dbus_message_new_signal, (const char *path, (path, interface, name), return) DEFINEFUNC(DBusMessage* , dbus_message_ref, (DBusMessage *message), (message), return) +DEFINEFUNC(void , dbus_message_set_auto_start, (DBusMessage *message, + dbus_bool_t auto_start), + (message, auto_start), return) DEFINEFUNC(dbus_bool_t , dbus_message_set_destination, (DBusMessage *message, const char *destination), (message, destination), return) diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index 83b5503..f9be783 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -63,7 +63,7 @@ static inline const char *data(const QByteArray &arr) QDBusMessagePrivate::QDBusMessagePrivate() : msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID), timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false), - parametersValidated(false) + parametersValidated(false), autoStart(true) { } @@ -129,6 +129,7 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(), data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8()); + q_dbus_message_set_auto_start( msg, d_ptr->autoStart ); break; case DBUS_MESSAGE_TYPE_METHOD_RETURN: msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); @@ -644,6 +645,30 @@ bool QDBusMessage::isDelayedReply() const } /*! + Sets whether this message will have the auto start flag. + This flag only makes sense for method call messages. For + these messages it tells the dbus server to either auto + start the service responsible for the service name, or + not to auto start it. + + This flag is true by default. +*/ +void QDBusMessage::setAutoStart(bool enable) const +{ + d_ptr->autoStart = enable; +} + +/*! + Returns the auto start flag, as set by setAutoStart(). By default, this + flag is true, which means QtDBus will auto start a service, if it is + not running already. +*/ +bool QDBusMessage::isAutoStart() const +{ + return d_ptr->autoStart; +} + +/*! Sets the arguments that are going to be sent over D-Bus to \a arguments. Those will be the arguments to a method call or the parameters in the signal. diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h index 1a85983..8106238 100644 --- a/src/dbus/qdbusmessage.h +++ b/src/dbus/qdbusmessage.h @@ -104,6 +104,9 @@ public: void setDelayedReply(bool enable) const; bool isDelayedReply() const; + void setAutoStart(bool enable) const; + bool isAutoStart() const; + void setArguments(const QList &arguments); QList arguments() const; diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h index 6bf5448..eb27562 100644 --- a/src/dbus/qdbusmessage_p.h +++ b/src/dbus/qdbusmessage_p.h @@ -86,6 +86,8 @@ public: uint localMessage : 1; mutable uint parametersValidated : 1; + mutable uint autoStart : 1; + static void setParametersValidated(QDBusMessage &msg, bool enable) { msg.d_ptr->parametersValidated = enable; } -- cgit v0.12 From 3fb70a8beea1dda58e50831edc5dd9073b899f72 Mon Sep 17 00:00:00 2001 From: Holger Schroeder Date: Fri, 12 Feb 2010 14:26:08 +0100 Subject: update according to Thiago's comments. Merge-request: 2307 Reviewed-by: Thiago Macieira --- src/dbus/qdbusmessage.cpp | 34 +++++++++++++++++++++++++--------- src/dbus/qdbusmessage.h | 4 ++-- src/dbus/qdbusmessage_p.h | 3 +-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index f9be783..79c7644 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -63,7 +63,7 @@ static inline const char *data(const QByteArray &arr) QDBusMessagePrivate::QDBusMessagePrivate() : msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID), timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false), - parametersValidated(false), autoStart(true) + parametersValidated(false), autoStartService(true) { } @@ -129,7 +129,7 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(), data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8()); - q_dbus_message_set_auto_start( msg, d_ptr->autoStart ); + q_dbus_message_set_auto_start( msg, d_ptr->autoStartService ); break; case DBUS_MESSAGE_TYPE_METHOD_RETURN: msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); @@ -647,25 +647,41 @@ bool QDBusMessage::isDelayedReply() const /*! Sets whether this message will have the auto start flag. This flag only makes sense for method call messages. For - these messages it tells the dbus server to either auto + these messages it tells the D-Bus server to either auto start the service responsible for the service name, or not to auto start it. - This flag is true by default. + By default this flag is true, i.e. a service is autostarted. + This means: + + When the service that this method call is sent to is already + running, the method call is sent to it. If the service is not + running yet, the D-Bus daemon is requested to autostart the + service that is assigned to this service name. This is + handled by .service files that are placed in a directory known + to the D-Bus server. These files then each contain a service + name and the path to a program that should be executed when + this service name is requested. + + \since 4.7 */ -void QDBusMessage::setAutoStart(bool enable) const +void QDBusMessage::setAutoStartService(bool enable) { - d_ptr->autoStart = enable; + d_ptr->autoStartService = enable; } /*! - Returns the auto start flag, as set by setAutoStart(). By default, this + Returns the auto start flag, as set by setAutoStartService(). By default, this flag is true, which means QtDBus will auto start a service, if it is not running already. + + \sa setAutoStartService() + + \since 4.7 */ -bool QDBusMessage::isAutoStart() const +bool QDBusMessage::autoStartService() const { - return d_ptr->autoStart; + return d_ptr->autoStartService; } /*! diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h index 8106238..6df5215 100644 --- a/src/dbus/qdbusmessage.h +++ b/src/dbus/qdbusmessage.h @@ -104,8 +104,8 @@ public: void setDelayedReply(bool enable) const; bool isDelayedReply() const; - void setAutoStart(bool enable) const; - bool isAutoStart() const; + void setAutoStartService(bool enable); + bool autoStartService() const; void setArguments(const QList &arguments); QList arguments() const; diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h index eb27562..b6da4a5 100644 --- a/src/dbus/qdbusmessage_p.h +++ b/src/dbus/qdbusmessage_p.h @@ -85,8 +85,7 @@ public: mutable uint delayedReply : 1; uint localMessage : 1; mutable uint parametersValidated : 1; - - mutable uint autoStart : 1; + uint autoStartService : 1; static void setParametersValidated(QDBusMessage &msg, bool enable) { msg.d_ptr->parametersValidated = enable; } -- cgit v0.12 From 441aff9d01a1530d2b187098c7c47bc683116a66 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Fri, 12 Feb 2010 16:42:42 +0100 Subject: Fix QRegion under Mac OS X. Now it takes the intersection of QRects for the region to repaint instead of taking the bounding box. --- src/gui/kernel/qcocoaview_mac.mm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 8c5d166..aa00e97 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -488,7 +488,15 @@ extern "C" { qWarning("QWidget::repaint: Recursive repaint detected"); const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height); - QRegion qrgn(qrect); + QRegion qrgn; + + const NSRect *rects; + NSInteger count; + [self getRectsBeingDrawn:&rects count:&count]; + for (int i = 0; i < count; ++i) { + QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height); + qrgn += tmpRect; + } if (!qwidget->isWindow() && !qobject_cast(qwidget->parent())) { const QRegion &parentMask = qwidget->window()->mask(); -- cgit v0.12 From 8911ed8bfe7f918b93c758f9b5d93274b37739e6 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Wed, 20 Jan 2010 14:56:37 +0100 Subject: Optimized QLocale to access system locale on demand. Changed the initialization of the system locale to make construction of the QLocale object as lightweight as possible. So now the default contructor just creates a QLocale and QSystemLocale objects, but doesn't try to fill the cache in the latter with data from the system and postpones it until it is actually requested (most applications create QLocale objects on the stack and might not even use the data from the system locale, so we don't need to initialize system locale right away). Reviewed-by: Thiago Macieira --- src/corelib/tools/qlocale.cpp | 215 ++++++++++++++++++++++++++----------- src/corelib/tools/qlocale.h | 1 + src/corelib/tools/qlocale_p.h | 2 + tests/auto/qlocale/tst_qlocale.cpp | 6 ++ 4 files changed, 164 insertions(+), 60 deletions(-) diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index ff10fa1..1df4fa0 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1274,11 +1274,25 @@ QLocale QSystemLocale::fallbackLocale() const */ QVariant QSystemLocale::query(QueryType type, QVariant /* in */) const { - if (type == MeasurementSystem) { + switch (type) { + case MeasurementSystem: return QVariant(unixGetSystemMeasurementSystem()); - } else { - return QVariant(); + case LanguageId: + case CountryId: { + QString locale = QLatin1String(envVarLocale()); + QLocale::Language lang; + QLocale::Country cntry; + getLangAndCountry(locale, lang, cntry); + if (type == LanguageId) + return lang; + if (cntry == QLocale::AnyCountry) + return fallbackLocale().country(); + return cntry; } + default: + break; + } + return QVariant(); } #elif !defined(Q_OS_SYMBIAN) @@ -1388,7 +1402,8 @@ QSystemLocale::QSystemLocale() /*! \internal */ QSystemLocale::QSystemLocale(bool) -{ } +{ +} /*! Deletes the object. @@ -1410,16 +1425,71 @@ static const QSystemLocale *systemLocale() return QSystemLocale_globalSystemLocale(); } +// returns the private data for the system locale. Cached data will not be +// initialized until the updateSystemPrivate is called. +static const QLocalePrivate *systemPrivate() +{ +#ifndef QT_NO_SYSTEMLOCALE + if (!system_lp) { + system_lp = globalLocalePrivate(); + // mark the locale as uninitialized system locale + system_lp->m_language_id = 0; + } + return system_lp; +#else + return locale_data; +#endif +} + +#ifndef QT_NO_SYSTEMLOCALE +static const QLocalePrivate *maybeSystemPrivate() +{ + return system_lp; +} +#endif + +static const QLocalePrivate *defaultPrivate() +{ + if (!default_lp) + default_lp = systemPrivate(); + return default_lp; +} + +bool QLocalePrivate::isUninitializedSystemLocale() const +{ + return this == maybeSystemPrivate() && m_language_id == 0; +} + +QVariant QLocalePrivate::querySystemLocale(QSystemLocale::QueryType type, const QVariant &in) const +{ + QVariant res = systemLocale()->query(type, in); + if (res.isNull() && isUninitializedSystemLocale()) { + // if we were not able to get data from the system, initialize the + // system locale private data (which is essentially equals to this) + // with a fallback locale. + QLocalePrivate *system_private = globalLocalePrivate(); + *system_private = *systemLocale()->fallbackLocale().d(); + // internal cache is not initialized with values from the system, mark + // it as not fully initialized system locale. + system_private->m_language_id = 0; + } + return res; +} + +// retrieves data from the system locale and caches them locally. void QLocalePrivate::updateSystemPrivate() { const QSystemLocale *sys_locale = systemLocale(); if (!system_lp) - system_lp = globalLocalePrivate(); + return; + + // copy over the information from the fallback locale and modify *system_lp = *sys_locale->fallbackLocale().d(); QVariant res = sys_locale->query(QSystemLocale::LanguageId, QVariant()); if (!res.isNull()) system_lp->m_language_id = res.toInt(); + res = sys_locale->query(QSystemLocale::CountryId, QVariant()); if (!res.isNull()) system_lp->m_country_id = res.toInt(); @@ -1446,26 +1516,6 @@ void QLocalePrivate::updateSystemPrivate() } #endif -static const QLocalePrivate *systemPrivate() -{ -#ifndef QT_NO_SYSTEMLOCALE - // copy over the information from the fallback locale and modify - if (!system_lp || system_lp->m_language_id == 0) - QLocalePrivate::updateSystemPrivate(); - - return system_lp; -#else - return locale_data; -#endif -} - -static const QLocalePrivate *defaultPrivate() -{ - if (!default_lp) - default_lp = systemPrivate(); - return default_lp; -} - static QString getLocaleListData(const ushort *data, int size, int index) { static const ushort separator = ';'; @@ -2283,7 +2333,12 @@ void QLocale::setDefault(const QLocale &locale) */ QLocale::Language QLocale::language() const { - return Language(d()->languageId()); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return Language(dd->languageId()); } /*! @@ -2293,7 +2348,12 @@ QLocale::Language QLocale::language() const */ QLocale::Country QLocale::country() const { - return Country(d()->countryId()); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return Country(dd->countryId()); } /*! @@ -2631,8 +2691,8 @@ QString QLocale::toString(const QDate &date, FormatType format) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(format == LongFormat ? QSystemLocale::DateToStringLong : QSystemLocale::DateToStringShort, date); if (!res.isNull()) @@ -2726,8 +2786,8 @@ QString QLocale::toString(const QDateTime &dateTime, FormatType format) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(format == LongFormat ? QSystemLocale::DateTimeToStringLong : QSystemLocale::DateTimeToStringShort, dateTime); @@ -2752,8 +2812,8 @@ QString QLocale::toString(const QTime &time, FormatType format) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(format == LongFormat ? QSystemLocale::TimeToStringLong : QSystemLocale::TimeToStringShort, time); if (!res.isNull()) @@ -2779,8 +2839,8 @@ QString QLocale::toString(const QTime &time, FormatType format) const QString QLocale::dateFormat(FormatType format) const { #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(format == LongFormat ? QSystemLocale::DateFormatLong : QSystemLocale::DateFormatShort, QVariant()); if (!res.isNull()) @@ -2816,8 +2876,8 @@ QString QLocale::dateFormat(FormatType format) const QString QLocale::timeFormat(FormatType format) const { #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(format == LongFormat ? QSystemLocale::TimeFormatLong : QSystemLocale::TimeFormatShort, QVariant()); if (!res.isNull()) @@ -2853,8 +2913,8 @@ QString QLocale::timeFormat(FormatType format) const QString QLocale::dateTimeFormat(FormatType format) const { #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(format == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(format == LongFormat ? QSystemLocale::DateTimeFormatLong : QSystemLocale::DateTimeFormatShort, QVariant()); @@ -3021,7 +3081,12 @@ QDateTime QLocale::toDateTime(const QString &string, const QString &format) cons */ QChar QLocale::decimalPoint() const { - return d()->decimal(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->decimal(); } /*! @@ -3031,7 +3096,12 @@ QChar QLocale::decimalPoint() const */ QChar QLocale::groupSeparator() const { - return d()->group(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->group(); } /*! @@ -3041,7 +3111,12 @@ QChar QLocale::groupSeparator() const */ QChar QLocale::percent() const { - return d()->percent(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->percent(); } /*! @@ -3051,7 +3126,12 @@ QChar QLocale::percent() const */ QChar QLocale::zeroDigit() const { - return d()->zero(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->zero(); } /*! @@ -3061,7 +3141,12 @@ QChar QLocale::zeroDigit() const */ QChar QLocale::negativeSign() const { - return d()->minus(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->minus(); } /*! @@ -3071,7 +3156,12 @@ QChar QLocale::negativeSign() const */ QChar QLocale::positiveSign() const { - return d()->plus(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->plus(); } /*! @@ -3081,7 +3171,12 @@ QChar QLocale::positiveSign() const */ QChar QLocale::exponential() const { - return d()->exponential(); + const QLocalePrivate *dd = d(); +#ifndef QT_NO_SYSTEMLOCALE + if (dd->isUninitializedSystemLocale()) + QLocalePrivate::updateSystemPrivate(); +#endif + return dd->exponential(); } static bool qIsUpper(char c) @@ -3200,8 +3295,8 @@ QString QLocale::monthName(int month, FormatType type) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(type == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(type == LongFormat ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort, month); if (!res.isNull()) @@ -3246,8 +3341,8 @@ QString QLocale::standaloneMonthName(int month, FormatType type) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(type == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(type == LongFormat ? QSystemLocale::MonthNameLong : QSystemLocale::MonthNameShort, month); if (!res.isNull()) @@ -3293,8 +3388,8 @@ QString QLocale::dayName(int day, FormatType type) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(type == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(type == LongFormat ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort, day); if (!res.isNull()) @@ -3342,8 +3437,8 @@ QString QLocale::standaloneDayName(int day, FormatType type) const return QString(); #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(type == LongFormat + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(type == LongFormat ? QSystemLocale::DayNameLong : QSystemLocale::DayNameShort, day); if (!res.isNull()) @@ -3387,8 +3482,8 @@ QLocale::MeasurementSystem QLocale::measurementSystem() const bool found = false; #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::MeasurementSystem, QVariant()); + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(QSystemLocale::MeasurementSystem, QVariant()); if (!res.isNull()) { meas = MeasurementSystem(res.toInt()); found = true; @@ -3415,8 +3510,8 @@ QLocale::MeasurementSystem QLocale::measurementSystem() const QString QLocale::amText() const { #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::AMText, QVariant()); + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(QSystemLocale::AMText, QVariant()); if (!res.isNull()) return res.toString(); } @@ -3435,8 +3530,8 @@ QString QLocale::amText() const QString QLocale::pmText() const { #ifndef QT_NO_SYSTEMLOCALE - if (d() == systemPrivate()) { - QVariant res = systemLocale()->query(QSystemLocale::PMText, QVariant()); + if (d() == maybeSystemPrivate()) { + QVariant res = d()->querySystemLocale(QSystemLocale::PMText, QVariant()); if (!res.isNull()) return res.toString(); } diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index e854c84..9b7b214 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -638,6 +638,7 @@ public: ; private: friend struct QLocalePrivate; + // ### We now use this field to pack an index into locale_data and NumberOptions. // ### Qt 5: change to a QLocaleData *d; uint numberOptions. union { diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index ecf79e9..b1bdea7 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -132,6 +132,8 @@ public: CharBuff *result) const; inline char digitToCLocale(const QChar &c) const; + inline bool isUninitializedSystemLocale() const; + QVariant querySystemLocale(QSystemLocale::QueryType type, const QVariant &in) const; static void updateSystemPrivate(); enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode }; diff --git a/tests/auto/qlocale/tst_qlocale.cpp b/tests/auto/qlocale/tst_qlocale.cpp index 3dc4dad..8dd5fbb 100644 --- a/tests/auto/qlocale/tst_qlocale.cpp +++ b/tests/auto/qlocale/tst_qlocale.cpp @@ -158,9 +158,15 @@ void tst_QLocale::ctor() QCoreApplication app(argc, (char**)&argv); #endif QLocale default_locale = QLocale::system(); + + QVERIFY(!default_locale.monthName(1, QLocale::LongFormat).isEmpty()); + QVERIFY(!default_locale.monthName(1, QLocale::ShortFormat).isEmpty()); + QVERIFY(default_locale.language() != 0); + QLocale::Language default_lang = default_locale.language(); QLocale::Country default_country = default_locale.country(); + qDebug("Default: %s/%s", QLocale::languageToString(default_lang).toLatin1().constData(), QLocale::countryToString(default_country).toLatin1().constData()); -- cgit v0.12 From 9e5176070cdeba3e96f1969cfbb71bbd407a651e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 13 Feb 2010 21:32:10 +0100 Subject: Don't use QSystemLocale if QT_NO_SYSTEMLOCALE (like QWS) Reviewed-By: Trust Me --- src/corelib/tools/qlocale.cpp | 4 ++-- src/corelib/tools/qlocale_p.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 1df4fa0..dd41154 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1460,9 +1460,9 @@ bool QLocalePrivate::isUninitializedSystemLocale() const return this == maybeSystemPrivate() && m_language_id == 0; } -QVariant QLocalePrivate::querySystemLocale(QSystemLocale::QueryType type, const QVariant &in) const +QVariant QLocalePrivate::querySystemLocale(int type, const QVariant &in) const { - QVariant res = systemLocale()->query(type, in); + QVariant res = systemLocale()->query(QSystemLocale::QueryType(type), in); if (res.isNull() && isUninitializedSystemLocale()) { // if we were not able to get data from the system, initialize the // system locale private data (which is essentially equals to this) diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index b1bdea7..6c0935b 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -133,7 +133,7 @@ public: inline char digitToCLocale(const QChar &c) const; inline bool isUninitializedSystemLocale() const; - QVariant querySystemLocale(QSystemLocale::QueryType type, const QVariant &in) const; + QVariant querySystemLocale(int type, const QVariant &in) const; static void updateSystemPrivate(); enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode }; -- cgit v0.12 From c786e0cd3c40193073ce2f59f98a4d83bbe1a9b9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 14 Feb 2010 08:34:14 +0100 Subject: Don't use QSystemLocale if QT_NO_SYSTEMLOCALE (like QWS) Reviewed-By: Trust Me --- src/corelib/tools/qlocale.cpp | 63 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index dd41154..9625228 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1324,12 +1324,10 @@ QVariant QSystemLocale::query(QueryType /* type */, QVariant /* in */) const #endif -#ifndef QT_NO_SYSTEMLOCALE static QSystemLocale *_systemLocale = 0; Q_GLOBAL_STATIC_WITH_ARGS(QSystemLocale, QSystemLocale_globalSystemLocale, (true)) static QLocalePrivate *system_lp = 0; Q_GLOBAL_STATIC(QLocalePrivate, globalLocalePrivate) -#endif /****************************************************************************** ** Default system locale behavior @@ -1425,36 +1423,7 @@ static const QSystemLocale *systemLocale() return QSystemLocale_globalSystemLocale(); } -// returns the private data for the system locale. Cached data will not be -// initialized until the updateSystemPrivate is called. -static const QLocalePrivate *systemPrivate() -{ -#ifndef QT_NO_SYSTEMLOCALE - if (!system_lp) { - system_lp = globalLocalePrivate(); - // mark the locale as uninitialized system locale - system_lp->m_language_id = 0; - } - return system_lp; -#else - return locale_data; -#endif -} - -#ifndef QT_NO_SYSTEMLOCALE -static const QLocalePrivate *maybeSystemPrivate() -{ - return system_lp; -} -#endif - -static const QLocalePrivate *defaultPrivate() -{ - if (!default_lp) - default_lp = systemPrivate(); - return default_lp; -} - +static const QLocalePrivate *maybeSystemPrivate(); bool QLocalePrivate::isUninitializedSystemLocale() const { return this == maybeSystemPrivate() && m_language_id == 0; @@ -1516,6 +1485,36 @@ void QLocalePrivate::updateSystemPrivate() } #endif +// returns the private data for the system locale. Cached data will not be +// initialized until the updateSystemPrivate is called. +static const QLocalePrivate *systemPrivate() +{ +#ifndef QT_NO_SYSTEMLOCALE + if (!system_lp) { + system_lp = globalLocalePrivate(); + // mark the locale as uninitialized system locale + system_lp->m_language_id = 0; + } + return system_lp; +#else + return locale_data; +#endif +} + +#ifndef QT_NO_SYSTEMLOCALE +static const QLocalePrivate *maybeSystemPrivate() +{ + return system_lp; +} +#endif + +static const QLocalePrivate *defaultPrivate() +{ + if (!default_lp) + default_lp = systemPrivate(); + return default_lp; +} + static QString getLocaleListData(const ushort *data, int size, int index) { static const ushort separator = ';'; -- cgit v0.12 From 9f387357a7e171636c97a7ef13afca60c01a9e3b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Sun, 14 Feb 2010 19:50:51 +0100 Subject: Add API for rich text and getting actual size of QStaticText Required for several use cases, support for some html tags to change font, color and do advanced text layouts, as well as getting the bounds of the text when drawn. --- src/gui/painting/qpainter.cpp | 15 +++++--- src/gui/text/qstatictext.cpp | 80 +++++++++++++++++++++++++++++++------------ src/gui/text/qstatictext.h | 4 ++- src/gui/text/qstatictext_p.h | 10 ++++-- 4 files changed, 78 insertions(+), 31 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 8ab813d..2b5a0c5 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5745,10 +5745,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // 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()) { - if (staticText_d->size.isValid()) - drawText(QRectF(position, staticText_d->size), staticText_d->text); - else - drawText(position, staticText_d->text); + staticText_d->paintText(this); return; } @@ -5784,7 +5781,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static bool restoreWhenFinished = false; if (staticText_d->needsClipRect) { save(); - setClipRect(QRectF(position, staticText_d->size)); + setClipRect(QRectF(position, staticText_d->maximumSize)); restoreWhenFinished = true; } @@ -5815,10 +5812,18 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static staticText_d->position = transformedPosition; } + QPen oldPen = d->state->pen; + QColor currentColor = oldPen.color(); for (int i=0; iitemCount; ++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(); diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 74c5958..2fe23e5 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -129,7 +129,7 @@ QStaticText::QStaticText(const QString &text, const QSizeF &size) : data(new QStaticTextPrivate) { data->text = text; - data->size = size; + data->maximumSize = size; data->init(); } @@ -199,7 +199,7 @@ bool QStaticText::operator==(const QStaticText &other) const return (data == other.data || (data->text == other.data->text && data->font == other.data->font - && data->size == other.data->size)); + && data->maximumSize == other.data->maximumSize)); } /*! @@ -212,16 +212,22 @@ bool QStaticText::operator!=(const QStaticText &other) const } /*! - Sets the text of the QStaticText to \a text. + Sets the text of the QStaticText to \a text. 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 text() */ -void QStaticText::setText(const QString &text) +void QStaticText::setText(const QString &text, Qt::TextFormat textFormat) { detach(); data->text = text; + data->preferRichText = (textFormat == Qt::RichText + || (textFormat == Qt::AutoText && Qt::mightBeRichText(text))); data->init(); } @@ -283,7 +289,7 @@ bool QStaticText::useBackendOptimizations() const void QStaticText::setMaximumSize(const QSizeF &size) { detach(); - data->size = size; + data->maximumSize = size; data->init(); } @@ -294,7 +300,17 @@ void QStaticText::setMaximumSize(const QSizeF &size) */ QSizeF QStaticText::maximumSize() const { - return data->size; + return data->maximumSize; +} + +/*! + Returns the size of the bounding rect for this QStaticText. + + \sa maximumSize() +*/ +QSizeF QStaticText::size() const +{ + return data->actualSize; } /*! @@ -315,7 +331,7 @@ QStaticTextPrivate::QStaticTextPrivate() } QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) - : text(other.text), font(other.font), size(other.size), matrix(other.matrix), + : text(other.text), font(other.font), maximumSize(other.maximumSize), matrix(other.matrix), items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), useBackendOptimizations(false) { @@ -373,6 +389,7 @@ namespace { 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()); @@ -488,7 +505,38 @@ namespace { private: DrawTextItemRecorder *m_paintEngine; }; +} + +void QStaticTextPrivate::paintText(QPainter *p) +{ + if (!preferRichText) { + if (maximumSize.isValid()) { + QRectF boundingRect; + p->drawText(QRectF(QPointF(0, 0), maximumSize), Qt::TextWordWrap, text, &boundingRect); + + actualSize = boundingRect.size(); + needsClipRect = boundingRect.width() > maximumSize.width() + || boundingRect.height() > maximumSize.height(); + } else { + p->drawText(0, 0, 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(QPointF(0, 0), maximumSize) : QRectF(); + document.adjustSize(); + document.drawContents(p, rect); + actualSize = document.size(); + needsClipRect = maximumSize.isValid() + && (actualSize.width() > maximumSize.width() + || actualSize.height() > maximumSize.height()); + } } void QStaticTextPrivate::init() @@ -507,10 +555,8 @@ void QStaticTextPrivate::init() painter.setFont(font); painter.setTransform(matrix); - if (size.isValid()) - painter.drawText(QRectF(QPointF(0, 0), size), text); - else - painter.drawText(0, 0, text); + paintText(&painter); + } itemCount = counterDevice.itemCount(); @@ -533,17 +579,7 @@ void QStaticTextPrivate::init() painter.setFont(font); painter.setTransform(matrix); - if (size.isValid()) { - QRectF boundingRect; - painter.drawText(QRectF(QPointF(0, 0), size), Qt::TextWordWrap, text, &boundingRect); - - needsClipRect = boundingRect.width() > size.width() - || boundingRect.height() > size.height(); - - } else { - painter.drawText(0, 0, text); - needsClipRect = false; - } + paintText(&painter); } } diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 11a4249..7498ad4 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -65,12 +65,14 @@ public: QStaticText(const QStaticText &other); ~QStaticText(); - void setText(const QString &text); + void setText(const QString &text, Qt::TextFormat textFormat = Qt::AutoText); QString text() const; void setMaximumSize(const QSizeF &maximumSize); QSizeF maximumSize() const; + QSizeF size() const; + void prepare(const QTransform &matrix, const QFont &font); void setUseBackendOptimizations(bool on); diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 72c8439..7aee5c4 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -98,11 +98,12 @@ public: 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; // // ================ - // 41 bytes per item + // 51 bytes per item }; class QStaticText; @@ -114,12 +115,14 @@ public: ~QStaticTextPrivate(); void init(); + void paintText(QPainter *p); QAtomicInt ref; // 4 bytes per text QString text; // 4 bytes per text QFont font; // 8 bytes per text - QSizeF size; // 16 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 @@ -130,8 +133,9 @@ public: char needsClipRect : 1; // 1 byte per text char useBackendOptimizations : 1; + char preferRichText : 1; // ================ - // 145 bytes per text + // 171 bytes per text static QStaticTextPrivate *get(const QStaticText *q); }; -- cgit v0.12 From 07536c0230692506d7207970eda8f255736fa653 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Mon, 15 Feb 2010 09:27:19 +1000 Subject: Move type initialization from global static initializers to QmlEngine construction. Task-number: QT-2798 --- src/declarative/graphicsitems/graphicsitems.pri | 3 + .../graphicsitems/qmlgraphicsanchors.cpp | 2 - .../graphicsitems/qmlgraphicsanimatedimage.cpp | 1 - .../graphicsitems/qmlgraphicsborderimage.cpp | 2 - .../graphicsitems/qmlgraphicseffects.cpp | 13 -- .../graphicsitems/qmlgraphicseffects_p.h | 65 +++++++ .../graphicsitems/qmlgraphicsevents.cpp | 3 - .../graphicsitems/qmlgraphicsflickable.cpp | 35 ---- .../graphicsitems/qmlgraphicsflickable_p_p.h | 32 ++++ .../graphicsitems/qmlgraphicsflipable.cpp | 2 - .../graphicsitems/qmlgraphicsfocuspanel.cpp | 2 - .../graphicsitems/qmlgraphicsfocusscope.cpp | 1 - .../qmlgraphicsgraphicsobjectcontainer.cpp | 3 - .../graphicsitems/qmlgraphicsgridview.cpp | 59 ------ .../graphicsitems/qmlgraphicsgridview_p.h | 58 ++++++ src/declarative/graphicsitems/qmlgraphicsimage.cpp | 2 - src/declarative/graphicsitems/qmlgraphicsitem.cpp | 210 --------------------- src/declarative/graphicsitems/qmlgraphicsitem_p.h | 201 ++++++++++++++++++++ .../graphicsitems/qmlgraphicsitemsmodule.cpp | 158 ++++++++++++++++ .../graphicsitems/qmlgraphicsitemsmodule_p.h | 63 +++++++ .../graphicsitems/qmlgraphicslayoutitem.cpp | 2 - .../graphicsitems/qmlgraphicslistview.cpp | 69 ------- .../graphicsitems/qmlgraphicslistview_p.h | 67 +++++++ .../graphicsitems/qmlgraphicsloader.cpp | 2 - .../graphicsitems/qmlgraphicsmouseregion.cpp | 3 - .../graphicsitems/qmlgraphicsparticles.cpp | 10 - src/declarative/graphicsitems/qmlgraphicspath.cpp | 8 - .../graphicsitems/qmlgraphicspathview.cpp | 3 - .../graphicsitems/qmlgraphicspositioners.cpp | 4 - .../graphicsitems/qmlgraphicsrectangle.cpp | 4 - .../graphicsitems/qmlgraphicsrepeater.cpp | 2 - .../graphicsitems/qmlgraphicsscalegrid.cpp | 1 - src/declarative/graphicsitems/qmlgraphicstext.cpp | 1 - .../graphicsitems/qmlgraphicstextedit.cpp | 1 - .../graphicsitems/qmlgraphicstextinput.cpp | 6 - .../graphicsitems/qmlgraphicsvisualitemmodel.cpp | 42 ----- .../graphicsitems/qmlgraphicsvisualitemmodel_p.h | 39 ++++ .../graphicsitems/qmlgraphicswebview.cpp | 28 --- .../graphicsitems/qmlgraphicswebview_p.h | 25 +++ src/declarative/qml/qmlengine.cpp | 8 + 40 files changed, 719 insertions(+), 521 deletions(-) create mode 100644 src/declarative/graphicsitems/qmlgraphicseffects_p.h create mode 100644 src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp create mode 100644 src/declarative/graphicsitems/qmlgraphicsitemsmodule_p.h diff --git a/src/declarative/graphicsitems/graphicsitems.pri b/src/declarative/graphicsitems/graphicsitems.pri index eb6e0ad..db9c29e 100644 --- a/src/declarative/graphicsitems/graphicsitems.pri +++ b/src/declarative/graphicsitems/graphicsitems.pri @@ -1,9 +1,11 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/qmlgraphicsitemsmodule_p.h \ $$PWD/qmlgraphicsanchors_p.h \ $$PWD/qmlgraphicsanchors_p_p.h \ $$PWD/qmlgraphicsevents_p_p.h \ + $$PWD/qmlgraphicseffects_p.h \ $$PWD/qmlgraphicsflickable_p.h \ $$PWD/qmlgraphicsflickable_p_p.h \ $$PWD/qmlgraphicsflipable_p.h \ @@ -52,6 +54,7 @@ HEADERS += \ $$PWD/qmlgraphicseffects.cpp SOURCES += \ + $$PWD/qmlgraphicsitemsmodule.cpp \ $$PWD/qmlgraphicsanchors.cpp \ $$PWD/qmlgraphicsevents.cpp \ $$PWD/qmlgraphicsflickable.cpp \ diff --git a/src/declarative/graphicsitems/qmlgraphicsanchors.cpp b/src/declarative/graphicsitems/qmlgraphicsanchors.cpp index 93055fc..816e580 100644 --- a/src/declarative/graphicsitems/qmlgraphicsanchors.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsanchors.cpp @@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsAnchors) - //TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)? //TODO: support non-parent, non-sibling (need to find lowest common ancestor) diff --git a/src/declarative/graphicsitems/qmlgraphicsanimatedimage.cpp b/src/declarative/graphicsitems/qmlgraphicsanimatedimage.cpp index e01e569..7d1c87a 100644 --- a/src/declarative/graphicsitems/qmlgraphicsanimatedimage.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsanimatedimage.cpp @@ -78,7 +78,6 @@ Item { \endqml \endtable */ -QML_DEFINE_TYPE(Qt,4,6,AnimatedImage,QmlGraphicsAnimatedImage) QmlGraphicsAnimatedImage::QmlGraphicsAnimatedImage(QmlGraphicsItem *parent) : QmlGraphicsImage(*(new QmlGraphicsAnimatedImagePrivate), parent) diff --git a/src/declarative/graphicsitems/qmlgraphicsborderimage.cpp b/src/declarative/graphicsitems/qmlgraphicsborderimage.cpp index 877e141..19da151 100644 --- a/src/declarative/graphicsitems/qmlgraphicsborderimage.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsborderimage.cpp @@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,BorderImage,QmlGraphicsBorderImage) - /*! \qmlclass BorderImage QmlGraphicsBorderImage \brief The BorderImage element provides an image that can be used as a border. diff --git a/src/declarative/graphicsitems/qmlgraphicseffects.cpp b/src/declarative/graphicsitems/qmlgraphicseffects.cpp index e1f5687..268ba28 100644 --- a/src/declarative/graphicsitems/qmlgraphicseffects.cpp +++ b/src/declarative/graphicsitems/qmlgraphicseffects.cpp @@ -43,12 +43,6 @@ #include -QML_DECLARE_TYPE(QGraphicsEffect) -QML_DEFINE_NOCREATE_TYPE(QGraphicsEffect) - -QML_DECLARE_TYPE(QGraphicsBlurEffect) -QML_DEFINE_TYPE(Qt,4,6,Blur,QGraphicsBlurEffect) - /*! \qmlclass Blur QGraphicsBlurEffect \brief The Blur object provides a blur effect. @@ -84,9 +78,6 @@ QML_DEFINE_TYPE(Qt,4,6,Blur,QGraphicsBlurEffect) The default hint is Qt.PerformanceHint. */ -QML_DECLARE_TYPE(QGraphicsColorizeEffect) -QML_DEFINE_TYPE(Qt,4,6,Colorize,QGraphicsColorizeEffect) - /*! \qmlclass Colorize QGraphicsColorizeEffect \brief The Colorize object provides a colorize effect. @@ -112,8 +103,6 @@ QML_DEFINE_TYPE(Qt,4,6,Colorize,QGraphicsColorizeEffect) while 1.0 means full colorization. By default, the strength is 1.0. */ -QML_DECLARE_TYPE(QGraphicsDropShadowEffect) -QML_DEFINE_TYPE(Qt,4,6,DropShadow,QGraphicsDropShadowEffect) /*! \qmlclass DropShadow QGraphicsDropShadowEffect @@ -155,8 +144,6 @@ QML_DEFINE_TYPE(Qt,4,6,DropShadow,QGraphicsDropShadowEffect) By default, the drop color is a semi-transparent dark gray. */ -QML_DECLARE_TYPE(QGraphicsOpacityEffect) -QML_DEFINE_TYPE(Qt,4,6,Opacity,QGraphicsOpacityEffect) /*! \qmlclass Opacity QGraphicsOpacityEffect diff --git a/src/declarative/graphicsitems/qmlgraphicseffects_p.h b/src/declarative/graphicsitems/qmlgraphicseffects_p.h new file mode 100644 index 0000000..2e561f8 --- /dev/null +++ b/src/declarative/graphicsitems/qmlgraphicseffects_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMLGRAPHICSEFFECTS_P_H +#define QMLGRAPHICSEFFECTS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QML_DECLARE_TYPE(QGraphicsEffect) +QML_DECLARE_TYPE(QGraphicsBlurEffect) +QML_DECLARE_TYPE(QGraphicsColorizeEffect) +QML_DECLARE_TYPE(QGraphicsDropShadowEffect) +QML_DECLARE_TYPE(QGraphicsOpacityEffect) + +#endif // QMLGRAPHICSEFFECTS_P_H diff --git a/src/declarative/graphicsitems/qmlgraphicsevents.cpp b/src/declarative/graphicsitems/qmlgraphicsevents.cpp index 9958dea..0d6adf6 100644 --- a/src/declarative/graphicsitems/qmlgraphicsevents.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsevents.cpp @@ -189,7 +189,4 @@ MouseRegion { \endqml */ -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsKeyEvent) -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsMouseEvent) - QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp index 2ff3b30..cf8952d 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp @@ -56,36 +56,6 @@ static const int FlickThreshold = 20; // Really slow flicks can be annoying. static const int minimumFlickVelocity = 200; -class QmlGraphicsFlickableVisibleArea : public QObject -{ - Q_OBJECT - - Q_PROPERTY(qreal xPosition READ xPosition NOTIFY pageChanged) - Q_PROPERTY(qreal yPosition READ yPosition NOTIFY pageChanged) - Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY pageChanged) - Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY pageChanged) - -public: - QmlGraphicsFlickableVisibleArea(QmlGraphicsFlickable *parent=0); - - qreal xPosition() const; - qreal widthRatio() const; - qreal yPosition() const; - qreal heightRatio() const; - - void updateVisible(); - -signals: - void pageChanged(); - -private: - QmlGraphicsFlickable *flickable; - qreal m_xPosition; - qreal m_widthRatio; - qreal m_yPosition; - qreal m_heightRatio; -}; - QmlGraphicsFlickableVisibleArea::QmlGraphicsFlickableVisibleArea(QmlGraphicsFlickable *parent) : QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.) , m_yPosition(0.), m_heightRatio(0.) @@ -356,8 +326,6 @@ void QmlGraphicsFlickablePrivate::updateBeginningEnd() visibleArea->updateVisible(); } -QML_DEFINE_TYPE(Qt,4,6,Flickable,QmlGraphicsFlickable) - /*! \qmlclass Flickable QmlGraphicsFlickable \brief The Flickable item provides a surface that can be "flicked". @@ -1368,7 +1336,4 @@ void QmlGraphicsFlickablePrivate::updateVelocity() QT_END_NAMESPACE -QML_DECLARE_TYPE(QmlGraphicsFlickableVisibleArea) -QML_DEFINE_TYPE(Qt,4,6,VisibleArea,QmlGraphicsFlickableVisibleArea) - #include diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h b/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h index ae164cc..e83e81b 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsflickable_p_p.h @@ -159,6 +159,38 @@ public: QML_DECLARE_LIST_PROXY(QmlGraphicsFlickablePrivate, QObject *, data) }; +class QmlGraphicsFlickableVisibleArea : public QObject +{ + Q_OBJECT + + Q_PROPERTY(qreal xPosition READ xPosition NOTIFY pageChanged) + Q_PROPERTY(qreal yPosition READ yPosition NOTIFY pageChanged) + Q_PROPERTY(qreal widthRatio READ widthRatio NOTIFY pageChanged) + Q_PROPERTY(qreal heightRatio READ heightRatio NOTIFY pageChanged) + +public: + QmlGraphicsFlickableVisibleArea(QmlGraphicsFlickable *parent=0); + + qreal xPosition() const; + qreal widthRatio() const; + qreal yPosition() const; + qreal heightRatio() const; + + void updateVisible(); + +signals: + void pageChanged(); + +private: + QmlGraphicsFlickable *flickable; + qreal m_xPosition; + qreal m_widthRatio; + qreal m_yPosition; + qreal m_heightRatio; +}; + QT_END_NAMESPACE +QML_DECLARE_TYPE(QmlGraphicsFlickableVisibleArea) + #endif diff --git a/src/declarative/graphicsitems/qmlgraphicsflipable.cpp b/src/declarative/graphicsitems/qmlgraphicsflipable.cpp index ff8995b..4116817 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflipable.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsflipable.cpp @@ -49,8 +49,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,Flipable,QmlGraphicsFlipable) - class QmlGraphicsFlipablePrivate : public QmlGraphicsItemPrivate { Q_DECLARE_PUBLIC(QmlGraphicsFlipable) diff --git a/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp b/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp index 333b689..4e1542a 100644 --- a/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp @@ -46,8 +46,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,FocusPanel,QmlGraphicsFocusPanel) - /*! \qmlclass FocusPanel QmlGraphicsFocusPanel \brief The FocusPanel item explicitly creates a focus panel. diff --git a/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp b/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp index 828756c..ce0e376 100644 --- a/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp @@ -42,7 +42,6 @@ #include "qmlgraphicsfocusscope_p.h" QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,FocusScope,QmlGraphicsFocusScope) /*! \qmlclass FocusScope QmlGraphicsFocusScope diff --git a/src/declarative/graphicsitems/qmlgraphicsgraphicsobjectcontainer.cpp b/src/declarative/graphicsitems/qmlgraphicsgraphicsobjectcontainer.cpp index a5a7935..f2b3c00 100644 --- a/src/declarative/graphicsitems/qmlgraphicsgraphicsobjectcontainer.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsgraphicsobjectcontainer.cpp @@ -131,9 +131,6 @@ public: \brief The QmlGraphicsGraphicsObjectContainer class allows you to add QGraphicsObjects into Fluid UI applications. */ -QML_DEFINE_NOCREATE_TYPE(QGraphicsObject) -QML_DEFINE_TYPE(Qt,4,6,GraphicsObjectContainer,QmlGraphicsGraphicsObjectContainer) - QmlGraphicsGraphicsObjectContainer::QmlGraphicsGraphicsObjectContainer(QmlGraphicsItem *parent) : QmlGraphicsItem(*new QmlGraphicsGraphicsObjectContainerPrivate, parent) { diff --git a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp index 83911c0..34aed4e 100644 --- a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp @@ -51,63 +51,6 @@ QT_BEGIN_NAMESPACE -class QmlGraphicsGridViewAttached : public QObject -{ - Q_OBJECT -public: - QmlGraphicsGridViewAttached(QObject *parent) - : QObject(parent), m_isCurrent(false), m_delayRemove(false) {} - ~QmlGraphicsGridViewAttached() { - attachedProperties.remove(parent()); - } - - Q_PROPERTY(QmlGraphicsGridView *view READ view CONSTANT) - QmlGraphicsGridView *view() { return m_view; } - - Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged) - bool isCurrentItem() const { return m_isCurrent; } - void setIsCurrentItem(bool c) { - if (m_isCurrent != c) { - m_isCurrent = c; - emit currentItemChanged(); - } - } - - Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged) - bool delayRemove() const { return m_delayRemove; } - void setDelayRemove(bool delay) { - if (m_delayRemove != delay) { - m_delayRemove = delay; - emit delayRemoveChanged(); - } - } - - static QmlGraphicsGridViewAttached *properties(QObject *obj) { - QmlGraphicsGridViewAttached *rv = attachedProperties.value(obj); - if (!rv) { - rv = new QmlGraphicsGridViewAttached(obj); - attachedProperties.insert(obj, rv); - } - return rv; - } - - void emitAdd() { emit add(); } - void emitRemove() { emit remove(); } - -Q_SIGNALS: - void currentItemChanged(); - void delayRemoveChanged(); - void add(); - void remove(); - -public: - QmlGraphicsGridView *m_view; - bool m_isCurrent; - bool m_delayRemove; - - static QHash attachedProperties; -}; - QHash QmlGraphicsGridViewAttached::attachedProperties; @@ -1754,8 +1697,6 @@ QmlGraphicsGridViewAttached *QmlGraphicsGridView::qmlAttachedProperties(QObject return QmlGraphicsGridViewAttached::properties(obj); } -QML_DEFINE_TYPE(Qt, 4,6, GridView, QmlGraphicsGridView) - QT_END_NAMESPACE #include diff --git a/src/declarative/graphicsitems/qmlgraphicsgridview_p.h b/src/declarative/graphicsitems/qmlgraphicsgridview_p.h index d2ef70e..25a76a3 100644 --- a/src/declarative/graphicsitems/qmlgraphicsgridview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsgridview_p.h @@ -154,6 +154,64 @@ private: void refill(); }; +class QmlGraphicsGridViewAttached : public QObject +{ + Q_OBJECT +public: + QmlGraphicsGridViewAttached(QObject *parent) + : QObject(parent), m_isCurrent(false), m_delayRemove(false) {} + ~QmlGraphicsGridViewAttached() { + attachedProperties.remove(parent()); + } + + Q_PROPERTY(QmlGraphicsGridView *view READ view CONSTANT) + QmlGraphicsGridView *view() { return m_view; } + + Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged) + bool isCurrentItem() const { return m_isCurrent; } + void setIsCurrentItem(bool c) { + if (m_isCurrent != c) { + m_isCurrent = c; + emit currentItemChanged(); + } + } + + Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged) + bool delayRemove() const { return m_delayRemove; } + void setDelayRemove(bool delay) { + if (m_delayRemove != delay) { + m_delayRemove = delay; + emit delayRemoveChanged(); + } + } + + static QmlGraphicsGridViewAttached *properties(QObject *obj) { + QmlGraphicsGridViewAttached *rv = attachedProperties.value(obj); + if (!rv) { + rv = new QmlGraphicsGridViewAttached(obj); + attachedProperties.insert(obj, rv); + } + return rv; + } + + void emitAdd() { emit add(); } + void emitRemove() { emit remove(); } + +Q_SIGNALS: + void currentItemChanged(); + void delayRemoveChanged(); + void add(); + void remove(); + +public: + QmlGraphicsGridView *m_view; + bool m_isCurrent; + bool m_delayRemove; + + static QHash attachedProperties; +}; + + QT_END_NAMESPACE QML_DECLARE_TYPE(QmlGraphicsGridView) diff --git a/src/declarative/graphicsitems/qmlgraphicsimage.cpp b/src/declarative/graphicsitems/qmlgraphicsimage.cpp index 7e63c8b..558511d 100644 --- a/src/declarative/graphicsitems/qmlgraphicsimage.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsimage.cpp @@ -48,8 +48,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,Image,QmlGraphicsImage) - /*! \qmlclass Image QmlGraphicsImage \brief The Image element allows you to add bitmaps to a scene. diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.cpp b/src/declarative/graphicsitems/qmlgraphicsitem.cpp index 8973cb4..9fd8702 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitem.cpp @@ -69,12 +69,6 @@ QT_BEGIN_NAMESPACE #define FLT_MAX 1E+37 #endif -QML_DEFINE_TYPE(Qt,4,6,Item,QmlGraphicsItem) - -QML_DEFINE_NOCREATE_TYPE(QGraphicsTransform); -QML_DEFINE_TYPE(Qt,4,6,Scale,QGraphicsScale) -QML_DEFINE_TYPE(Qt,4,6,Rotation,QGraphicsRotation) - #include "qmlgraphicseffects.cpp" /*! @@ -325,28 +319,6 @@ void QmlGraphicsContents::setItem(QmlGraphicsItem *item) calcWidth(); } -/* - Key filters can be installed on a QmlGraphicsItem, but not removed. Currently they - are only used by attached objects (which are only destroyed on Item - destruction), so this isn't a problem. If in future this becomes any form - of public API, they will have to support removal too. -*/ -class QmlGraphicsItemKeyFilter -{ -public: - QmlGraphicsItemKeyFilter(QmlGraphicsItem * = 0); - virtual ~QmlGraphicsItemKeyFilter(); - - virtual void keyPressed(QKeyEvent *event); - virtual void keyReleased(QKeyEvent *event); - virtual void inputMethodEvent(QInputMethodEvent *event); - virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; - virtual void componentComplete(); - -private: - QmlGraphicsItemKeyFilter *m_next; -}; - QmlGraphicsItemKeyFilter::QmlGraphicsItemKeyFilter(QmlGraphicsItem *item) : m_next(0) { @@ -458,49 +430,6 @@ void QmlGraphicsItemKeyFilter::componentComplete() pressed. */ -class QmlGraphicsKeyNavigationAttachedPrivate : public QObjectPrivate -{ -public: - QmlGraphicsKeyNavigationAttachedPrivate() - : QObjectPrivate(), left(0), right(0), up(0), down(0) {} - - QmlGraphicsItem *left; - QmlGraphicsItem *right; - QmlGraphicsItem *up; - QmlGraphicsItem *down; -}; - -class QmlGraphicsKeyNavigationAttached : public QObject, public QmlGraphicsItemKeyFilter -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QmlGraphicsKeyNavigationAttached) - - Q_PROPERTY(QmlGraphicsItem *left READ left WRITE setLeft NOTIFY changed) - Q_PROPERTY(QmlGraphicsItem *right READ right WRITE setRight NOTIFY changed) - Q_PROPERTY(QmlGraphicsItem *up READ up WRITE setUp NOTIFY changed) - Q_PROPERTY(QmlGraphicsItem *down READ down WRITE setDown NOTIFY changed) -public: - QmlGraphicsKeyNavigationAttached(QObject * = 0); - - QmlGraphicsItem *left() const; - void setLeft(QmlGraphicsItem *); - QmlGraphicsItem *right() const; - void setRight(QmlGraphicsItem *); - QmlGraphicsItem *up() const; - void setUp(QmlGraphicsItem *); - QmlGraphicsItem *down() const; - void setDown(QmlGraphicsItem *); - - static QmlGraphicsKeyNavigationAttached *qmlAttachedProperties(QObject *); - -Q_SIGNALS: - void changed(); - -private: - virtual void keyPressed(QKeyEvent *event); - virtual void keyReleased(QKeyEvent *event); -}; - QmlGraphicsKeyNavigationAttached::QmlGraphicsKeyNavigationAttached(QObject *parent) : QObject(*(new QmlGraphicsKeyNavigationAttachedPrivate), parent), QmlGraphicsItemKeyFilter(qobject_cast(parent)) @@ -964,137 +893,6 @@ void QmlGraphicsKeyNavigationAttached::keyReleased(QKeyEvent *event) */ -class QmlGraphicsKeysAttachedPrivate : public QObjectPrivate -{ -public: - QmlGraphicsKeysAttachedPrivate() - : QObjectPrivate(), inPress(false), inRelease(false) - , inIM(false), enabled(true), imeItem(0), item(0) - {} - - bool isConnected(const char *signalName); - - QGraphicsItem *finalFocusProxy(QGraphicsItem *item) const - { - QGraphicsItem *fp; - while ((fp = item->focusProxy())) - item = fp; - return item; - } - - //loop detection - bool inPress:1; - bool inRelease:1; - bool inIM:1; - - bool enabled : 1; - - QGraphicsItem *imeItem; - QList targets; - QmlGraphicsItem *item; -}; - -class QmlGraphicsKeysAttached : public QObject, public QmlGraphicsItemKeyFilter -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QmlGraphicsKeysAttached) - - Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(QList *forwardTo READ forwardTo) - -public: - QmlGraphicsKeysAttached(QObject *parent=0); - ~QmlGraphicsKeysAttached(); - - bool enabled() const { Q_D(const QmlGraphicsKeysAttached); return d->enabled; } - void setEnabled(bool enabled) { - Q_D(QmlGraphicsKeysAttached); - if (enabled != d->enabled) { - d->enabled = enabled; - emit enabledChanged(); - } - } - - QList *forwardTo() { - Q_D(QmlGraphicsKeysAttached); - return &d->targets; - } - - virtual void componentComplete(); - - static QmlGraphicsKeysAttached *qmlAttachedProperties(QObject *); - -Q_SIGNALS: - void enabledChanged(); - void pressed(QmlGraphicsKeyEvent *event); - void released(QmlGraphicsKeyEvent *event); - void digit0Pressed(QmlGraphicsKeyEvent *event); - void digit1Pressed(QmlGraphicsKeyEvent *event); - void digit2Pressed(QmlGraphicsKeyEvent *event); - void digit3Pressed(QmlGraphicsKeyEvent *event); - void digit4Pressed(QmlGraphicsKeyEvent *event); - void digit5Pressed(QmlGraphicsKeyEvent *event); - void digit6Pressed(QmlGraphicsKeyEvent *event); - void digit7Pressed(QmlGraphicsKeyEvent *event); - void digit8Pressed(QmlGraphicsKeyEvent *event); - void digit9Pressed(QmlGraphicsKeyEvent *event); - - void leftPressed(QmlGraphicsKeyEvent *event); - void rightPressed(QmlGraphicsKeyEvent *event); - void upPressed(QmlGraphicsKeyEvent *event); - void downPressed(QmlGraphicsKeyEvent *event); - - void asteriskPressed(QmlGraphicsKeyEvent *event); - void numberSignPressed(QmlGraphicsKeyEvent *event); - void escapePressed(QmlGraphicsKeyEvent *event); - void returnPressed(QmlGraphicsKeyEvent *event); - void enterPressed(QmlGraphicsKeyEvent *event); - void deletePressed(QmlGraphicsKeyEvent *event); - void spacePressed(QmlGraphicsKeyEvent *event); - void backPressed(QmlGraphicsKeyEvent *event); - void cancelPressed(QmlGraphicsKeyEvent *event); - void selectPressed(QmlGraphicsKeyEvent *event); - void yesPressed(QmlGraphicsKeyEvent *event); - void noPressed(QmlGraphicsKeyEvent *event); - void context1Pressed(QmlGraphicsKeyEvent *event); - void context2Pressed(QmlGraphicsKeyEvent *event); - void context3Pressed(QmlGraphicsKeyEvent *event); - void context4Pressed(QmlGraphicsKeyEvent *event); - void callPressed(QmlGraphicsKeyEvent *event); - void hangupPressed(QmlGraphicsKeyEvent *event); - void flipPressed(QmlGraphicsKeyEvent *event); - void menuPressed(QmlGraphicsKeyEvent *event); - void volumeUpPressed(QmlGraphicsKeyEvent *event); - void volumeDownPressed(QmlGraphicsKeyEvent *event); - -private: - virtual void keyPressed(QKeyEvent *event); - virtual void keyReleased(QKeyEvent *event); - virtual void inputMethodEvent(QInputMethodEvent *); - virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; - - const QByteArray keyToSignal(int key) { - QByteArray keySignal; - if (key >= Qt::Key_0 && key <= Qt::Key_9) { - keySignal = "digit0Pressed"; - keySignal[5] = '0' + (key - Qt::Key_0); - } else { - int i = 0; - while (sigMap[i].key && sigMap[i].key != key) - ++i; - keySignal = sigMap[i].sig; - } - return keySignal; - } - - struct SigMap { - int key; - const char *sig; - }; - - static const SigMap sigMap[]; -}; - const QmlGraphicsKeysAttached::SigMap QmlGraphicsKeysAttached::sigMap[] = { { Qt::Key_Left, "leftPressed" }, { Qt::Key_Right, "rightPressed" }, @@ -3086,14 +2884,6 @@ int QmlGraphicsItemPrivate::restart(QTime &t) return n; } -#include #include QT_END_NAMESPACE - -QML_DECLARE_TYPE(QmlGraphicsKeysAttached) -QML_DECLARE_TYPEINFO(QmlGraphicsKeysAttached, QML_HAS_ATTACHED_PROPERTIES) -QML_DEFINE_TYPE(Qt,4,6,Keys,QmlGraphicsKeysAttached) -QML_DECLARE_TYPE(QmlGraphicsKeyNavigationAttached) -QML_DECLARE_TYPEINFO(QmlGraphicsKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES) -QML_DEFINE_TYPE(Qt,4,6,KeyNavigation,QmlGraphicsKeyNavigationAttached) diff --git a/src/declarative/graphicsitems/qmlgraphicsitem_p.h b/src/declarative/graphicsitems/qmlgraphicsitem_p.h index 1741808..9a77dbb 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsitem_p.h @@ -280,8 +280,209 @@ public: static int restart(QTime &); }; +/* + Key filters can be installed on a QmlGraphicsItem, but not removed. Currently they + are only used by attached objects (which are only destroyed on Item + destruction), so this isn't a problem. If in future this becomes any form + of public API, they will have to support removal too. +*/ +class QmlGraphicsItemKeyFilter +{ +public: + QmlGraphicsItemKeyFilter(QmlGraphicsItem * = 0); + virtual ~QmlGraphicsItemKeyFilter(); + + virtual void keyPressed(QKeyEvent *event); + virtual void keyReleased(QKeyEvent *event); + virtual void inputMethodEvent(QInputMethodEvent *event); + virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; + virtual void componentComplete(); + +private: + QmlGraphicsItemKeyFilter *m_next; +}; + +class QmlGraphicsKeyNavigationAttachedPrivate : public QObjectPrivate +{ +public: + QmlGraphicsKeyNavigationAttachedPrivate() + : QObjectPrivate(), left(0), right(0), up(0), down(0) {} + + QmlGraphicsItem *left; + QmlGraphicsItem *right; + QmlGraphicsItem *up; + QmlGraphicsItem *down; +}; + +class QmlGraphicsKeyNavigationAttached : public QObject, public QmlGraphicsItemKeyFilter +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlGraphicsKeyNavigationAttached) + + Q_PROPERTY(QmlGraphicsItem *left READ left WRITE setLeft NOTIFY changed) + Q_PROPERTY(QmlGraphicsItem *right READ right WRITE setRight NOTIFY changed) + Q_PROPERTY(QmlGraphicsItem *up READ up WRITE setUp NOTIFY changed) + Q_PROPERTY(QmlGraphicsItem *down READ down WRITE setDown NOTIFY changed) +public: + QmlGraphicsKeyNavigationAttached(QObject * = 0); + + QmlGraphicsItem *left() const; + void setLeft(QmlGraphicsItem *); + QmlGraphicsItem *right() const; + void setRight(QmlGraphicsItem *); + QmlGraphicsItem *up() const; + void setUp(QmlGraphicsItem *); + QmlGraphicsItem *down() const; + void setDown(QmlGraphicsItem *); + + static QmlGraphicsKeyNavigationAttached *qmlAttachedProperties(QObject *); + +Q_SIGNALS: + void changed(); + +private: + virtual void keyPressed(QKeyEvent *event); + virtual void keyReleased(QKeyEvent *event); +}; + +class QmlGraphicsKeysAttachedPrivate : public QObjectPrivate +{ +public: + QmlGraphicsKeysAttachedPrivate() + : QObjectPrivate(), inPress(false), inRelease(false) + , inIM(false), enabled(true), imeItem(0), item(0) + {} + + bool isConnected(const char *signalName); + + QGraphicsItem *finalFocusProxy(QGraphicsItem *item) const + { + QGraphicsItem *fp; + while ((fp = item->focusProxy())) + item = fp; + return item; + } + + //loop detection + bool inPress:1; + bool inRelease:1; + bool inIM:1; + + bool enabled : 1; + + QGraphicsItem *imeItem; + QList targets; + QmlGraphicsItem *item; +}; + +class QmlGraphicsKeysAttached : public QObject, public QmlGraphicsItemKeyFilter +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlGraphicsKeysAttached) + + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(QList *forwardTo READ forwardTo) + +public: + QmlGraphicsKeysAttached(QObject *parent=0); + ~QmlGraphicsKeysAttached(); + + bool enabled() const { Q_D(const QmlGraphicsKeysAttached); return d->enabled; } + void setEnabled(bool enabled) { + Q_D(QmlGraphicsKeysAttached); + if (enabled != d->enabled) { + d->enabled = enabled; + emit enabledChanged(); + } + } + + QList *forwardTo() { + Q_D(QmlGraphicsKeysAttached); + return &d->targets; + } + + virtual void componentComplete(); + + static QmlGraphicsKeysAttached *qmlAttachedProperties(QObject *); + +Q_SIGNALS: + void enabledChanged(); + void pressed(QmlGraphicsKeyEvent *event); + void released(QmlGraphicsKeyEvent *event); + void digit0Pressed(QmlGraphicsKeyEvent *event); + void digit1Pressed(QmlGraphicsKeyEvent *event); + void digit2Pressed(QmlGraphicsKeyEvent *event); + void digit3Pressed(QmlGraphicsKeyEvent *event); + void digit4Pressed(QmlGraphicsKeyEvent *event); + void digit5Pressed(QmlGraphicsKeyEvent *event); + void digit6Pressed(QmlGraphicsKeyEvent *event); + void digit7Pressed(QmlGraphicsKeyEvent *event); + void digit8Pressed(QmlGraphicsKeyEvent *event); + void digit9Pressed(QmlGraphicsKeyEvent *event); + + void leftPressed(QmlGraphicsKeyEvent *event); + void rightPressed(QmlGraphicsKeyEvent *event); + void upPressed(QmlGraphicsKeyEvent *event); + void downPressed(QmlGraphicsKeyEvent *event); + + void asteriskPressed(QmlGraphicsKeyEvent *event); + void numberSignPressed(QmlGraphicsKeyEvent *event); + void escapePressed(QmlGraphicsKeyEvent *event); + void returnPressed(QmlGraphicsKeyEvent *event); + void enterPressed(QmlGraphicsKeyEvent *event); + void deletePressed(QmlGraphicsKeyEvent *event); + void spacePressed(QmlGraphicsKeyEvent *event); + void backPressed(QmlGraphicsKeyEvent *event); + void cancelPressed(QmlGraphicsKeyEvent *event); + void selectPressed(QmlGraphicsKeyEvent *event); + void yesPressed(QmlGraphicsKeyEvent *event); + void noPressed(QmlGraphicsKeyEvent *event); + void context1Pressed(QmlGraphicsKeyEvent *event); + void context2Pressed(QmlGraphicsKeyEvent *event); + void context3Pressed(QmlGraphicsKeyEvent *event); + void context4Pressed(QmlGraphicsKeyEvent *event); + void callPressed(QmlGraphicsKeyEvent *event); + void hangupPressed(QmlGraphicsKeyEvent *event); + void flipPressed(QmlGraphicsKeyEvent *event); + void menuPressed(QmlGraphicsKeyEvent *event); + void volumeUpPressed(QmlGraphicsKeyEvent *event); + void volumeDownPressed(QmlGraphicsKeyEvent *event); + +private: + virtual void keyPressed(QKeyEvent *event); + virtual void keyReleased(QKeyEvent *event); + virtual void inputMethodEvent(QInputMethodEvent *); + virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; + + const QByteArray keyToSignal(int key) { + QByteArray keySignal; + if (key >= Qt::Key_0 && key <= Qt::Key_9) { + keySignal = "digit0Pressed"; + keySignal[5] = '0' + (key - Qt::Key_0); + } else { + int i = 0; + while (sigMap[i].key && sigMap[i].key != key) + ++i; + keySignal = sigMap[i].sig; + } + return keySignal; + } + + struct SigMap { + int key; + const char *sig; + }; + + static const SigMap sigMap[]; +}; + Q_DECLARE_OPERATORS_FOR_FLAGS(QmlGraphicsItemPrivate::ChangeTypes); QT_END_NAMESPACE +QML_DECLARE_TYPE(QmlGraphicsKeysAttached) +QML_DECLARE_TYPEINFO(QmlGraphicsKeysAttached, QML_HAS_ATTACHED_PROPERTIES) +QML_DECLARE_TYPE(QmlGraphicsKeyNavigationAttached) +QML_DECLARE_TYPEINFO(QmlGraphicsKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES) + #endif // QMLGRAPHICSITEM_P_H diff --git a/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp b/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp new file mode 100644 index 0000000..d2cfb1a --- /dev/null +++ b/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 "qmlgraphicsitemsmodule_p.h" + +#include +#include +#include + +#include "qmlgraphicsevents_p_p.h" +#include "qmlgraphicseffects_p.h" +#include "qmlgraphicsscalegrid_p_p.h" +#include "qmlgraphicsanimatedimage_p.h" +#include "qmlgraphicsborderimage_p.h" +#include "qmlgraphicspositioners_p.h" +#include "qmlgraphicsmouseregion_p.h" +#include "qmlgraphicsflickable_p.h" +#include "qmlgraphicsflickable_p_p.h" +#include "qmlgraphicsflipable_p.h" +#include "qmlgraphicsfocuspanel_p.h" +#include "qmlgraphicsfocusscope_p.h" +#include "qmlgraphicsgraphicsobjectcontainer_p.h" +#include "qmlgraphicsgridview_p.h" +#include "qmlgraphicsimage_p.h" +#include "qmlgraphicsitem_p.h" +#include "qmlgraphicslayoutitem_p.h" +#include "qmlgraphicslistview_p.h" +#include "qmlgraphicsloader_p.h" +#include "qmlgraphicsmouseregion_p.h" +#include "qmlgraphicsparticles_p.h" +#include "qmlgraphicspath_p.h" +#include "qmlgraphicspathview_p.h" +#include "qmlgraphicsrectangle_p.h" +#include "qmlgraphicsrepeater_p.h" +#include "qmlgraphicstext_p.h" +#include "qmlgraphicstextedit_p.h" +#include "qmlgraphicstextinput_p.h" +#include "qmlgraphicsvisualitemmodel_p.h" +#include "qmlgraphicswebview_p.h" +#include "qmlgraphicswebview_p_p.h" +#include "qmlgraphicsanchors_p.h" + +#define QML_REGISTER_TYPE(URI,VMAJ,VMIN,TYPE,CLASS) \ + qmlRegisterType(#URI, VMAJ, VMIN, #TYPE, #CLASS) + +#define QML_REGISTER_NOCREATE_TYPE(CLASS) \ + qmlRegisterType(#CLASS) + +void QmlGraphicsItemModule::defineModule() +{ + QML_REGISTER_TYPE(Qt,4,6,AnimatedImage,QmlGraphicsAnimatedImage); + QML_REGISTER_TYPE(Qt,4,6,Blur,QGraphicsBlurEffect); + QML_REGISTER_TYPE(Qt,4,6,BorderImage,QmlGraphicsBorderImage); + QML_REGISTER_TYPE(Qt,4,6,Colorize,QGraphicsColorizeEffect); + QML_REGISTER_TYPE(Qt,4,6,Column,QmlGraphicsColumn); + QML_REGISTER_TYPE(Qt,4,6,Drag,QmlGraphicsDrag); + QML_REGISTER_TYPE(Qt,4,6,DropShadow,QGraphicsDropShadowEffect); + QML_REGISTER_TYPE(Qt,4,6,Flickable,QmlGraphicsFlickable); + QML_REGISTER_TYPE(Qt,4,6,Flipable,QmlGraphicsFlipable); + QML_REGISTER_TYPE(Qt,4,6,Flow,QmlGraphicsFlow); + QML_REGISTER_TYPE(Qt,4,6,FocusPanel,QmlGraphicsFocusPanel); + QML_REGISTER_TYPE(Qt,4,6,FocusScope,QmlGraphicsFocusScope); + QML_REGISTER_TYPE(Qt,4,6,Gradient,QmlGraphicsGradient); + QML_REGISTER_TYPE(Qt,4,6,GradientStop,QmlGraphicsGradientStop); + QML_REGISTER_TYPE(Qt,4,6,GraphicsObjectContainer,QmlGraphicsGraphicsObjectContainer); + QML_REGISTER_TYPE(Qt,4,6,Grid,QmlGraphicsGrid); + QML_REGISTER_TYPE(Qt,4,6,GridView,QmlGraphicsGridView); + QML_REGISTER_TYPE(Qt,4,6,Image,QmlGraphicsImage); + QML_REGISTER_TYPE(Qt,4,6,Item,QmlGraphicsItem); + QML_REGISTER_TYPE(Qt,4,6,KeyNavigation,QmlGraphicsKeyNavigationAttached); + QML_REGISTER_TYPE(Qt,4,6,Keys,QmlGraphicsKeysAttached); + QML_REGISTER_TYPE(Qt,4,6,LayoutItem,QmlGraphicsLayoutItem); + QML_REGISTER_TYPE(Qt,4,6,ListView,QmlGraphicsListView); + QML_REGISTER_TYPE(Qt,4,6,Loader,QmlGraphicsLoader); + QML_REGISTER_TYPE(Qt,4,6,MouseRegion,QmlGraphicsMouseRegion); + QML_REGISTER_TYPE(Qt,4,6,Opacity,QGraphicsOpacityEffect); + QML_REGISTER_TYPE(Qt,4,6,ParticleMotion,QmlGraphicsParticleMotion); + QML_REGISTER_TYPE(Qt,4,6,ParticleMotionGravity,QmlGraphicsParticleMotionGravity); + QML_REGISTER_TYPE(Qt,4,6,ParticleMotionLinear,QmlGraphicsParticleMotionLinear); + QML_REGISTER_TYPE(Qt,4,6,ParticleMotionWander,QmlGraphicsParticleMotionWander); + QML_REGISTER_TYPE(Qt,4,6,Particles,QmlGraphicsParticles); + QML_REGISTER_TYPE(Qt,4,6,Path,QmlGraphicsPath); + QML_REGISTER_TYPE(Qt,4,6,PathAttribute,QmlGraphicsPathAttribute); + QML_REGISTER_TYPE(Qt,4,6,PathCubic,QmlGraphicsPathCubic); + QML_REGISTER_TYPE(Qt,4,6,PathLine,QmlGraphicsPathLine); + QML_REGISTER_TYPE(Qt,4,6,PathPercent,QmlGraphicsPathPercent); + QML_REGISTER_TYPE(Qt,4,6,PathQuad,QmlGraphicsPathQuad); + QML_REGISTER_TYPE(Qt,4,6,PathView,QmlGraphicsPathView); + QML_REGISTER_TYPE(Qt,4,6,Pen,QmlGraphicsPen); + QML_REGISTER_TYPE(Qt,4,6,QDoubleValidator,QDoubleValidator); + QML_REGISTER_TYPE(Qt,4,6,QIntValidator,QIntValidator); + QML_REGISTER_TYPE(Qt,4,6,QRegExpValidator,QRegExpValidator); + QML_REGISTER_TYPE(Qt,4,6,Rectangle,QmlGraphicsRectangle); + QML_REGISTER_TYPE(Qt,4,6,Repeater,QmlGraphicsRepeater); + QML_REGISTER_TYPE(Qt,4,6,Rotation,QGraphicsRotation); + QML_REGISTER_TYPE(Qt,4,6,Row,QmlGraphicsRow); + QML_REGISTER_TYPE(Qt,4,6,Scale,QGraphicsScale); + QML_REGISTER_TYPE(Qt,4,6,Text,QmlGraphicsText); + QML_REGISTER_TYPE(Qt,4,6,TextEdit,QmlGraphicsTextEdit); + QML_REGISTER_TYPE(Qt,4,6,TextInput,QmlGraphicsTextInput); + QML_REGISTER_TYPE(Qt,4,6,ViewSection,QmlGraphicsViewSection); + QML_REGISTER_TYPE(Qt,4,6,VisibleArea,QmlGraphicsFlickableVisibleArea); + QML_REGISTER_TYPE(Qt,4,6,VisualDataModel,QmlGraphicsVisualDataModel); + QML_REGISTER_TYPE(Qt,4,6,VisualItemModel,QmlGraphicsVisualItemModel); + QML_REGISTER_TYPE(Qt,4,6,WebView,QmlGraphicsWebView); + + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsAnchors); + QML_REGISTER_NOCREATE_TYPE(QGraphicsEffect); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsKeyEvent); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsMouseEvent); + QML_REGISTER_NOCREATE_TYPE(QGraphicsObject); + QML_REGISTER_NOCREATE_TYPE(QGraphicsTransform); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsPathElement); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsCurve); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsScaleGrid); + QML_REGISTER_NOCREATE_TYPE(QValidator); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsVisualModel); + QML_REGISTER_NOCREATE_TYPE(QAction); + QML_REGISTER_NOCREATE_TYPE(QmlGraphicsWebSettings); +} diff --git a/src/declarative/graphicsitems/qmlgraphicsitemsmodule_p.h b/src/declarative/graphicsitems/qmlgraphicsitemsmodule_p.h new file mode 100644 index 0000000..bf38c24 --- /dev/null +++ b/src/declarative/graphicsitems/qmlgraphicsitemsmodule_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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 QMLGRAPHICSITEMMODULE_H +#define QMLGRAPHICSITEMMODULE_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlGraphicsItemModule +{ +public: + static void defineModule(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLGRAPHICSITEMMODULE_H diff --git a/src/declarative/graphicsitems/qmlgraphicslayoutitem.cpp b/src/declarative/graphicsitems/qmlgraphicslayoutitem.cpp index 7227eb0..98361dc 100644 --- a/src/declarative/graphicsitems/qmlgraphicslayoutitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslayoutitem.cpp @@ -47,8 +47,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,LayoutItem,QmlGraphicsLayoutItem) - /*! \qmlclass LayoutItem QmlGraphicsLayoutItem \brief The LayoutItem element allows you to place your Fluid UI elements inside a classical Qt layout. diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index d0b3739..cdff73e 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -85,72 +85,6 @@ QString QmlGraphicsViewSection::sectionString(const QString &value) return value; } -class QmlGraphicsListViewAttached : public QObject -{ - Q_OBJECT -public: - QmlGraphicsListViewAttached(QObject *parent) - : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {} - ~QmlGraphicsListViewAttached() {} - - Q_PROPERTY(QmlGraphicsListView *view READ view CONSTANT) - QmlGraphicsListView *view() { return m_view; } - - Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged) - bool isCurrentItem() const { return m_isCurrent; } - void setIsCurrentItem(bool c) { - if (m_isCurrent != c) { - m_isCurrent = c; - emit currentItemChanged(); - } - } - - Q_PROPERTY(QString prevSection READ prevSection NOTIFY prevSectionChanged) - QString prevSection() const { return m_prevSection; } - void setPrevSection(const QString §) { - if (m_prevSection != sect) { - m_prevSection = sect; - emit prevSectionChanged(); - } - } - - Q_PROPERTY(QString section READ section NOTIFY sectionChanged) - QString section() const { return m_section; } - void setSection(const QString §) { - if (m_section != sect) { - m_section = sect; - emit sectionChanged(); - } - } - - Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged) - bool delayRemove() const { return m_delayRemove; } - void setDelayRemove(bool delay) { - if (m_delayRemove != delay) { - m_delayRemove = delay; - emit delayRemoveChanged(); - } - } - - void emitAdd() { emit add(); } - void emitRemove() { emit remove(); } - -Q_SIGNALS: - void currentItemChanged(); - void sectionChanged(); - void prevSectionChanged(); - void delayRemoveChanged(); - void add(); - void remove(); - -public: - QmlGraphicsListView *m_view; - bool m_isCurrent; - mutable QString m_section; - QString m_prevSection; - bool m_delayRemove; -}; - //---------------------------------------------------------------------------- class FxListItem @@ -2740,9 +2674,6 @@ QmlGraphicsListViewAttached *QmlGraphicsListView::qmlAttachedProperties(QObject return new QmlGraphicsListViewAttached(obj); } -QML_DEFINE_TYPE(Qt,4,6,ListView,QmlGraphicsListView) -QML_DEFINE_TYPE(Qt,4,6,ViewSection,QmlGraphicsViewSection) - QT_END_NAMESPACE #include diff --git a/src/declarative/graphicsitems/qmlgraphicslistview_p.h b/src/declarative/graphicsitems/qmlgraphicslistview_p.h index 79d678a..42ace15 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicslistview_p.h @@ -227,6 +227,73 @@ private Q_SLOTS: void animStopped(); }; +class QmlGraphicsListViewAttached : public QObject +{ + Q_OBJECT +public: + QmlGraphicsListViewAttached(QObject *parent) + : QObject(parent), m_view(0), m_isCurrent(false), m_delayRemove(false) {} + ~QmlGraphicsListViewAttached() {} + + Q_PROPERTY(QmlGraphicsListView *view READ view CONSTANT) + QmlGraphicsListView *view() { return m_view; } + + Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged) + bool isCurrentItem() const { return m_isCurrent; } + void setIsCurrentItem(bool c) { + if (m_isCurrent != c) { + m_isCurrent = c; + emit currentItemChanged(); + } + } + + Q_PROPERTY(QString prevSection READ prevSection NOTIFY prevSectionChanged) + QString prevSection() const { return m_prevSection; } + void setPrevSection(const QString §) { + if (m_prevSection != sect) { + m_prevSection = sect; + emit prevSectionChanged(); + } + } + + Q_PROPERTY(QString section READ section NOTIFY sectionChanged) + QString section() const { return m_section; } + void setSection(const QString §) { + if (m_section != sect) { + m_section = sect; + emit sectionChanged(); + } + } + + Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged) + bool delayRemove() const { return m_delayRemove; } + void setDelayRemove(bool delay) { + if (m_delayRemove != delay) { + m_delayRemove = delay; + emit delayRemoveChanged(); + } + } + + void emitAdd() { emit add(); } + void emitRemove() { emit remove(); } + +Q_SIGNALS: + void currentItemChanged(); + void sectionChanged(); + void prevSectionChanged(); + void delayRemoveChanged(); + void add(); + void remove(); + +public: + QmlGraphicsListView *m_view; + bool m_isCurrent; + mutable QString m_section; + QString m_prevSection; + bool m_delayRemove; +}; + + QT_END_NAMESPACE QML_DECLARE_TYPEINFO(QmlGraphicsListView, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/declarative/graphicsitems/qmlgraphicsloader.cpp b/src/declarative/graphicsitems/qmlgraphicsloader.cpp index b3486ef..d778c83 100644 --- a/src/declarative/graphicsitems/qmlgraphicsloader.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsloader.cpp @@ -108,8 +108,6 @@ void QmlGraphicsLoaderPrivate::initResize() _q_updateSize(); } -QML_DEFINE_TYPE(Qt,4,6,Loader,QmlGraphicsLoader) - /*! \qmlclass Loader QmlGraphicsLoader \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp b/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp index bd21e7a..fe72e84 100644 --- a/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp @@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE static const int PressAndHoldDelay = 800; -QML_DEFINE_TYPE(Qt,4,6,Drag,QmlGraphicsDrag) QmlGraphicsDrag::QmlGraphicsDrag(QObject *parent) : QObject(parent), _target(0), _axis(XandYAxis), _xmin(0), _xmax(0), _ymin(0), _ymax(0) { @@ -231,8 +230,6 @@ QmlGraphicsMouseRegionPrivate::~QmlGraphicsMouseRegionPrivate() The \e accepted property of the MouseEvent parameter is ignored in this handler. */ -QML_DEFINE_TYPE(Qt,4,6,MouseRegion,QmlGraphicsMouseRegion) - /*! \internal \class QmlGraphicsMouseRegion diff --git a/src/declarative/graphicsitems/qmlgraphicsparticles.cpp b/src/declarative/graphicsitems/qmlgraphicsparticles.cpp index 8c5fb4f..5edd59e 100644 --- a/src/declarative/graphicsitems/qmlgraphicsparticles.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsparticles.cpp @@ -108,8 +108,6 @@ public: //--------------------------------------------------------------------------- -QML_DEFINE_TYPE(Qt,4,6,ParticleMotion,QmlGraphicsParticleMotion) - /*! \class QmlGraphicsParticleMotion \ingroup group_effects @@ -169,8 +167,6 @@ void QmlGraphicsParticleMotion::destroy(QmlGraphicsParticle &particle) \brief The QmlGraphicsParticleMotionLinear class moves the particles linearly. */ -QML_DEFINE_TYPE(Qt,4,6,ParticleMotionLinear,QmlGraphicsParticleMotionLinear) - void QmlGraphicsParticleMotionLinear::advance(QmlGraphicsParticle &p, int interval) { p.x += interval * p.x_velocity; @@ -191,8 +187,6 @@ void QmlGraphicsParticleMotionLinear::advance(QmlGraphicsParticle &p, int interv \brief The QmlGraphicsParticleMotionGravity class moves the particles towards a point. */ -QML_DEFINE_TYPE(Qt,4,6,ParticleMotionGravity,QmlGraphicsParticleMotionGravity) - /*! \qmlproperty int ParticleMotionGravity::xattractor \qmlproperty int ParticleMotionGravity::yattractor @@ -293,8 +287,6 @@ Rectangle { This property holds how quickly the paricles will move from side to side. */ -QML_DEFINE_TYPE(Qt,4,6,ParticleMotionWander,QmlGraphicsParticleMotionWander) - void QmlGraphicsParticleMotionWander::advance(QmlGraphicsParticle &p, int interval) { if (!particles) @@ -561,8 +553,6 @@ void QmlGraphicsParticlesPrivate::updateOpacity(QmlGraphicsParticle &p, int age) } } -QML_DEFINE_TYPE(Qt,4,6,Particles,QmlGraphicsParticles) - /*! \qmlclass Particles \brief The Particles object generates and moves particles. diff --git a/src/declarative/graphicsitems/qmlgraphicspath.cpp b/src/declarative/graphicsitems/qmlgraphicspath.cpp index 18f27af..fae8161 100644 --- a/src/declarative/graphicsitems/qmlgraphicspath.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspath.cpp @@ -49,14 +49,6 @@ #include QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,Path,QmlGraphicsPath) -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsPathElement) -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsCurve) -QML_DEFINE_TYPE(Qt,4,6,PathAttribute,QmlGraphicsPathAttribute) -QML_DEFINE_TYPE(Qt,4,6,PathPercent,QmlGraphicsPathPercent) -QML_DEFINE_TYPE(Qt,4,6,PathLine,QmlGraphicsPathLine) -QML_DEFINE_TYPE(Qt,4,6,PathQuad,QmlGraphicsPathQuad) -QML_DEFINE_TYPE(Qt,4,6,PathCubic,QmlGraphicsPathCubic) /*! \qmlclass PathElement QmlGraphicsPathElement diff --git a/src/declarative/graphicsitems/qmlgraphicspathview.cpp b/src/declarative/graphicsitems/qmlgraphicspathview.cpp index 6718d25..a1c9229 100644 --- a/src/declarative/graphicsitems/qmlgraphicspathview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspathview.cpp @@ -54,9 +54,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,PathView,QmlGraphicsPathView) - - inline qreal qmlMod(qreal x, qreal y) { #ifdef QT_USE_MATH_H_FLOATS diff --git a/src/declarative/graphicsitems/qmlgraphicspositioners.cpp b/src/declarative/graphicsitems/qmlgraphicspositioners.cpp index 5b081a2..142cdce 100644 --- a/src/declarative/graphicsitems/qmlgraphicspositioners.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspositioners.cpp @@ -288,7 +288,6 @@ void QmlGraphicsBasePositioner::finishApplyTransitions() d->moveActions.clear(); } -QML_DEFINE_TYPE(Qt,4,6,Column,QmlGraphicsColumn) /*! \qmlclass Column QmlGraphicsColumn \brief The Column item lines up its children vertically. @@ -418,7 +417,6 @@ void QmlGraphicsColumn::doPositioning() } } -QML_DEFINE_TYPE(Qt,4,6,Row,QmlGraphicsRow) /*! \qmlclass Row QmlGraphicsRow \brief The Row item lines up its children horizontally. @@ -523,7 +521,6 @@ void QmlGraphicsRow::doPositioning() } } -QML_DEFINE_TYPE(Qt,4,6,Grid,QmlGraphicsGrid) /*! \qmlclass Grid QmlGraphicsGrid @@ -711,7 +708,6 @@ void QmlGraphicsGrid::doPositioning() } -QML_DEFINE_TYPE(Qt,4,6,Flow,QmlGraphicsFlow) /*! \qmlclass Flow QmlGraphicsFlow \brief The Flow item lines up its children side by side, wrapping as necessary. diff --git a/src/declarative/graphicsitems/qmlgraphicsrectangle.cpp b/src/declarative/graphicsitems/qmlgraphicsrectangle.cpp index cc09436..ec44d93 100644 --- a/src/declarative/graphicsitems/qmlgraphicsrectangle.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsrectangle.cpp @@ -46,9 +46,6 @@ #include QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,Pen,QmlGraphicsPen) -QML_DEFINE_TYPE(Qt,4,6,GradientStop,QmlGraphicsGradientStop) -QML_DEFINE_TYPE(Qt,4,6,Gradient,QmlGraphicsGradient) /*! \internal @@ -149,7 +146,6 @@ void QmlGraphicsGradient::doUpdate() emit updated(); } -QML_DEFINE_TYPE(Qt,4,6,Rectangle,QmlGraphicsRectangle) /*! \qmlclass Rectangle QmlGraphicsRectangle diff --git a/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp b/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp index 99f0faa..f0e5bb3 100644 --- a/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp @@ -60,8 +60,6 @@ QmlGraphicsRepeaterPrivate::~QmlGraphicsRepeaterPrivate() delete model; } -QML_DEFINE_TYPE(Qt,4,6,Repeater,QmlGraphicsRepeater) - /*! \qmlclass Repeater QmlGraphicsRepeater \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicsscalegrid.cpp b/src/declarative/graphicsitems/qmlgraphicsscalegrid.cpp index f50b79b..94b562b 100644 --- a/src/declarative/graphicsitems/qmlgraphicsscalegrid.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsscalegrid.cpp @@ -52,7 +52,6 @@ QT_BEGIN_NAMESPACE \class QmlGraphicsScaleGrid \brief The QmlGraphicsScaleGrid class allows you to specify a 3x3 grid to use in scaling an image. */ -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsScaleGrid) QmlGraphicsScaleGrid::QmlGraphicsScaleGrid(QObject *parent) : QObject(parent), _left(0), _top(0), _right(0), _bottom(0) { diff --git a/src/declarative/graphicsitems/qmlgraphicstext.cpp b/src/declarative/graphicsitems/qmlgraphicstext.cpp index b13fb7c..89081eb 100644 --- a/src/declarative/graphicsitems/qmlgraphicstext.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstext.cpp @@ -55,7 +55,6 @@ #include QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,Text,QmlGraphicsText) /*! \qmlclass Text QmlGraphicsText diff --git a/src/declarative/graphicsitems/qmlgraphicstextedit.cpp b/src/declarative/graphicsitems/qmlgraphicstextedit.cpp index fc80258..00f7e42 100644 --- a/src/declarative/graphicsitems/qmlgraphicstextedit.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstextedit.cpp @@ -56,7 +56,6 @@ #include QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,TextEdit,QmlGraphicsTextEdit) /*! \qmlclass TextEdit QmlGraphicsTextEdit diff --git a/src/declarative/graphicsitems/qmlgraphicstextinput.cpp b/src/declarative/graphicsitems/qmlgraphicstextinput.cpp index 6d79c7a..ea54351 100644 --- a/src/declarative/graphicsitems/qmlgraphicstextinput.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstextinput.cpp @@ -51,12 +51,6 @@ QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,TextInput,QmlGraphicsTextInput); -QML_DEFINE_NOCREATE_TYPE(QValidator); -QML_DEFINE_TYPE(Qt,4,6,QIntValidator,QIntValidator); -QML_DEFINE_TYPE(Qt,4,6,QDoubleValidator,QDoubleValidator); -QML_DEFINE_TYPE(Qt,4,6,QRegExpValidator,QRegExpValidator); - /*! \qmlclass TextInput QmlGraphicsTextInput The TextInput item allows you to add an editable line of text to a scene. diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp index 2fc143d..b4487a6 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp @@ -66,44 +66,6 @@ QML_DECLARE_TYPE(QListModelInterface) QT_BEGIN_NAMESPACE -class QmlGraphicsVisualItemModelAttached : public QObject -{ - Q_OBJECT - -public: - QmlGraphicsVisualItemModelAttached(QObject *parent) - : QObject(parent), m_index(0) {} - ~QmlGraphicsVisualItemModelAttached() { - attachedProperties.remove(parent()); - } - - Q_PROPERTY(int index READ index NOTIFY indexChanged) - int index() const { return m_index; } - void setIndex(int idx) { - if (m_index != idx) { - m_index = idx; - emit indexChanged(); - } - } - - static QmlGraphicsVisualItemModelAttached *properties(QObject *obj) { - QmlGraphicsVisualItemModelAttached *rv = attachedProperties.value(obj); - if (!rv) { - rv = new QmlGraphicsVisualItemModelAttached(obj); - attachedProperties.insert(obj, rv); - } - return rv; - } - -Q_SIGNALS: - void indexChanged(); - -public: - int m_index; - - static QHash attachedProperties; -}; - QHash QmlGraphicsVisualItemModelAttached::attachedProperties; @@ -1146,10 +1108,6 @@ void QmlGraphicsVisualDataModel::_q_destroyingPackage(QmlPackage *package) emit destroyingItem(qobject_cast(package->part(d->m_part))); } -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsVisualModel); -QML_DEFINE_TYPE(Qt,4,6,VisualItemModel,QmlGraphicsVisualItemModel) -QML_DEFINE_TYPE(Qt,4,6,VisualDataModel,QmlGraphicsVisualDataModel) - QT_END_NAMESPACE #include diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h index ef849b0..9ebf626 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h @@ -195,6 +195,45 @@ private: Q_DISABLE_COPY(QmlGraphicsVisualDataModel) }; +class QmlGraphicsVisualItemModelAttached : public QObject +{ + Q_OBJECT + +public: + QmlGraphicsVisualItemModelAttached(QObject *parent) + : QObject(parent), m_index(0) {} + ~QmlGraphicsVisualItemModelAttached() { + attachedProperties.remove(parent()); + } + + Q_PROPERTY(int index READ index NOTIFY indexChanged) + int index() const { return m_index; } + void setIndex(int idx) { + if (m_index != idx) { + m_index = idx; + emit indexChanged(); + } + } + + static QmlGraphicsVisualItemModelAttached *properties(QObject *obj) { + QmlGraphicsVisualItemModelAttached *rv = attachedProperties.value(obj); + if (!rv) { + rv = new QmlGraphicsVisualItemModelAttached(obj); + attachedProperties.insert(obj, rv); + } + return rv; + } + +Q_SIGNALS: + void indexChanged(); + +public: + int m_index; + + static QHash attachedProperties; +}; + + QT_END_NAMESPACE QML_DECLARE_TYPE(QmlGraphicsVisualModel) diff --git a/src/declarative/graphicsitems/qmlgraphicswebview.cpp b/src/declarative/graphicsitems/qmlgraphicswebview.cpp index 85fd0d7..c71a366 100644 --- a/src/declarative/graphicsitems/qmlgraphicswebview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicswebview.cpp @@ -64,13 +64,9 @@ #include QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(Qt,4,6,WebView,QmlGraphicsWebView) -QML_DEFINE_NOCREATE_TYPE(QAction) static const int MAX_DOUBLECLICK_TIME=500; // XXX need better gesture system -QML_DEFINE_NOCREATE_TYPE(QmlGraphicsWebSettings) - class QmlGraphicsWebViewPrivate : public QmlGraphicsPaintedItemPrivate { Q_DECLARE_PUBLIC(QmlGraphicsWebView) @@ -461,30 +457,6 @@ QmlList *QmlGraphicsWebView::javaScriptWindowObjects() return &d->windowObjects; } -class QmlGraphicsWebViewAttached : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString windowObjectName READ windowObjectName WRITE setWindowObjectName) -public: - QmlGraphicsWebViewAttached(QObject *parent) - : QObject(parent) - { - } - - QString windowObjectName() const - { - return m_windowObjectName; - } - - void setWindowObjectName(const QString &n) - { - m_windowObjectName = n; - } - -private: - QString m_windowObjectName; -}; - QmlGraphicsWebViewAttached *QmlGraphicsWebView::qmlAttachedProperties(QObject *o) { return new QmlGraphicsWebViewAttached(o); diff --git a/src/declarative/graphicsitems/qmlgraphicswebview_p.h b/src/declarative/graphicsitems/qmlgraphicswebview_p.h index f5edb7a..c370c59 100644 --- a/src/declarative/graphicsitems/qmlgraphicswebview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicswebview_p.h @@ -246,6 +246,31 @@ private: friend class QmlGraphicsWebPage; }; +class QmlGraphicsWebViewAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString windowObjectName READ windowObjectName WRITE setWindowObjectName) +public: + QmlGraphicsWebViewAttached(QObject *parent) + : QObject(parent) + { + } + + QString windowObjectName() const + { + return m_windowObjectName; + } + + void setWindowObjectName(const QString &n) + { + m_windowObjectName = n; + } + +private: + QString m_windowObjectName; +}; + + QT_END_NAMESPACE QML_DECLARE_TYPE(QmlGraphicsWebView) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index cdbe5f3..35fc3d4 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -95,6 +95,8 @@ #include #include +#include + #ifdef Q_OS_WIN // for %APPDATA% #include #include @@ -136,6 +138,8 @@ struct StaticQtMetaObject : public QObject { return &static_cast (0)->staticQtMetaObject; } }; +static bool qt_QmlQtModule_registered = false; + QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : captureProperties(false), rootContext(0), currentExpression(0), isDebugging(false), contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), @@ -144,6 +148,10 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) networkAccessManager(0), networkAccessManagerFactory(0), typeManager(e), uniqueId(1) { + if (!qt_QmlQtModule_registered) { + qt_QmlQtModule_registered = true; + QmlGraphicsItemModule::defineModule(); + } globalClass = new QmlGlobalScriptClass(&scriptEngine); fileImportPath.append(QLibraryInfo::location(QLibraryInfo::DataPath)+QDir::separator()+QLatin1String("qml")); } -- cgit v0.12 From 21f9b43979f5a8193de8932448466aa42d7a4e5f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 12 Feb 2010 16:24:11 +1000 Subject: Remove noop code --- src/declarative/qml/qmlcomponent.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 9e06016..343bd4b 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -539,7 +539,6 @@ QObject *QmlComponent::create(QmlContext *context) QObject *QmlComponentPrivate::create(QmlContext *context, const QBitField &bindings) { - QObject *create(QmlContext *context, const QBitField &); if (!context) context = engine->rootContext(); -- cgit v0.12 From 3cc41dc8cd0c3d1e0540f3f3e975d62a4dc89e9b Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 15 Feb 2010 10:48:28 +1000 Subject: Fix hue rotation in QPainterVideoSurface. --- src/multimedia/base/qpaintervideosurface.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index 533ddee..f097db8 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -368,17 +368,17 @@ void QVideoSurfaceGLPainter::updateColors(int brightness, int contrast, int hue, const qreal cosH = qCos(M_PI * h); const qreal sinH = qSin(M_PI * h); - const qreal h11 = -0.4728 * cosH + 0.7954 * sinH + 1.4728; - const qreal h21 = -0.9253 * cosH - 0.0118 * sinH + 0.9523; - const qreal h31 = 0.4525 * cosH + 0.8072 * sinH - 0.4524; + const qreal h11 = 0.787 * cosH - 0.213 * sinH + 0.213; + const qreal h21 = -0.213 * cosH + 0.143 * sinH + 0.213; + const qreal h31 = -0.213 * cosH - 0.787 * sinH + 0.213; - const qreal h12 = 1.4728 * cosH - 1.3728 * sinH - 1.4728; - const qreal h22 = 1.9253 * cosH + 0.5891 * sinH - 0.9253; - const qreal h32 = -0.4525 * cosH - 1.9619 * sinH + 0.4525; + const qreal h12 = -0.715 * cosH - 0.715 * sinH + 0.715; + const qreal h22 = 0.285 * cosH + 0.140 * sinH + 0.715; + const qreal h32 = -0.715 * cosH + 0.715 * sinH + 0.715; - const qreal h13 = 1.4728 * cosH - 0.2181 * sinH - 1.4728; - const qreal h23 = 0.9253 * cosH + 1.1665 * sinH - 0.9253; - const qreal h33 = 0.5475 * cosH - 1.3846 * sinH + 0.4525; + const qreal h13 = -0.072 * cosH + 0.928 * sinH + 0.072; + const qreal h23 = -0.072 * cosH - 0.283 * sinH + 0.072; + const qreal h33 = 0.928 * cosH + 0.072 * sinH + 0.072; const qreal sr = (1.0 - s) * 0.3086; const qreal sg = (1.0 - s) * 0.6094; -- cgit v0.12 From ec2a1fc447112d7200a378d56cf83894cdd00653 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 15 Feb 2010 11:09:09 +1000 Subject: Extend hue rotation to a full 360 degrees. --- src/multimedia/base/qpaintervideosurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index f097db8..f451809 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -362,7 +362,7 @@ void QVideoSurfaceGLPainter::updateColors(int brightness, int contrast, int hue, { const qreal b = brightness / 200.0; const qreal c = contrast / 100.0 + 1.0; - const qreal h = hue / 200.0; + const qreal h = hue / 100.0; const qreal s = saturation / 100.0 + 1.0; const qreal cosH = qCos(M_PI * h); -- cgit v0.12 From e9c56612c633a19c8abbe9215aa46091c454846d Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 11:33:31 +1000 Subject: Use correct path for headers and source in qml.pri. --- src/multimedia/qml/qml.pri | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/multimedia/qml/qml.pri b/src/multimedia/qml/qml.pri index a30c3ad..370232e 100644 --- a/src/multimedia/qml/qml.pri +++ b/src/multimedia/qml/qml.pri @@ -4,16 +4,16 @@ contains(QT_CONFIG, declarative) { system(pkg-config --exists \'libpulse >= 0.9.10\') { DEFINES += QT_MULTIMEDIA_PULSEAUDIO - HEADERS += qsoundeffect_pulse_p.h - SOURCES += qsoundeffect_pulse_p.cpp + HEADERS += $$PWD/qsoundeffect_pulse_p.h + SOURCES += $$PWD/qsoundeffect_pulse_p.cpp LIBS += -lpulse } else:x11 { DEFINES += QT_MULTIMEDIA_QMEDIAPLAYER - HEADERS += qsoundeffect_qmedia_p.h - SOURCES += qsoundeffect_qmedia_p.cpp + HEADERS += $$PWD/qsoundeffect_qmedia_p.h + SOURCES += $$PWD/qsoundeffect_qmedia_p.cpp } else { - HEADERS += qsoundeffect_qsound_p.h - SOURCES += qsoundeffect_qsound_p.cpp + HEADERS += $$PWD/qsoundeffect_qsound_p.h + SOURCES += $$PWD/qsoundeffect_qsound_p.cpp } HEADERS += \ -- cgit v0.12 From f58f47afb83ddeb5e3374c3089f2e602df27b48d Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 11:34:44 +1000 Subject: Use correct path for private header. --- src/multimedia/qml/qmlmediabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multimedia/qml/qmlmediabase.cpp b/src/multimedia/qml/qmlmediabase.cpp index 17be240..11b4337 100644 --- a/src/multimedia/qml/qmlmediabase.cpp +++ b/src/multimedia/qml/qmlmediabase.cpp @@ -48,7 +48,7 @@ #include #include #include -#include +#include -- cgit v0.12 From 11d3a73d43553a28cf6fae4e8741f09f419f7d90 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 11:36:27 +1000 Subject: Use correct license headers. --- src/multimedia/qml/qsoundeffect.cpp | 4 ++-- src/multimedia/qml/qsoundeffect_p.h | 4 ++-- src/multimedia/qml/qsoundeffect_pulse_p.cpp | 4 ++-- src/multimedia/qml/qsoundeffect_pulse_p.h | 4 ++-- src/multimedia/qml/qsoundeffect_qmedia_p.cpp | 4 ++-- src/multimedia/qml/qsoundeffect_qmedia_p.h | 4 ++-- src/multimedia/qml/qsoundeffect_qsound_p.cpp | 4 ++-- src/multimedia/qml/qsoundeffect_qsound_p.h | 4 ++-- src/multimedia/qml/wavedecoder_p.cpp | 4 ++-- src/multimedia/qml/wavedecoder_p.h | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/multimedia/qml/qsoundeffect.cpp b/src/multimedia/qml/qsoundeffect.cpp index 9692c89..b9174b7 100644 --- a/src/multimedia/qml/qsoundeffect.cpp +++ b/src/multimedia/qml/qsoundeffect.cpp @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_p.h b/src/multimedia/qml/qsoundeffect_p.h index de7070e..00bf64b 100644 --- a/src/multimedia/qml/qsoundeffect_p.h +++ b/src/multimedia/qml/qsoundeffect_p.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.cpp b/src/multimedia/qml/qsoundeffect_pulse_p.cpp index c16e999..6d7b222 100644 --- a/src/multimedia/qml/qsoundeffect_pulse_p.cpp +++ b/src/multimedia/qml/qsoundeffect_pulse_p.cpp @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.h b/src/multimedia/qml/qsoundeffect_pulse_p.h index 05728d0..7e857d2 100644 --- a/src/multimedia/qml/qsoundeffect_pulse_p.h +++ b/src/multimedia/qml/qsoundeffect_pulse_p.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.cpp b/src/multimedia/qml/qsoundeffect_qmedia_p.cpp index 26354a5..e5ac0d3 100644 --- a/src/multimedia/qml/qsoundeffect_qmedia_p.cpp +++ b/src/multimedia/qml/qsoundeffect_qmedia_p.cpp @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.h b/src/multimedia/qml/qsoundeffect_qmedia_p.h index 8b3165a..d04c0d6 100644 --- a/src/multimedia/qml/qsoundeffect_qmedia_p.h +++ b/src/multimedia/qml/qsoundeffect_qmedia_p.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.cpp b/src/multimedia/qml/qsoundeffect_qsound_p.cpp index fd40a05..33f5bd4 100644 --- a/src/multimedia/qml/qsoundeffect_qsound_p.cpp +++ b/src/multimedia/qml/qsoundeffect_qsound_p.cpp @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.h b/src/multimedia/qml/qsoundeffect_qsound_p.h index ac47e8f..991da22 100644 --- a/src/multimedia/qml/qsoundeffect_qsound_p.h +++ b/src/multimedia/qml/qsoundeffect_qsound_p.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/wavedecoder_p.cpp b/src/multimedia/qml/wavedecoder_p.cpp index f45f25c..5fc5a96 100644 --- a/src/multimedia/qml/wavedecoder_p.cpp +++ b/src/multimedia/qml/wavedecoder_p.cpp @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/src/multimedia/qml/wavedecoder_p.h b/src/multimedia/qml/wavedecoder_p.h index 010fec6..70b485c 100644 --- a/src/multimedia/qml/wavedecoder_p.h +++ b/src/multimedia/qml/wavedecoder_p.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 Qt Mobility Components. +** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage -- cgit v0.12 From 215608a69f3ff889b75df600a2f9fbfbe850e430 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 11:38:02 +1000 Subject: Cleanup include files. --- src/multimedia/qml/qsoundeffect_p.h | 14 ++++++++++++-- src/multimedia/qml/qsoundeffect_pulse_p.h | 18 +++++++++++------- src/multimedia/qml/qsoundeffect_qmedia_p.h | 12 ++++++++---- src/multimedia/qml/qsoundeffect_qsound_p.h | 11 ++++++++--- src/multimedia/qml/wavedecoder_p.h | 12 +++++++++++- 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/multimedia/qml/qsoundeffect_p.h b/src/multimedia/qml/qsoundeffect_p.h index 00bf64b..6d5790d 100644 --- a/src/multimedia/qml/qsoundeffect_p.h +++ b/src/multimedia/qml/qsoundeffect_p.h @@ -56,7 +56,12 @@ #include #include -#include +#include + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE class QSoundEffectPrivate; class QSoundEffect : public QObject @@ -111,6 +116,11 @@ private: QSoundEffectPrivate* d; }; -QML_DECLARE_TYPE(QSoundEffect) +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QSoundEffect)) + +QT_END_HEADER + #endif // QSOUNDEFFECT_H diff --git a/src/multimedia/qml/qsoundeffect_pulse_p.h b/src/multimedia/qml/qsoundeffect_pulse_p.h index 7e857d2..155d7fc 100644 --- a/src/multimedia/qml/qsoundeffect_pulse_p.h +++ b/src/multimedia/qml/qsoundeffect_pulse_p.h @@ -54,17 +54,17 @@ // -#include - -#include - -#include - #include "qsoundeffect_p.h" +#include +#include +#include #include -QTM_USE_NAMESPACE + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE class QNetworkReply; class QNetworkAccessManager; @@ -131,4 +131,8 @@ private: QNetworkAccessManager *m_networkAccessManager; }; +QT_END_NAMESPACE + +QT_END_HEADER + #endif // QSOUNDEFFECT_PULSE_H diff --git a/src/multimedia/qml/qsoundeffect_qmedia_p.h b/src/multimedia/qml/qsoundeffect_qmedia_p.h index d04c0d6..e17d720 100644 --- a/src/multimedia/qml/qsoundeffect_qmedia_p.h +++ b/src/multimedia/qml/qsoundeffect_qmedia_p.h @@ -56,13 +56,13 @@ #include #include +#include +#include "qsoundeffect_p.h" -#include -#include -#include "qsoundeffect_p.h" +QT_BEGIN_HEADER -QTM_USE_NAMESPACE +QT_BEGIN_NAMESPACE class WaveDecoder; @@ -102,4 +102,8 @@ private: QMediaPlayer *m_player; }; +QT_END_NAMESPACE + +QT_END_HEADER + #endif // QSOUNDEFFECT_QMEDIA_H diff --git a/src/multimedia/qml/qsoundeffect_qsound_p.h b/src/multimedia/qml/qsoundeffect_qsound_p.h index 991da22..45c0888 100644 --- a/src/multimedia/qml/qsoundeffect_qsound_p.h +++ b/src/multimedia/qml/qsoundeffect_qsound_p.h @@ -56,13 +56,14 @@ #include #include - -#include +#include #include "qsoundeffect_p.h" -QTM_USE_NAMESPACE +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE class QTimer; class QSound; @@ -121,4 +122,8 @@ private: QTimer *m_timer; }; +QT_END_NAMESPACE + +QT_END_HEADER + #endif // QSOUNDEFFECT_QSOUND_H diff --git a/src/multimedia/qml/wavedecoder_p.h b/src/multimedia/qml/wavedecoder_p.h index 70b485c..3bcd90d 100644 --- a/src/multimedia/qml/wavedecoder_p.h +++ b/src/multimedia/qml/wavedecoder_p.h @@ -45,9 +45,15 @@ #include #include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + class WaveDecoder : public QIODevice { -Q_OBJECT + Q_OBJECT public: explicit WaveDecoder(QIODevice *source, QObject *parent = 0); @@ -110,4 +116,8 @@ private: CombinedHeader header; }; +QT_END_NAMESPACE + +QT_END_HEADER + #endif // WAVEDECODER_H -- cgit v0.12 From fb28599786d069a2b99040bd7eee8c5ad8ef1ba9 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Mon, 15 Feb 2010 11:47:52 +1000 Subject: Not exported in Qt 4.6.2, push to next release. --- tools/qmlviewer/qmlviewer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 1566473..8b3b7aa 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -52,8 +52,9 @@ #include #include "deviceskin.h" -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 3)) #include +#define QMLVIEWER_ZIP_SUPPORT #endif #include @@ -866,7 +867,7 @@ void QmlViewer::reload() void QmlViewer::open(const QString& doc) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) +#ifdef QMLVIEWER_ZIP_SUPPORT if (doc.endsWith(".wgt",Qt::CaseInsensitive) || doc.endsWith(".wgz",Qt::CaseInsensitive) || doc.endsWith(".zip",Qt::CaseInsensitive)) @@ -878,7 +879,7 @@ void QmlViewer::open(const QString& doc) void QmlViewer::openWgt(const QString& doc) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) +#ifdef QMLVIEWER_ZIP_SUPPORT // XXX This functionality could be migrated to QmlView once refined QUrl url(doc); @@ -891,7 +892,7 @@ void QmlViewer::openWgt(const QString& doc) #endif } -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) +#ifdef QMLVIEWER_ZIP_SUPPORT static void removeRecursive(const QString& dirname) { QDir dir(dirname); @@ -907,7 +908,7 @@ static void removeRecursive(const QString& dirname) void QmlViewer::unpackWgt() { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) +#ifdef QMLVIEWER_ZIP_SUPPORT QByteArray all = wgtreply->readAll(); QBuffer buf(&all); buf.open(QIODevice::ReadOnly); -- cgit v0.12 From a0839595a5738b4c9b3f2e80a8265df885d8d80c Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 15 Feb 2010 11:48:25 +1000 Subject: Fix flickering when items are overlaid on QGraphicsVideoItem. Re-enable scissor and stencil tests so the texture frame is clipped correctly. Otherwise when an overlaid item is updated the entire frame will be redrawn not just the part intersecting the updated item, resulting in other items being drawn over. --- src/multimedia/base/qgraphicsvideoitem.cpp | 6 +----- src/multimedia/base/qpaintervideosurface.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/multimedia/base/qgraphicsvideoitem.cpp b/src/multimedia/base/qgraphicsvideoitem.cpp index 8aba269..85369db 100644 --- a/src/multimedia/base/qgraphicsvideoitem.cpp +++ b/src/multimedia/base/qgraphicsvideoitem.cpp @@ -47,7 +47,7 @@ #include #include #include - +#include QT_BEGIN_NAMESPACE @@ -384,9 +384,6 @@ void QGraphicsVideoItem::paint( if (d->surface && d->surface->isActive()) { d->surface->paint(painter, d->boundingRect, d->sourceRect); d->surface->setReady(true); -#ifndef QGRAPHICSVIDEOITEM_SHADERS // Flickers - } -#else } else if (d->updatePaintDevice && (painter->paintEngine()->type() == QPaintEngine::OpenGL || painter->paintEngine()->type() == QPaintEngine::OpenGL2)) { d->updatePaintDevice = false; @@ -398,7 +395,6 @@ void QGraphicsVideoItem::paint( d->surface->setShaderType(QPainterVideoSurface::FragmentProgramShader); } } -#endif } /*! diff --git a/src/multimedia/base/qpaintervideosurface.cpp b/src/multimedia/base/qpaintervideosurface.cpp index f451809..f7ffb02 100644 --- a/src/multimedia/base/qpaintervideosurface.cpp +++ b/src/multimedia/base/qpaintervideosurface.cpp @@ -982,6 +982,9 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( if (m_frame.isValid()) { painter->beginNativePainting(); + glEnable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + const int width = QGLContext::currentContext()->device()->width(); const int height = QGLContext::currentContext()->device()->height(); @@ -1072,6 +1075,9 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( m_program.release(); + + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); painter->endNativePainting(); } return QAbstractVideoSurface::NoError; -- cgit v0.12 From b258be1d39889e65411324fe5cda47a34f814033 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Mon, 15 Feb 2010 12:47:36 +1000 Subject: Fix build Remove unneeded .moc imports resulting from moved classes. --- src/declarative/graphicsitems/qmlgraphicsflickable.cpp | 2 -- src/declarative/graphicsitems/qmlgraphicsgridview.cpp | 2 -- src/declarative/graphicsitems/qmlgraphicslistview.cpp | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp index cf8952d..5143251 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp @@ -1335,5 +1335,3 @@ void QmlGraphicsFlickablePrivate::updateVelocity() } QT_END_NAMESPACE - -#include diff --git a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp index 34aed4e..ee711b4 100644 --- a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp @@ -1698,5 +1698,3 @@ QmlGraphicsGridViewAttached *QmlGraphicsGridView::qmlAttachedProperties(QObject } QT_END_NAMESPACE - -#include diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index cdff73e..db0afe1 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -2675,5 +2675,3 @@ QmlGraphicsListViewAttached *QmlGraphicsListView::qmlAttachedProperties(QObject } QT_END_NAMESPACE - -#include -- cgit v0.12 From 40a8d38c68258623da468483b75c5256240d0557 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Mon, 15 Feb 2010 13:04:59 +1000 Subject: Fix compile with -no-webkit --- src/declarative/graphicsitems/qmlgraphicsitem.h | 2 ++ src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp | 6 ++++++ src/declarative/graphicsitems/qmlgraphicswebview_p.h | 1 - 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.h b/src/declarative/graphicsitems/qmlgraphicsitem.h index 8ae2d5c..e0f33c7 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.h +++ b/src/declarative/graphicsitems/qmlgraphicsitem.h @@ -50,6 +50,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -233,6 +234,7 @@ QML_DECLARE_TYPE(QmlGraphicsItem) QML_DECLARE_TYPE(QGraphicsTransform) QML_DECLARE_TYPE(QGraphicsScale) QML_DECLARE_TYPE(QGraphicsRotation) +QML_DECLARE_TYPE(QAction) QT_END_HEADER diff --git a/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp b/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp index d2cfb1a..127aec8 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitemsmodule.cpp @@ -74,8 +74,10 @@ #include "qmlgraphicstextedit_p.h" #include "qmlgraphicstextinput_p.h" #include "qmlgraphicsvisualitemmodel_p.h" +#ifdef QT_WEBKIT_LIB #include "qmlgraphicswebview_p.h" #include "qmlgraphicswebview_p_p.h" +#endif #include "qmlgraphicsanchors_p.h" #define QML_REGISTER_TYPE(URI,VMAJ,VMIN,TYPE,CLASS) \ @@ -140,7 +142,9 @@ void QmlGraphicsItemModule::defineModule() QML_REGISTER_TYPE(Qt,4,6,VisibleArea,QmlGraphicsFlickableVisibleArea); QML_REGISTER_TYPE(Qt,4,6,VisualDataModel,QmlGraphicsVisualDataModel); QML_REGISTER_TYPE(Qt,4,6,VisualItemModel,QmlGraphicsVisualItemModel); +#ifdef QT_WEBKIT_LIB QML_REGISTER_TYPE(Qt,4,6,WebView,QmlGraphicsWebView); +#endif QML_REGISTER_NOCREATE_TYPE(QmlGraphicsAnchors); QML_REGISTER_NOCREATE_TYPE(QGraphicsEffect); @@ -154,5 +158,7 @@ void QmlGraphicsItemModule::defineModule() QML_REGISTER_NOCREATE_TYPE(QValidator); QML_REGISTER_NOCREATE_TYPE(QmlGraphicsVisualModel); QML_REGISTER_NOCREATE_TYPE(QAction); +#ifdef QT_WEBKIT_LIB QML_REGISTER_NOCREATE_TYPE(QmlGraphicsWebSettings); +#endif } diff --git a/src/declarative/graphicsitems/qmlgraphicswebview_p.h b/src/declarative/graphicsitems/qmlgraphicswebview_p.h index c370c59..0aaf895 100644 --- a/src/declarative/graphicsitems/qmlgraphicswebview_p.h +++ b/src/declarative/graphicsitems/qmlgraphicswebview_p.h @@ -275,7 +275,6 @@ QT_END_NAMESPACE QML_DECLARE_TYPE(QmlGraphicsWebView) QML_DECLARE_TYPEINFO(QmlGraphicsWebView, QML_HAS_ATTACHED_PROPERTIES) -QML_DECLARE_TYPE(QAction) QT_END_HEADER -- cgit v0.12 From e55cb23edff635061ec9537c7589b900cc65a83c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 15 Feb 2010 14:07:02 +1000 Subject: Make tests compile without webkit --- tests/auto/declarative/declarative.pro | 5 ++++- tests/auto/declarative/qmlengine/qmlengine.pro | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 8773026..c0e807e 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -35,7 +35,6 @@ SUBDIRS += \ qmlgraphicstext \ # Cover qmlgraphicstextedit \ # Cover qmlgraphicstextinput \ # Cover - qmlgraphicswebview \ # Cover qmlinfo \ # Cover qmlinstruction \ # Cover qmllanguage \ # Cover @@ -59,6 +58,10 @@ SUBDIRS += \ qmlxmlhttprequest \ # Cover sql # Cover +contains(QT_CONFIG, webkit) { + SUBDIRS += \ + qmlgraphicswebview # Cover +} # Tests which should run in Pulse PULSE_TESTS = $$SUBDIRS diff --git a/tests/auto/declarative/qmlengine/qmlengine.pro b/tests/auto/declarative/qmlengine/qmlengine.pro index 21d55a4..1a0e5f4 100644 --- a/tests/auto/declarative/qmlengine/qmlengine.pro +++ b/tests/auto/declarative/qmlengine/qmlengine.pro @@ -1,5 +1,5 @@ load(qttest_p4) -contains(QT_CONFIG,declarative): QT += declarative webkit network +contains(QT_CONFIG,declarative): QT += declarative network macx:CONFIG -= app_bundle SOURCES += tst_qmlengine.cpp -- cgit v0.12 From 1caff7f6909aa69f280d7ba89aeaad15e80563d8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 15 Feb 2010 14:15:49 +1000 Subject: Make tst_qmlmetatype stable --- tests/auto/declarative/qmlmetatype/tst_qmlmetatype.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/auto/declarative/qmlmetatype/tst_qmlmetatype.cpp b/tests/auto/declarative/qmlmetatype/tst_qmlmetatype.cpp index ccb8f30..c336226 100644 --- a/tests/auto/declarative/qmlmetatype/tst_qmlmetatype.cpp +++ b/tests/auto/declarative/qmlmetatype/tst_qmlmetatype.cpp @@ -157,9 +157,12 @@ void tst_qmlmetatype::copy() QT_COPY_TEST(QStringList, QStringList() << "QML" << "Rocks"); QT_COPY_TEST(QByteArray, QByteArray("0x1102DDD")); QT_COPY_TEST(QBitArray, QBitArray(102, true)); - QT_COPY_TEST(QDate, QDate::currentDate()); - QT_COPY_TEST(QTime, QTime::currentTime()); - QT_COPY_TEST(QDateTime, QDateTime::currentDateTime()); + QDate cd = QDate::currentDate(); + QT_COPY_TEST(QDate, cd); + QTime ct = QTime::currentTime(); + QT_COPY_TEST(QTime, ct); + QDateTime cdt = QDateTime::currentDateTime(); + QT_COPY_TEST(QDateTime, cdt); QT_COPY_TEST(QUrl, QUrl("http://www.nokia.com")); QT_COPY_TEST(QLocale, QLocale(QLocale::English, QLocale::Australia)); QT_COPY_TEST(QRect, QRect(-10, 10, 102, 99)); -- cgit v0.12 From 070208528ca9a532a926d7b38abf4b5df576c0d5 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 15 Feb 2010 14:27:49 +1000 Subject: Make tst_qmlecmascript::dynamicDestruction stable --- tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index e5472bb..4edca69 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include @@ -835,9 +835,9 @@ void tst_qmlecmascript::dynamicCreation() void tst_qmlecmascript::dynamicDestruction() { QmlComponent component(&engine, TEST_FILE("dynamicDeletion.qml")); - QGuard object = qobject_cast(component.create()); + QmlGuard object = qobject_cast(component.create()); QVERIFY(object != 0); - QGuard createdQmlObject = 0; + QmlGuard createdQmlObject = 0; QMetaObject::invokeMethod(object, "create"); createdQmlObject = object->objectProperty(); @@ -846,10 +846,9 @@ void tst_qmlecmascript::dynamicDestruction() QMetaObject::invokeMethod(object, "killOther"); QVERIFY(createdQmlObject); - QTest::qWait(0); QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion); QVERIFY(createdQmlObject); - for (int ii = 0; createdQmlObject && ii < 10; ++ii) { + for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up if (createdQmlObject) { QTest::qWait(100); QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion); -- cgit v0.12 From e1ffe40b36a69ba1b1e3bcd3619e5dc2a2fbe8ba Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Mon, 15 Feb 2010 14:31:33 +1000 Subject: Update as test running qmakery changes. --- tests/auto/declarative/runall.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/auto/declarative/runall.sh b/tests/auto/declarative/runall.sh index 33087a1..d9eddf9 100755 --- a/tests/auto/declarative/runall.sh +++ b/tests/auto/declarative/runall.sh @@ -5,13 +5,19 @@ sleep 1 trap "kill $!" EXIT export DISPLAY=:7 -make -k -j1 install 2>&1 | +( make -k -j1 install 2>&1; + for exe in $(make install | sed -n 's/^install .* "\([^"]*qt4\/tst_[^"]*\)".*/\1/p') + do + $exe + done +) | while read line do case "$line" in make*Error) echo "$line";; make*Stop) echo "$line";; make*) ;; + install*) ;; */qmake*) ;; */bin/moc*) ;; *targ.debug*) ;; -- cgit v0.12 From 24c116deb1459b2f20aa724e092c0232e9902461 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 16:21:48 +1000 Subject: Add missing QT_MODULE to header. --- src/multimedia/base/qgraphicsvideoitem.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/multimedia/base/qgraphicsvideoitem.h b/src/multimedia/base/qgraphicsvideoitem.h index 06f471f..c339606 100644 --- a/src/multimedia/base/qgraphicsvideoitem.h +++ b/src/multimedia/base/qgraphicsvideoitem.h @@ -51,6 +51,8 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +QT_MODULE(Multimedia) + class QVideoSurfaceFormat; class QGraphicsVideoItemPrivate; -- cgit v0.12 From 1679980392e9784bf0c0d321d541aee6efeaba15 Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 16:25:06 +1000 Subject: Express dependencies for QtMultimedia. --- src/src.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/src.pro b/src/src.pro index f2070ae..2b9dc30 100644 --- a/src/src.pro +++ b/src/src.pro @@ -19,7 +19,6 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, o contains(QT_CONFIG, openvg): SRC_SUBDIRS += src_openvg contains(QT_CONFIG, xmlpatterns): SRC_SUBDIRS += src_xmlpatterns contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon -contains(QT_CONFIG, multimedia): SRC_SUBDIRS += src_multimedia contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg contains(QT_CONFIG, webkit) { #exists($$QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.pro): SRC_SUBDIRS += src_javascriptcore @@ -28,6 +27,7 @@ contains(QT_CONFIG, webkit) { contains(QT_CONFIG, script): SRC_SUBDIRS += src_script contains(QT_CONFIG, scripttools): SRC_SUBDIRS += src_scripttools contains(QT_CONFIG, declarative): SRC_SUBDIRS += src_declarative +contains(QT_CONFIG, multimedia): SRC_SUBDIRS += src_multimedia SRC_SUBDIRS += src_plugins src_s60main.subdir = $$QT_SOURCE_TREE/src/s60main @@ -102,7 +102,7 @@ src_declarative.target = sub-declarative src_multimedia.depends = src_gui src_tools_activeqt.depends = src_tools_idc src_gui src_declarative.depends = src_xml src_gui src_script src_network src_svg - src_plugins.depends = src_gui src_sql src_svg + src_plugins.depends = src_gui src_sql src_svg src_multimedia contains(QT_CONFIG, webkit) { src_webkit.depends = src_gui src_sql src_network src_xml contains(QT_CONFIG, phonon):src_webkit.depends += src_phonon @@ -116,6 +116,7 @@ src_declarative.target = sub-declarative src_phonon.depends += src_dbus } contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): src_plugins.depends += src_opengl + contains(QT_CONFIG, declarative): src_multimedia.depends += src_declarative } !symbian { -- cgit v0.12 From e486ec3b4730d470033a0a88b1cc56bc98d8d00e Mon Sep 17 00:00:00 2001 From: Justin McPherson Date: Mon, 15 Feb 2010 16:27:42 +1000 Subject: Revert "Added Q_WS_MAEMO_5 to mkspec file." Defined elsewhere. This reverts commit abf04def344aeb14dbb8539ba73fb5de26237bcc. --- mkspecs/linux-g++-maemo/qmake.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/mkspecs/linux-g++-maemo/qmake.conf b/mkspecs/linux-g++-maemo/qmake.conf index e586ed0..38c26a6 100644 --- a/mkspecs/linux-g++-maemo/qmake.conf +++ b/mkspecs/linux-g++-maemo/qmake.conf @@ -32,6 +32,4 @@ DEFINES += QT_GL_NO_SCISSOR_TEST # Work round SGX 1.4 driver bug (text corrupted), modify glyph cache width: DEFINES += QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH=1024 -DEFINES += Q_WS_MAEMO_5 - load(qt_config) -- cgit v0.12 From 988c69de1a16080bf9646f9698ff62cc5541e0b8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 15 Feb 2010 16:36:25 +1000 Subject: Make tst_xmlhttprequest more reliable --- tests/auto/declarative/qmlxmlhttprequest/data/abort.reply | 1 + .../qmlxmlhttprequest/data/getResponseHeader.reply | 1 + .../declarative/qmlxmlhttprequest/data/open_network.reply | 1 + tests/auto/declarative/qmlxmlhttprequest/data/send_data.reply | 1 + .../declarative/qmlxmlhttprequest/data/send_ignoreData.reply | 1 + .../declarative/qmlxmlhttprequest/data/setRequestHeader.reply | 1 + .../qmlxmlhttprequest/data/setRequestHeader_illegalName.qml | 1 + .../auto/declarative/qmlxmlhttprequest/data/status.200.reply | 1 + .../auto/declarative/qmlxmlhttprequest/data/status.404.reply | 1 + tests/auto/declarative/shared/testhttpserver.cpp | 11 ++++++----- 10 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/abort.reply b/tests/auto/declarative/qmlxmlhttprequest/data/abort.reply index 35b11f4..7ae6951 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/abort.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/abort.reply @@ -1,2 +1,3 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/getResponseHeader.reply b/tests/auto/declarative/qmlxmlhttprequest/data/getResponseHeader.reply index 62ec67b..c4b4bb2 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/getResponseHeader.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/getResponseHeader.reply @@ -1,4 +1,5 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 Test-Header: TestValue MultiTest-Header: TestValue diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/open_network.reply b/tests/auto/declarative/qmlxmlhttprequest/data/open_network.reply index 35b11f4..7ae6951 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/open_network.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/open_network.reply @@ -1,2 +1,3 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/send_data.reply b/tests/auto/declarative/qmlxmlhttprequest/data/send_data.reply index 35b11f4..7ae6951 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/send_data.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/send_data.reply @@ -1,2 +1,3 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/send_ignoreData.reply b/tests/auto/declarative/qmlxmlhttprequest/data/send_ignoreData.reply index 35b11f4..7ae6951 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/send_ignoreData.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/send_ignoreData.reply @@ -1,2 +1,3 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader.reply b/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader.reply index 35b11f4..7ae6951 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader.reply @@ -1,2 +1,3 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader_illegalName.qml b/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader_illegalName.qml index bf31eca..e9535d5 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader_illegalName.qml +++ b/tests/auto/declarative/qmlxmlhttprequest/data/setRequestHeader_illegalName.qml @@ -46,6 +46,7 @@ QtObject { x.onreadystatechange = function() { if (x.readyState == XMLHttpRequest.DONE) { dataOK = (x.responseText == "QML Rocks!\n"); + print("DATA:" + x.responseText); } } diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/status.200.reply b/tests/auto/declarative/qmlxmlhttprequest/data/status.200.reply index 35b11f4..7ae6951 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/status.200.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/status.200.reply @@ -1,2 +1,3 @@ HTTP/1.0 200 OK +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/qmlxmlhttprequest/data/status.404.reply b/tests/auto/declarative/qmlxmlhttprequest/data/status.404.reply index 964a7a8..2e29f56 100644 --- a/tests/auto/declarative/qmlxmlhttprequest/data/status.404.reply +++ b/tests/auto/declarative/qmlxmlhttprequest/data/status.404.reply @@ -1,2 +1,3 @@ HTTP/1.0 404 Document not found +Connection: close Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/declarative/shared/testhttpserver.cpp b/tests/auto/declarative/shared/testhttpserver.cpp index 490fc95..5740925 100644 --- a/tests/auto/declarative/shared/testhttpserver.cpp +++ b/tests/auto/declarative/shared/testhttpserver.cpp @@ -190,13 +190,14 @@ void TestHTTPServer::disconnected() --ii; } } + socket->disconnect(); socket->deleteLater(); } void TestHTTPServer::readyRead() { QTcpSocket *socket = qobject_cast(sender()); - if (!socket) return; + if (!socket || socket->state() == QTcpSocket::ClosingState) return; QByteArray ba = socket->readAll(); @@ -222,14 +223,14 @@ void TestHTTPServer::readyRead() QByteArray data = ba.mid(ii); qWarning() << "TestHTTPServer: Unexpected data" << data << "\nExpected: " << waitData; m_hasFailed = true; - socket->disconnect(); + socket->disconnectFromHost(); return; } } if (waitData.isEmpty()) { socket->write(replyData); - socket->disconnect(); + socket->disconnectFromHost(); } } @@ -316,8 +317,8 @@ void TestHTTPServer::serveGET(QTcpSocket *socket, const QByteArray &data) } dataCache.remove(socket); - if (close) - socket->close(); + if (close) + socket->disconnectFromHost(); } } -- cgit v0.12 From af36be2c7257870e1ad094ec7b2cc37ae4ca2176 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Mon, 15 Feb 2010 17:22:29 +1000 Subject: For qmldebug* tests, make sure engine is running before the test thread is started. Also fix some memory leaks. --- src/declarative/debugger/qmldebugservice.cpp | 33 ++++++++++++++++++ src/declarative/debugger/qmldebugservice_p.h | 4 ++- tests/auto/declarative/qmldebug/tst_qmldebug.cpp | 40 +++++++++++++--------- .../qmldebugservice/tst_qmldebugservice.cpp | 1 + tests/auto/declarative/shared/debugutil.cpp | 21 +++++++----- tests/auto/declarative/shared/debugutil_p.h | 25 ++++++++------ 6 files changed, 88 insertions(+), 36 deletions(-) diff --git a/src/declarative/debugger/qmldebugservice.cpp b/src/declarative/debugger/qmldebugservice.cpp index 810fbed..2c9586f 100644 --- a/src/declarative/debugger/qmldebugservice.cpp +++ b/src/declarative/debugger/qmldebugservice.cpp @@ -61,9 +61,11 @@ class QmlDebugServer : public QObject public: static QmlDebugServer *instance(); void wait(); + void registerForStartNotification(QObject *object, const char *receiver); private Q_SLOTS: void readyRead(); + void registeredObjectDestroyed(QObject *object); private: friend class QmlDebugService; @@ -83,6 +85,7 @@ public: QPacketProtocol *protocol; QHash plugins; QStringList enabledPlugins; + QList > notifyClients; }; class QmlDebugServicePrivate : public QObjectPrivate @@ -112,6 +115,14 @@ void QmlDebugServerPrivate::wait() qWarning("QmlDebugServer: Waiting for connection on port %d...", port); + for (int i=0; iwait(); } +void QmlDebugServer::registerForStartNotification(QObject *object, const char *methodName) +{ + Q_D(QmlDebugServer); + connect(object, SIGNAL(destroyed(QObject*)), SLOT(registeredObjectDestroyed(QObject*))); + d->notifyClients.append(qMakePair(object, QByteArray(methodName))); +} + +void QmlDebugServer::registeredObjectDestroyed(QObject *object) +{ + Q_D(QmlDebugServer); + QMutableListIterator > i(d->notifyClients); + while (i.hasNext()) { + if (i.next().first == object) + i.remove(); + } +} + QmlDebugServer::QmlDebugServer(int port) : QObject(*(new QmlDebugServerPrivate)) { @@ -367,6 +395,11 @@ void QmlDebugService::waitForClients() QmlDebugServer::instance()->wait(); } +void QmlDebugService::notifyOnServerStart(QObject *object, const char *receiver) +{ + QmlDebugServer::instance()->registerForStartNotification(object, receiver); +} + void QmlDebugService::sendMessage(const QByteArray &message) { Q_D(QmlDebugService); diff --git a/src/declarative/debugger/qmldebugservice_p.h b/src/declarative/debugger/qmldebugservice_p.h index b406a3c..ec90d95 100644 --- a/src/declarative/debugger/qmldebugservice_p.h +++ b/src/declarative/debugger/qmldebugservice_p.h @@ -68,17 +68,19 @@ public: static int idForObject(QObject *); static QObject *objectForId(int); - static bool isDebuggingEnabled(); static QString objectToString(QObject *obj); static void waitForClients(); + static void notifyOnServerStart(QObject *object, const char *receiver); + protected: virtual void enabledChanged(bool); virtual void messageReceived(const QByteArray &); private: + void registerForStartNotification(QObject *object, const char *methodName); friend class QmlDebugServer; }; diff --git a/tests/auto/declarative/qmldebug/tst_qmldebug.cpp b/tests/auto/declarative/qmldebug/tst_qmldebug.cpp index 82e74ce..a51fd29 100644 --- a/tests/auto/declarative/qmldebug/tst_qmldebug.cpp +++ b/tests/auto/declarative/qmldebug/tst_qmldebug.cpp @@ -288,10 +288,11 @@ void tst_QmlDebug::watch_property() QmlDebugPropertyWatch *watch; - QmlEngineDebug unconnected(0); - watch = unconnected.addWatch(prop, this); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + watch = unconnected->addWatch(prop, this); QCOMPARE(watch->state(), QmlDebugWatch::Dead); delete watch; + delete unconnected; watch = m_dbg->addWatch(QmlDebugPropertyReference(), this); QVERIFY(QmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QmlDebugWatch::State)))); @@ -346,10 +347,11 @@ void tst_QmlDebug::watch_object() QmlDebugWatch *watch; - QmlEngineDebug unconnected(0); - watch = unconnected.addWatch(obj, this); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + watch = unconnected->addWatch(obj, this); QCOMPARE(watch->state(), QmlDebugWatch::Dead); delete watch; + delete unconnected; watch = m_dbg->addWatch(QmlDebugObjectReference(), this); QVERIFY(QmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QmlDebugWatch::State)))); @@ -409,10 +411,11 @@ void tst_QmlDebug::watch_expression() QmlDebugObjectExpressionWatch *watch; - QmlEngineDebug unconnected(0); - watch = unconnected.addWatch(obj, expr, this); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + watch = unconnected->addWatch(obj, expr, this); QCOMPARE(watch->state(), QmlDebugWatch::Dead); delete watch; + delete unconnected; watch = m_dbg->addWatch(QmlDebugObjectReference(), expr, this); QVERIFY(QmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QmlDebugWatch::State)))); @@ -487,10 +490,11 @@ void tst_QmlDebug::queryAvailableEngines() { QmlDebugEnginesQuery *q_engines; - QmlEngineDebug unconnected(0); - q_engines = unconnected.queryAvailableEngines(0); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + q_engines = unconnected->queryAvailableEngines(0); QCOMPARE(q_engines->state(), QmlDebugQuery::Error); delete q_engines; + delete unconnected; q_engines = m_dbg->queryAvailableEngines(this); delete q_engines; @@ -519,10 +523,11 @@ void tst_QmlDebug::queryRootContexts() QmlDebugRootContextQuery *q_context; - QmlEngineDebug unconnected(0); - q_context = unconnected.queryRootContexts(engineId, this); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + q_context = unconnected->queryRootContexts(engineId, this); QCOMPARE(q_context->state(), QmlDebugQuery::Error); delete q_context; + delete unconnected; q_context = m_dbg->queryRootContexts(engineId, this); delete q_context; @@ -563,10 +568,11 @@ void tst_QmlDebug::queryObject() QmlDebugObjectQuery *q_obj = 0; - QmlEngineDebug unconnected(0); - q_obj = recursive ? unconnected.queryObjectRecursive(rootObject, this) : unconnected.queryObject(rootObject, this); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + q_obj = recursive ? unconnected->queryObjectRecursive(rootObject, this) : unconnected->queryObject(rootObject, this); QCOMPARE(q_obj->state(), QmlDebugQuery::Error); delete q_obj; + delete unconnected; q_obj = recursive ? m_dbg->queryObjectRecursive(rootObject, this) : m_dbg->queryObject(rootObject, this); delete q_obj; @@ -637,10 +643,11 @@ void tst_QmlDebug::queryExpressionResult() QmlDebugExpressionQuery *q_expr; - QmlEngineDebug unconnected(0); - q_expr = unconnected.queryExpressionResult(objectId, expr, this); + QmlEngineDebug *unconnected = new QmlEngineDebug(0); + q_expr = unconnected->queryExpressionResult(objectId, expr, this); QCOMPARE(q_expr->state(), QmlDebugQuery::Error); delete q_expr; + delete unconnected; q_expr = m_dbg->queryExpressionResult(objectId, expr, this); delete q_expr; @@ -801,9 +808,10 @@ class tst_QmlDebug_Factory : public QmlTestFactory public: QObject *createTest(QmlDebugTestData *data) { - QmlContext *c = new QmlContext(data->engine->rootContext()); + tst_QmlDebug *test = new tst_QmlDebug(data); + QmlContext *c = new QmlContext(data->engine->rootContext(), test); c->setObjectName("tst_QmlDebug_childContext"); - return new tst_QmlDebug(data); + return test; } }; diff --git a/tests/auto/declarative/qmldebugservice/tst_qmldebugservice.cpp b/tests/auto/declarative/qmldebugservice/tst_qmldebugservice.cpp index 4e7bc27..9abc5a5 100644 --- a/tests/auto/declarative/qmldebugservice/tst_qmldebugservice.cpp +++ b/tests/auto/declarative/qmldebugservice/tst_qmldebugservice.cpp @@ -167,6 +167,7 @@ void tst_QmlDebugService::objectToString() obj->setObjectName("Hello"); QCOMPARE(QmlDebugService::objectToString(obj), QString("QObject: Hello")); + delete obj; } diff --git a/tests/auto/declarative/shared/debugutil.cpp b/tests/auto/declarative/shared/debugutil.cpp index aa0cd31..0010508 100644 --- a/tests/auto/declarative/shared/debugutil.cpp +++ b/tests/auto/declarative/shared/debugutil.cpp @@ -47,6 +47,8 @@ #include "debugutil_p.h" +#include + bool QmlDebugTest::waitForSignal(QObject *receiver, const char *member, int timeout) { QEventLoop loop; QTimer timer; @@ -117,21 +119,22 @@ void QmlDebugTestClient::messageReceived(const QByteArray &ba) tst_QmlDebug_Thread::tst_QmlDebug_Thread(QmlDebugTestData *data, QmlTestFactory *factory) - : m_ready(false), m_data(data), m_factory(factory) + : m_data(data), m_factory(factory) { } void tst_QmlDebug_Thread::run() { - QTest::qWait(1000); + bool ok = false; QmlDebugConnection conn; conn.connectToHost("127.0.0.1", 3768); - bool ok = conn.waitForConnected(5000); + ok = conn.waitForConnected(); Q_ASSERT(ok); - while (!m_ready) - QTest::qWait(100); + QEventLoop loop; + connect(m_data, SIGNAL(engineCreated()), &loop, SLOT(quit())); + loop.exec(); m_data->conn = &conn; @@ -139,10 +142,10 @@ void tst_QmlDebug_Thread::run() QObject *test = m_factory->createTest(m_data); Q_ASSERT(test); int code = QTest::qExec(test, QCoreApplication::arguments()); + delete test; emit testsFinished(code); } - int QmlDebugTest::runTests(QmlTestFactory *factory, const QList &qml) { qputenv("QML_DEBUG_SERVER_PORT", "3768"); @@ -152,7 +155,8 @@ int QmlDebugTest::runTests(QmlTestFactory *factory, const QList &qml tst_QmlDebug_Thread thread(&data, factory); QObject::connect(&thread, SIGNAL(testsFinished(int)), &data, SLOT(testsFinished(int))); - thread.start(); + + QmlDebugService::notifyOnServerStart(&thread, "start"); QmlEngine engine; // blocks until client connects @@ -165,7 +169,7 @@ int QmlDebugTest::runTests(QmlTestFactory *factory, const QList &qml // start the test data.engine = &engine; - thread.m_ready = true; + emit data.engineCreated(); loop.exec(); thread.wait(); @@ -173,4 +177,3 @@ int QmlDebugTest::runTests(QmlTestFactory *factory, const QList &qml return data.exitCode; } - diff --git a/tests/auto/declarative/shared/debugutil_p.h b/tests/auto/declarative/shared/debugutil_p.h index 313d16c..6f23899 100644 --- a/tests/auto/declarative/shared/debugutil_p.h +++ b/tests/auto/declarative/shared/debugutil_p.h @@ -51,6 +51,15 @@ #include #include +class QmlTestFactory; + +class QmlDebugTest +{ +public: + static bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000); + + static int runTests(QmlTestFactory *factory, const QList &qml = QList()); +}; class QmlDebugTestData : public QObject { @@ -68,8 +77,14 @@ public: QList items; +signals: + void engineCreated(); + public slots: void testsFinished(int code); + +private: + friend class QmlDebugTest; }; @@ -82,14 +97,6 @@ public: virtual QObject *createTest(QmlDebugTestData *data) = 0; }; - -namespace QmlDebugTest { - - bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000); - - int runTests(QmlTestFactory *factory, const QList &qml = QList()); -} - class QmlDebugTestService : public QmlDebugService { Q_OBJECT @@ -132,8 +139,6 @@ public: void run(); - bool m_ready; - signals: void testsFinished(int); -- cgit v0.12 From fa6dc19b9212706532f3f88da0fb3542e9c3eafe Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 15 Feb 2010 09:23:27 +0100 Subject: Enhance samegame high score dialog 'Better' layout mechanics, included animated resize for those people with long names. --- demos/declarative/samegame/content/Dialog.qml | 1 + demos/declarative/samegame/content/samegame.js | 4 ++++ demos/declarative/samegame/samegame.qml | 16 +++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/demos/declarative/samegame/content/Dialog.qml b/demos/declarative/samegame/content/Dialog.qml index f9a281a..5bd1123 100644 --- a/demos/declarative/samegame/content/Dialog.qml +++ b/demos/declarative/samegame/content/Dialog.qml @@ -11,6 +11,7 @@ Rectangle { page.opacity = 1; } signal closed(); + property Item text: myText color: "white"; border.width: 1; width: myText.width + 20; height: myText.height + 40; opacity: 0 opacity: Behavior { diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index 0a42e88..41ed84c 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -158,7 +158,11 @@ function victoryCheck() //Checks for game over if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))){ timer = new Date() - timer; + //scoreName.show("You won! Please enter your name: "); scoreName.show("You won! Please enter your name: "); + scoreName.initialWidth = scoreName.text.width + 20; + scoreName.width = scoreName.initialWidth; + scoreName.text.opacity = 0;//Just a spacer //dialog.show("Game Over. Your score is " + gameCanvas.score); } } diff --git a/demos/declarative/samegame/samegame.qml b/demos/declarative/samegame/samegame.qml index 626c76b..c2557ae 100644 --- a/demos/declarative/samegame/samegame.qml +++ b/demos/declarative/samegame/samegame.qml @@ -38,20 +38,30 @@ Rectangle { Dialog { id: dialog; anchors.centerIn: parent; z: 21 } Dialog { id: scoreName; anchors.centerIn: parent; z: 22; + property int initialWidth: 0 + width: Behavior{NumberAnimation{} enabled: initialWidth!=0} Text { id: spacer - opacity: 0 - text: " You won! Please enter your name:" + anchors.left: scoreName.left + anchors.leftMargin: 20 + anchors.verticalCenter: parent.verticalCenter + text: "You won! Please enter your name: " } TextInput { id: editor + onTextChanged: { + var newWidth = editor.width + spacer.width + 40; + if((newWidth > scoreName.width && newWidth < screen.width) + || (scoreName.width > scoreName.initialWidth)) + scoreName.width = newWidth; + } onAccepted: { if(scoreName.opacity==1&&editor.text!="") saveHighScore(editor.text); scoreName.forceClose(); } anchors.verticalCenter: parent.verticalCenter - width: 72; focus: true + focus: true anchors.left: spacer.right } } -- cgit v0.12 From 77715148d635c31d7042140c93013a1af77f2967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Mon, 15 Feb 2010 11:00:56 +0100 Subject: Replaced the numCopies()/setNumCopies() and actualNumCopies() API. Obsoleted the numCopies()/setNumCopies()/actualNumCopies() with copyCount()/setCopyCount() and supportsMultipleCopies(). The old numCopies() was confusing since it returned the number of times a job had to be printed to get the copies you wanted. Now copyCount() and setCopyCount() are symmetric, and always returns the number of copies the user want to print. Task-number: QTBUG-5605 Reviewed-by: Kim --- src/gui/dialogs/qprintdialog_qws.cpp | 6 +-- src/gui/dialogs/qprintdialog_unix.cpp | 6 +-- src/gui/painting/qpdf.cpp | 12 +++++ src/gui/painting/qpdf_p.h | 2 - src/gui/painting/qprintengine.h | 2 + src/gui/painting/qprintengine_mac.mm | 10 ++++ src/gui/painting/qprintengine_qws.cpp | 5 ++ src/gui/painting/qprintengine_win.cpp | 9 ++++ src/gui/painting/qprintengine_win_p.h | 1 - src/gui/painting/qprinter.cpp | 99 +++++++++++++++++++++++++---------- src/gui/painting/qprinter.h | 4 ++ src/gui/text/qtextdocument.cpp | 4 +- tests/auto/qprinter/tst_qprinter.cpp | 10 ++-- 13 files changed, 125 insertions(+), 45 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/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..4a96d44 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: { + uint copies = 1; + PMGetCopies(d->settings, &copies); + ret = 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(engine); - numCopies = base->d_func()->copies; - } -#ifdef Q_WS_WIN - else if (engine->type() == QPaintEngine::Windows) { - QWin32PrintEngine *base = static_cast(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 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/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 80931c9..44e6ba5 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -1767,9 +1767,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/tests/auto/qprinter/tst_qprinter.cpp b/tests/auto/qprinter/tst_qprinter.cpp index b1ff425..7e8ce84 100644 --- a/tests/auto/qprinter/tst_qprinter.cpp +++ b/tests/auto/qprinter/tst_qprinter.cpp @@ -106,7 +106,7 @@ private slots: void testCustomPageSizes(); void printDialogCompleter(); - void testActualNumCopies(); + void testCopyCount(); void taskQTBUG4497_reusePrinterOnDifferentFiles(); @@ -455,7 +455,7 @@ void tst_QPrinter::testNonExistentPrinter() printer.pageSize(); printer.orientation(); printer.fullPage(); - printer.setNumCopies(1); + printer.setCopyCount(1); printer.printerName(); // nor metrics @@ -966,11 +966,11 @@ void tst_QPrinter::printDialogCompleter() #endif } -void tst_QPrinter::testActualNumCopies() +void tst_QPrinter::testCopyCount() { QPrinter p; - p.setNumCopies(15); - QCOMPARE(p.actualNumCopies(), 15); + p.setCopyCount(15); + QCOMPARE(p.copyCount(), 15); } static void printPage(QPainter *painter) -- cgit v0.12 From 815911cc85883f621874d3c11714e80dc352ee29 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 4 Feb 2010 16:04:14 +0100 Subject: Fixes a behaviour for QDockWidget used without QMainWindow There was a behaviour change. Even though using QDockWidget without QMainWindow is not supported, it broke applications. --- src/gui/widgets/qdockwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(q->parentWidget()->layout()); - if (!mwlayout || mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea) + if (mwlayout && mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea) return; // this dockwidget can't be redocked } -- cgit v0.12 From c9a13228d61de352edfb0019121bc83160d3b79f Mon Sep 17 00:00:00 2001 From: aavit Date: Mon, 15 Feb 2010 13:07:12 +0100 Subject: Delete libpng 1.2.40 --- src/3rdparty/libpng/ANNOUNCE | 57 - src/3rdparty/libpng/CHANGES | 2479 ----------- src/3rdparty/libpng/INSTALL | 199 - src/3rdparty/libpng/KNOWNBUG | 22 - src/3rdparty/libpng/LICENSE | 111 - src/3rdparty/libpng/README | 267 -- src/3rdparty/libpng/TODO | 25 - src/3rdparty/libpng/Y2KINFO | 55 - src/3rdparty/libpng/configure | 13 - src/3rdparty/libpng/example.c | 835 ---- src/3rdparty/libpng/libpng-1.2.40.txt | 3112 -------------- src/3rdparty/libpng/libpng.3 | 4349 ------------------- src/3rdparty/libpng/libpngpf.3 | 790 ---- src/3rdparty/libpng/png.5 | 74 - src/3rdparty/libpng/png.c | 926 ----- src/3rdparty/libpng/png.h | 3726 ----------------- src/3rdparty/libpng/pngbar.jpg | Bin 2498 -> 0 bytes src/3rdparty/libpng/pngbar.png | Bin 2399 -> 0 bytes src/3rdparty/libpng/pngconf.h | 1518 ------- src/3rdparty/libpng/pngerror.c | 364 -- src/3rdparty/libpng/pnggccrd.c | 103 - src/3rdparty/libpng/pngget.c | 943 ----- src/3rdparty/libpng/pngmem.c | 620 --- src/3rdparty/libpng/pngnow.png | Bin 2069 -> 0 bytes src/3rdparty/libpng/pngpread.c | 1727 -------- src/3rdparty/libpng/pngread.c | 1473 ------- src/3rdparty/libpng/pngrio.c | 177 - src/3rdparty/libpng/pngrtran.c | 4381 -------------------- src/3rdparty/libpng/pngrutil.c | 3252 --------------- src/3rdparty/libpng/pngset.c | 1285 ------ src/3rdparty/libpng/pngtest.c | 1692 -------- src/3rdparty/libpng/pngtest.png | Bin 8574 -> 0 bytes src/3rdparty/libpng/pngtrans.c | 677 --- src/3rdparty/libpng/pngvcrd.c | 1 - src/3rdparty/libpng/pngwio.c | 259 -- src/3rdparty/libpng/pngwrite.c | 1561 ------- src/3rdparty/libpng/pngwtran.c | 575 --- src/3rdparty/libpng/pngwutil.c | 2825 ------------- src/3rdparty/libpng/projects/beos/x86-shared.proj | Bin 17031 -> 0 bytes src/3rdparty/libpng/projects/beos/x86-shared.txt | 22 - src/3rdparty/libpng/projects/beos/x86-static.proj | Bin 16706 -> 0 bytes src/3rdparty/libpng/projects/beos/x86-static.txt | 22 - src/3rdparty/libpng/projects/cbuilder5/libpng.bpf | 22 - src/3rdparty/libpng/projects/cbuilder5/libpng.bpg | 25 - src/3rdparty/libpng/projects/cbuilder5/libpng.bpr | 157 - src/3rdparty/libpng/projects/cbuilder5/libpng.cpp | 29 - .../libpng/projects/cbuilder5/libpng.readme.txt | 25 - .../libpng/projects/cbuilder5/libpngstat.bpf | 22 - .../libpng/projects/cbuilder5/libpngstat.bpr | 109 - .../libpng/projects/cbuilder5/zlib.readme.txt | 14 - src/3rdparty/libpng/projects/netware.txt | 6 - src/3rdparty/libpng/projects/visualc6/README.txt | 57 - src/3rdparty/libpng/projects/visualc6/libpng.dsp | 472 --- src/3rdparty/libpng/projects/visualc6/libpng.dsw | 59 - src/3rdparty/libpng/projects/visualc6/pngtest.dsp | 314 -- src/3rdparty/libpng/projects/visualc71/PRJ0041.mak | 21 - src/3rdparty/libpng/projects/visualc71/README.txt | 57 - .../libpng/projects/visualc71/README_zlib.txt | 44 - src/3rdparty/libpng/projects/visualc71/libpng.sln | 88 - .../libpng/projects/visualc71/libpng.vcproj | 702 ---- .../libpng/projects/visualc71/pngtest.vcproj | 459 -- src/3rdparty/libpng/projects/visualc71/zlib.vcproj | 670 --- src/3rdparty/libpng/projects/wince.txt | 6 - src/3rdparty/libpng/scripts/CMakeLists.txt | 253 -- src/3rdparty/libpng/scripts/SCOPTIONS.ppc | 7 - src/3rdparty/libpng/scripts/descrip.mms | 52 - src/3rdparty/libpng/scripts/libpng-config-body.in | 96 - src/3rdparty/libpng/scripts/libpng-config-head.in | 24 - src/3rdparty/libpng/scripts/libpng-config.in | 127 - src/3rdparty/libpng/scripts/libpng.icc | 47 - src/3rdparty/libpng/scripts/libpng.pc-configure.in | 11 - src/3rdparty/libpng/scripts/libpng.pc.in | 10 - src/3rdparty/libpng/scripts/makefile.32sunu | 257 -- src/3rdparty/libpng/scripts/makefile.64sunu | 257 -- src/3rdparty/libpng/scripts/makefile.acorn | 50 - src/3rdparty/libpng/scripts/makefile.aix | 116 - src/3rdparty/libpng/scripts/makefile.amiga | 51 - src/3rdparty/libpng/scripts/makefile.atari | 55 - src/3rdparty/libpng/scripts/makefile.bc32 | 145 - src/3rdparty/libpng/scripts/makefile.beos | 230 - src/3rdparty/libpng/scripts/makefile.bor | 156 - src/3rdparty/libpng/scripts/makefile.cygwin | 302 -- src/3rdparty/libpng/scripts/makefile.darwin | 237 -- src/3rdparty/libpng/scripts/makefile.dec | 217 - src/3rdparty/libpng/scripts/makefile.dj2 | 58 - src/3rdparty/libpng/scripts/makefile.elf | 279 -- src/3rdparty/libpng/scripts/makefile.freebsd | 51 - src/3rdparty/libpng/scripts/makefile.gcc | 83 - src/3rdparty/libpng/scripts/makefile.gcmmx | 274 -- src/3rdparty/libpng/scripts/makefile.hp64 | 239 -- src/3rdparty/libpng/scripts/makefile.hpgcc | 248 -- src/3rdparty/libpng/scripts/makefile.hpux | 236 -- src/3rdparty/libpng/scripts/makefile.ibmc | 77 - src/3rdparty/libpng/scripts/makefile.intel | 106 - src/3rdparty/libpng/scripts/makefile.knr | 103 - src/3rdparty/libpng/scripts/makefile.linux | 253 -- src/3rdparty/libpng/scripts/makefile.mingw | 289 -- src/3rdparty/libpng/scripts/makefile.mips | 87 - src/3rdparty/libpng/scripts/makefile.msc | 91 - src/3rdparty/libpng/scripts/makefile.ne12bsd | 49 - src/3rdparty/libpng/scripts/makefile.netbsd | 49 - src/3rdparty/libpng/scripts/makefile.nommx | 255 -- src/3rdparty/libpng/scripts/makefile.openbsd | 76 - src/3rdparty/libpng/scripts/makefile.os2 | 72 - src/3rdparty/libpng/scripts/makefile.sco | 232 -- src/3rdparty/libpng/scripts/makefile.sggcc | 243 -- src/3rdparty/libpng/scripts/makefile.sgi | 248 -- src/3rdparty/libpng/scripts/makefile.so9 | 254 -- src/3rdparty/libpng/scripts/makefile.solaris | 251 -- src/3rdparty/libpng/scripts/makefile.solaris-x86 | 251 -- src/3rdparty/libpng/scripts/makefile.std | 95 - src/3rdparty/libpng/scripts/makefile.sunos | 100 - src/3rdparty/libpng/scripts/makefile.tc3 | 89 - src/3rdparty/libpng/scripts/makefile.vcawin32 | 104 - src/3rdparty/libpng/scripts/makefile.vcwin32 | 104 - src/3rdparty/libpng/scripts/makefile.watcom | 112 - src/3rdparty/libpng/scripts/makevms.com | 142 - src/3rdparty/libpng/scripts/pngos2.def | 257 -- src/3rdparty/libpng/scripts/pngw32.def | 239 -- src/3rdparty/libpng/scripts/pngw32.rc | 112 - src/3rdparty/libpng/scripts/smakefile.ppc | 33 - 121 files changed, 52416 deletions(-) delete mode 100644 src/3rdparty/libpng/ANNOUNCE delete mode 100644 src/3rdparty/libpng/CHANGES delete mode 100644 src/3rdparty/libpng/INSTALL delete mode 100644 src/3rdparty/libpng/KNOWNBUG delete mode 100644 src/3rdparty/libpng/LICENSE delete mode 100644 src/3rdparty/libpng/README delete mode 100644 src/3rdparty/libpng/TODO delete mode 100644 src/3rdparty/libpng/Y2KINFO delete mode 100755 src/3rdparty/libpng/configure delete mode 100644 src/3rdparty/libpng/example.c delete mode 100644 src/3rdparty/libpng/libpng-1.2.40.txt delete mode 100644 src/3rdparty/libpng/libpng.3 delete mode 100644 src/3rdparty/libpng/libpngpf.3 delete mode 100644 src/3rdparty/libpng/png.5 delete mode 100644 src/3rdparty/libpng/png.c delete mode 100644 src/3rdparty/libpng/png.h delete mode 100644 src/3rdparty/libpng/pngbar.jpg delete mode 100644 src/3rdparty/libpng/pngbar.png delete mode 100644 src/3rdparty/libpng/pngconf.h delete mode 100644 src/3rdparty/libpng/pngerror.c delete mode 100644 src/3rdparty/libpng/pnggccrd.c delete mode 100644 src/3rdparty/libpng/pngget.c delete mode 100644 src/3rdparty/libpng/pngmem.c delete mode 100644 src/3rdparty/libpng/pngnow.png delete mode 100644 src/3rdparty/libpng/pngpread.c delete mode 100644 src/3rdparty/libpng/pngread.c delete mode 100644 src/3rdparty/libpng/pngrio.c delete mode 100644 src/3rdparty/libpng/pngrtran.c delete mode 100644 src/3rdparty/libpng/pngrutil.c delete mode 100644 src/3rdparty/libpng/pngset.c delete mode 100644 src/3rdparty/libpng/pngtest.c delete mode 100644 src/3rdparty/libpng/pngtest.png delete mode 100644 src/3rdparty/libpng/pngtrans.c delete mode 100644 src/3rdparty/libpng/pngvcrd.c delete mode 100644 src/3rdparty/libpng/pngwio.c delete mode 100644 src/3rdparty/libpng/pngwrite.c delete mode 100644 src/3rdparty/libpng/pngwtran.c delete mode 100644 src/3rdparty/libpng/pngwutil.c delete mode 100644 src/3rdparty/libpng/projects/beos/x86-shared.proj delete mode 100644 src/3rdparty/libpng/projects/beos/x86-shared.txt delete mode 100644 src/3rdparty/libpng/projects/beos/x86-static.proj delete mode 100644 src/3rdparty/libpng/projects/beos/x86-static.txt delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpng.bpf delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpng.bpg delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpng.bpr delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpng.cpp delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpng.readme.txt delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpngstat.bpf delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/libpngstat.bpr delete mode 100644 src/3rdparty/libpng/projects/cbuilder5/zlib.readme.txt delete mode 100644 src/3rdparty/libpng/projects/netware.txt delete mode 100644 src/3rdparty/libpng/projects/visualc6/README.txt delete mode 100644 src/3rdparty/libpng/projects/visualc6/libpng.dsp delete mode 100644 src/3rdparty/libpng/projects/visualc6/libpng.dsw delete mode 100644 src/3rdparty/libpng/projects/visualc6/pngtest.dsp delete mode 100644 src/3rdparty/libpng/projects/visualc71/PRJ0041.mak delete mode 100644 src/3rdparty/libpng/projects/visualc71/README.txt delete mode 100644 src/3rdparty/libpng/projects/visualc71/README_zlib.txt delete mode 100644 src/3rdparty/libpng/projects/visualc71/libpng.sln delete mode 100644 src/3rdparty/libpng/projects/visualc71/libpng.vcproj delete mode 100644 src/3rdparty/libpng/projects/visualc71/pngtest.vcproj delete mode 100644 src/3rdparty/libpng/projects/visualc71/zlib.vcproj delete mode 100644 src/3rdparty/libpng/projects/wince.txt delete mode 100644 src/3rdparty/libpng/scripts/CMakeLists.txt delete mode 100644 src/3rdparty/libpng/scripts/SCOPTIONS.ppc delete mode 100644 src/3rdparty/libpng/scripts/descrip.mms delete mode 100755 src/3rdparty/libpng/scripts/libpng-config-body.in delete mode 100755 src/3rdparty/libpng/scripts/libpng-config-head.in delete mode 100755 src/3rdparty/libpng/scripts/libpng-config.in delete mode 100644 src/3rdparty/libpng/scripts/libpng.icc delete mode 100644 src/3rdparty/libpng/scripts/libpng.pc-configure.in delete mode 100644 src/3rdparty/libpng/scripts/libpng.pc.in delete mode 100644 src/3rdparty/libpng/scripts/makefile.32sunu delete mode 100644 src/3rdparty/libpng/scripts/makefile.64sunu delete mode 100644 src/3rdparty/libpng/scripts/makefile.acorn delete mode 100644 src/3rdparty/libpng/scripts/makefile.aix delete mode 100644 src/3rdparty/libpng/scripts/makefile.amiga delete mode 100644 src/3rdparty/libpng/scripts/makefile.atari delete mode 100644 src/3rdparty/libpng/scripts/makefile.bc32 delete mode 100644 src/3rdparty/libpng/scripts/makefile.beos delete mode 100644 src/3rdparty/libpng/scripts/makefile.bor delete mode 100644 src/3rdparty/libpng/scripts/makefile.cygwin delete mode 100644 src/3rdparty/libpng/scripts/makefile.darwin delete mode 100644 src/3rdparty/libpng/scripts/makefile.dec delete mode 100644 src/3rdparty/libpng/scripts/makefile.dj2 delete mode 100644 src/3rdparty/libpng/scripts/makefile.elf delete mode 100644 src/3rdparty/libpng/scripts/makefile.freebsd delete mode 100644 src/3rdparty/libpng/scripts/makefile.gcc delete mode 100644 src/3rdparty/libpng/scripts/makefile.gcmmx delete mode 100644 src/3rdparty/libpng/scripts/makefile.hp64 delete mode 100644 src/3rdparty/libpng/scripts/makefile.hpgcc delete mode 100644 src/3rdparty/libpng/scripts/makefile.hpux delete mode 100644 src/3rdparty/libpng/scripts/makefile.ibmc delete mode 100644 src/3rdparty/libpng/scripts/makefile.intel delete mode 100644 src/3rdparty/libpng/scripts/makefile.knr delete mode 100644 src/3rdparty/libpng/scripts/makefile.linux delete mode 100644 src/3rdparty/libpng/scripts/makefile.mingw delete mode 100644 src/3rdparty/libpng/scripts/makefile.mips delete mode 100644 src/3rdparty/libpng/scripts/makefile.msc delete mode 100644 src/3rdparty/libpng/scripts/makefile.ne12bsd delete mode 100644 src/3rdparty/libpng/scripts/makefile.netbsd delete mode 100644 src/3rdparty/libpng/scripts/makefile.nommx delete mode 100644 src/3rdparty/libpng/scripts/makefile.openbsd delete mode 100644 src/3rdparty/libpng/scripts/makefile.os2 delete mode 100644 src/3rdparty/libpng/scripts/makefile.sco delete mode 100644 src/3rdparty/libpng/scripts/makefile.sggcc delete mode 100644 src/3rdparty/libpng/scripts/makefile.sgi delete mode 100644 src/3rdparty/libpng/scripts/makefile.so9 delete mode 100644 src/3rdparty/libpng/scripts/makefile.solaris delete mode 100644 src/3rdparty/libpng/scripts/makefile.solaris-x86 delete mode 100644 src/3rdparty/libpng/scripts/makefile.std delete mode 100644 src/3rdparty/libpng/scripts/makefile.sunos delete mode 100644 src/3rdparty/libpng/scripts/makefile.tc3 delete mode 100644 src/3rdparty/libpng/scripts/makefile.vcawin32 delete mode 100644 src/3rdparty/libpng/scripts/makefile.vcwin32 delete mode 100644 src/3rdparty/libpng/scripts/makefile.watcom delete mode 100644 src/3rdparty/libpng/scripts/makevms.com delete mode 100644 src/3rdparty/libpng/scripts/pngos2.def delete mode 100644 src/3rdparty/libpng/scripts/pngw32.def delete mode 100644 src/3rdparty/libpng/scripts/pngw32.rc delete mode 100644 src/3rdparty/libpng/scripts/smakefile.ppc diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE deleted file mode 100644 index b73bbb5..0000000 --- a/src/3rdparty/libpng/ANNOUNCE +++ /dev/null @@ -1,57 +0,0 @@ - -Libpng 1.2.40 - September 10, 2009 - -This is a public release of libpng, intended for use in production codes. - -Files available for download: - -Source files with LF line endings (for Unix/Linux) and with a -"configure" script - - libpng-1.2.40.tar.xz (LZMA-compressed, recommended) - libpng-1.2.40.tar.gz - libpng-1.2.40.tar.bz2 - -Source files with LF line endings (for Unix/Linux) without the -"configure" script - - libpng-1.2.40-no-config.tar.xz (LZMA-compressed, recommended) - libpng-1.2.40-no-config.tar.gz - libpng-1.2.40-no-config.tar.bz2 - -Source files with CRLF line endings (for Windows), without the -"configure" script - - lpng1240.zip - lpng1240.7z - lpng1240.tar.bz2 - -Project files - - libpng-1.2.40-project-netware.zip - libpng-1.2.40-project-wince.zip - -Other information: - - libpng-1.2.40-README.txt - libpng-1.2.40-KNOWNBUGS.txt - libpng-1.2.40-LICENSE.txt - libpng-1.2.40-Y2K-compliance.txt - libpng-1.2.40-[previous version]-diff.txt - -Changes since the last public release (1.2.39): - -version 1.2.40 [September 10, 2009] - - Removed an extra png_debug() recently added to png_write_find_filter(). - Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. - Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) or to glennrp at users.sourceforge.net - -Glenn R-P diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES deleted file mode 100644 index 9bb8ac8..0000000 --- a/src/3rdparty/libpng/CHANGES +++ /dev/null @@ -1,2479 +0,0 @@ -/* -CHANGES - changes for libpng - -version 0.2 - added reader into png.h - fixed small problems in stub file - -version 0.3 - added pull reader - split up pngwrite.c to several files - added pnglib.txt - added example.c - cleaned up writer, adding a few new transformations - fixed some bugs in writer - interfaced with zlib 0.5 - added K&R support - added check for 64 KB blocks for 16 bit machines - -version 0.4 - cleaned up code and commented code - simplified time handling into png_time - created png_color_16 and png_color_8 to handle color needs - cleaned up color type defines - fixed various bugs - made various names more consistent - interfaced with zlib 0.71 - cleaned up zTXt reader and writer (using zlib's Reset functions) - split transformations into pngrtran.c and pngwtran.c - -version 0.5 - interfaced with zlib 0.8 - fixed many reading and writing bugs - saved using 3 spaces instead of tabs - -version 0.6 - added png_large_malloc() and png_large_free() - added png_size_t - cleaned up some compiler warnings - added png_start_read_image() - -version 0.7 - cleaned up lots of bugs - finished dithering and other stuff - added test program - changed name from pnglib to libpng - -version 0.71 [June, 1995] - changed pngtest.png for zlib 0.93 - fixed error in libpng.txt and example.c - -version 0.8 - cleaned up some bugs - added png_set_filler() - split up pngstub.c into pngmem.c, pngio.c, and pngerror.c - added #define's to remove unwanted code - moved png_info_init() to png.c - added old_size into png_realloc() - added functions to manually set filtering and compression info - changed compression parameters based on image type - optimized filter selection code - added version info - changed external functions passing floats to doubles (k&r problems?) - put all the configurable stuff in pngconf.h - enabled png_set_shift to work with paletted images on read - added png_read_update_info() - updates info structure with - transformations - -version 0.81 [August, 1995] - incorporated Tim Wegner's medium model code (thanks, Tim) - -version 0.82 [September, 1995] - [unspecified changes] - -version 0.85 [December, 1995] - added more medium model code (almost everything's a far) - added i/o, error, and memory callback functions - fixed some bugs (16 bit, 4 bit interlaced, etc.) - added first run progressive reader (barely tested) - -version 0.86 [January, 1996] - fixed bugs - improved documentation - -version 0.87 [January, 1996] - fixed medium model bugs - fixed other bugs introduced in 0.85 and 0.86 - added some minor documentation - -version 0.88 [January, 1996] - fixed progressive bugs - replaced tabs with spaces - cleaned up documentation - added callbacks for read/write and warning/error functions - -version 0.89 [July, 1996] - added new initialization API to make libpng work better with shared libs - we now have png_create_read_struct(), png_create_write_struct(), - png_create_info_struct(), png_destroy_read_struct(), and - png_destroy_write_struct() instead of the separate calls to - malloc and png_read_init(), png_info_init(), and png_write_init() - changed warning/error callback functions to fix bug - this means you - should use the new initialization API if you were using the old - png_set_message_fn() calls, and that the old API no longer exists - so that people are aware that they need to change their code - changed filter selection API to allow selection of multiple filters - since it didn't work in previous versions of libpng anyways - optimized filter selection code - fixed png_set_background() to allow using an arbitrary RGB color for - paletted images - fixed gamma and background correction for paletted images, so - png_correct_palette is not needed unless you are correcting an - external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED - in pngconf.h) - if nobody uses this, it may disappear in the future. - fixed bug with Borland 64K memory allocation (Alexander Lehmann) - fixed bug in interlace handling (Smarasderagd, I think) - added more error checking for writing and image to reduce invalid files - separated read and write functions so that they won't both be linked - into a binary when only reading or writing functionality is used - new pngtest image also has interlacing and zTXt - updated documentation to reflect new API - -version 0.90 [January, 1997] - made CRC errors/warnings on critical and ancillary chunks configurable - libpng will use the zlib CRC routines by (compile-time) default - changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) - added external C++ wrapper statements to png.h (Gilles Dauphin) - allow PNG file to be read when some or all of file signature has already - been read from the beginning of the stream. ****This affects the size - of info_struct and invalidates all programs that use a shared libpng**** - fixed png_filler() declarations - fixed? background color conversions - fixed order of error function pointers to match documentation - current chunk name is now available in png_struct to reduce the number - of nearly identical error messages (will simplify multi-lingual - support when available) - try to get ready for unknown-chunk callback functions: - - previously read critical chunks are flagged, so the chunk handling - routines can determine if the chunk is in the right place - - all chunk handling routines have the same prototypes, so we will - be able to handle all chunks via a callback mechanism - try to fix Linux "setjmp" buffer size problems - removed png_large_malloc, png_large_free, and png_realloc functions. - -version 0.95 [March, 1997] - fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never - fixed bug in PNG file signature compares when start != 0 - changed parameter type of png_set_filler(...filler...) from png_byte - to png_uint_32 - added test for MACOS to ensure that both math.h and fp.h are not #included - added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) - added "packswap" transformation, which changes the endianness of - packed-pixel bytes (Kevin Bracey) - added "strip_alpha" transformation, which removes the alpha channel of - input images without using it (not necessarily a good idea) - added "swap_alpha" transformation, which puts the alpha channel in front - of the color bytes instead of after - removed all implicit variable tests which assume NULL == 0 (I think) - changed several variables to "png_size_t" to show 16/32-bit limitations - added new pCAL chunk read/write support - added experimental filter selection weighting (Greg Roelofs) - removed old png_set_rgbx() and png_set_xrgb() functions that have been - obsolete for about 2 years now (use png_set_filler() instead) - added macros to read 16- and 32-bit ints directly from buffer, to be - used only on those systems that support it (namely PowerPC and 680x0) - With some testing, this may become the default for MACOS/PPC systems. - only calculate CRC on data if we are going to use it - added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? - added macros for simple libpng debugging output selectable at compile time - removed PNG_READ_END_MODE in progressive reader (Smarasderagd) - more description of info_struct in libpng.txt and png.h - more instructions in example.c - more chunk types tested in pngtest.c - renamed pngrcb.c to pngset.c, and all png_read_ functions to be - png_set_. We now have corresponding png_get_ - functions in pngget.c to get information in info_ptr. This isolates - the application from the internal organization of png_info_struct - (good for shared library implementations). - -version 0.96 [May, 1997] - fixed serious bug with < 8bpp images introduced in 0.95 - fixed 256-color transparency bug (Greg Roelofs) - fixed up documentation (Greg Roelofs, Laszlo Nyul) - fixed "error" in pngconf.h for Linux setjmp() behaviour - fixed DOS medium model support (Tim Wegner) - fixed png_check_keyword() for case with error in static string text - added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) - added typecasts to quiet compiler errors - added more debugging info - -version 0.97 [January, 1998] - removed PNG_USE_OWN_CRC capability - relocated png_set_crc_action from pngrutil.c to pngrtran.c - fixed typecasts of "new_key", etc. (Andreas Dilger) - added RFC 1152 [sic] date support - fixed bug in gamma handling of 4-bit grayscale - added 2-bit grayscale gamma handling (Glenn R-P) - added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) - minor corrections in libpng.txt - added simple sRGB support (Glenn R-P) - easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; - all configurable options can be selected from command-line instead - of having to edit pngconf.h (Glenn R-P) - fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) - added more conditions for png_do_background, to avoid changing - black pixels to background when a background is supplied and - no pixels are transparent - repaired PNG_NO_STDIO behaviour - tested NODIV support and made it default behaviour (Greg Roelofs) - added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) - regularized version numbering scheme and bumped shared-library major - version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs) - -version 0.98 [January, 1998] - cleaned up some typos in libpng.txt and in code documentation - fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) - cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c - changed recommendation about file_gamma for PC images to .51 from .45, - in example.c and libpng.txt, added comments to distinguish between - screen_gamma, viewing_gamma, and display_gamma. - changed all references to RFC1152 to read RFC1123 and changed the - PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED - added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) - changed srgb_intent from png_byte to int to avoid compiler bugs - -version 0.99 [January 30, 1998] - free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) - fixed a longstanding "packswap" bug in pngtrans.c - fixed some inconsistencies in pngconf.h that prevented compiling with - PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined - fixed some typos and made other minor rearrangement of libpng.txt (Andreas) - changed recommendation about file_gamma for PC images to .50 from .51 in - example.c and libpng.txt, and changed file_gamma for sRGB images to .45 - added a number of functions to access information from the png structure - png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) - added TARGET_MACOS similar to zlib-1.0.8 - define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined - added type casting to all png_malloc() function calls -version 0.99a [January 31, 1998] - Added type casts and parentheses to all returns that return a value.(Tim W.) -version 0.99b [February 4, 1998] - Added type cast png_uint_32 on malloc function calls where needed. - Changed type of num_hist from png_uint_32 to int (same as num_palette). - Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. - Renamed makefile.elf to makefile.lnx. -version 0.99c [February 7, 1998] - More type casting. Removed erroneous overflow test in pngmem.c. - Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. - Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. -version 0.99d [February 11, 1998] - Renamed "far_to_near()" "png_far_to_near()" - Revised libpng.3 - Version 99c "buffered" operations didn't work as intended. Replaced them - with png_memcpy_check() and png_memset_check(). - Added many "if (png_ptr == NULL) return" to quell compiler warnings about - unused png_ptr, mostly in pngget.c and pngset.c. - Check for overlength tRNS chunk present when indexed-color PLTE is read. - Cleaned up spelling errors in libpng.3/libpng.txt - Corrected a problem with png_get_tRNS() which returned undefined trans array -version 0.99e [February 28, 1998] - Corrected png_get_tRNS() again. - Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". - Touched up example.c to make more of it compileable, although the entire - file still can't be compiled (Willem van Schaik) - Fixed a bug in png_do_shift() (Bryan Tsai) - Added a space in png.h prototype for png_write_chunk_start() - Replaced pngtest.png with one created with zlib 1.1.1 - Changed pngtest to report PASS even when file size is different (Jean-loup G.) - Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) -version 0.99f [March 5, 1998] - Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) - Moved makefiles into a "scripts" directory, and added INSTALL instruction file - Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) - Added pointers to "note on libpng versions" in makefile.lnx and README - Added row callback feature when reading and writing nonprogressive rows - and added a test of this feature in pngtest.c - Added user transform callbacks, with test of the feature in pngtest.c -version 0.99g [March 6, 1998, morning] - Minor changes to pngtest.c to suppress compiler warnings. - Removed "beta" language from documentation. -version 0.99h [March 6, 1998, evening] - Minor changes to previous minor changes to pngtest.c - Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED - and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro - Added user transform capability - -version 1.00 [March 7, 1998] - Changed several typedefs in pngrutil.c - Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) - replaced "while(1)" with "for(;;)" - added PNGARG() to prototypes in pngtest.c and removed some prototypes - updated some of the makefiles (Tom Lane) - changed some typedefs (s_start, etc.) in pngrutil.c - fixed dimensions of "short_months" array in pngwrite.c - Replaced ansi2knr.c with the one from jpeg-v6 - -version 1.0.0 [March 8, 1998] - Changed name from 1.00 to 1.0.0 (Adam Costello) - Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) -version 1.0.0a [March 9, 1998] - Fixed three bugs in pngrtran.c to make gamma+background handling consistent - (Greg Roelofs) - Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz - for major, minor, and bugfix releases. This is 10001. (Adam Costello, - Tom Lane) - Make months range from 1-12 in png_convert_to_rfc1123 -version 1.0.0b [March 13, 1998] - Quieted compiler complaints about two empty "for" loops in pngrutil.c - Minor changes to makefile.s2x - Removed #ifdef/#endif around a png_free() in pngread.c - -version 1.0.1 [March 14, 1998] - Changed makefile.s2x to reduce security risk of using a relative pathname - Fixed some typos in the documentation (Greg). - Fixed a problem with value of "channels" returned by png_read_update_info() -version 1.0.1a [April 21, 1998] - Optimized Paeth calculations by replacing abs() function calls with intrinsics - plus other loop optimizations. Improves avg decoding speed by about 20%. - Commented out i386istic "align" compiler flags in makefile.lnx. - Reduced the default warning level in some makefiles, to make them consistent. - Removed references to IJG and JPEG in the ansi2knr.c copyright statement. - Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. - Added grayscale and 16-bit capability to png_do_read_filler(). - Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes - too large when writing an image with bit_depth < 8 (Bob Dellaca). - Corrected some bugs in the experimental weighted filtering heuristics. - Moved a misplaced pngrutil code block that truncates tRNS if it has more - than num_palette entries -- test was done before num_palette was defined. - Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). - Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen). -version 1.0.1b [May 2, 1998] - Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). - Relocated the png_composite macros from pngrtran.c to png.h (Greg). - Added makefile.sco (contributed by Mike Hopkirk). - Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. - Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. - More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert). - More work on loop optimization which may help when compiled with C++ compilers. - Added warnings when people try to use transforms they've defined out. - Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. - Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) -version 1.0.1c [May 11, 1998] - Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for - filler bytes should have been 0xff instead of 0xf. - Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. - Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED - out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h - Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, - for consistency, in pngconf.h - Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier - to remove unwanted capabilities via the compile line - Made some corrections to grammar (which, it's) in documentation (Greg). - Corrected example.c, use of row_pointers in png_write_image(). -version 1.0.1d [May 24, 1998] - Corrected several statements that used side effects illegally in pngrutil.c - and pngtrans.c, that were introduced in version 1.0.1b - Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) - More corrections to example.c, use of row_pointers in png_write_image() - and png_read_rows(). - Added pngdll.mak and pngdef.pas to scripts directory, contributed by - Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 - Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) - Changed several loops from count-down to count-up, for consistency. -version 1.0.1e [June 6, 1998] - Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and - added warnings when people try to set png_read_fn and png_write_fn in - the same structure. - Added a test such that png_do_gamma will be done when num_trans==0 - for truecolor images that have defined a background. This corrects an - error that was introduced in libpng-0.90 that can cause gamma processing - to be skipped. - Added tests in png.h to include "trans" and "trans_values" in structures - when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. - Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() - Moved png_convert_to_rfc_1123() from pngwrite.c to png.c - Added capability for user-provided malloc_fn() and free_fn() functions, - and revised pngtest.c to demonstrate their use, replacing the - PNGTEST_DEBUG_MEM feature. - Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). - -version 1.0.2 [June 14, 1998] - Fixed two bugs in makefile.bor . -version 1.0.2a [December 30, 1998] - Replaced and extended code that was removed from png_set_filler() in 1.0.1a. - Fixed a bug in png_do_filler() that made it fail to write filler bytes in - the left-most pixel of each row (Kevin Bracey). - Changed "static pngcharp tIME_string" to "static char tIME_string[30]" - in pngtest.c (Duncan Simpson). - Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk - even when no tIME chunk was present in the source file. - Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. - Fixed a problem in png_read_push_finish_row(), which would not skip some - passes that it should skip, for images that are less than 3 pixels high. - Interchanged the order of calls to png_do_swap() and png_do_shift() - in pngwtran.c (John Cromer). - Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . - Changed "bad adaptive filter type" from error to warning in pngrutil.c . - Fixed a documentation error about default filtering with 8-bit indexed-color. - Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO - (L. Peter Deutsch). - Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. - Added png_get_copyright() and png_get_header_version() functions. - Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c - Added information about debugging in libpng.txt and libpng.3 . - Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco. - Removed lines after Dynamic Dependencies" in makefile.aco . - Revised makefile.dec to make a shared library (Jeremie Petit). - Removed trailing blanks from all files. -version 1.0.2a [January 6, 1999] - Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h - Added "if" tests to silence complaints about unused png_ptr in png.h and png.c - Changed "check_if_png" function in example.c to return true (nonzero) if PNG. - Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() - which is obsolete. - -version 1.0.3 [January 14, 1999] - Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) - Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. -version 1.0.3a [August 12, 1999] - Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning - if an attempt is made to read an interlaced image when it's not supported. - Added check if png_ptr->trans is defined before freeing it in pngread.c - Modified the Y2K statement to include versions back to version 0.71 - Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c - Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) - Replaced leading blanks with tab characters in makefile.hux - Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. - Changed (float)red and (float)green to (double)red, (double)green - in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. - Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). - Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). - Updated documentation to refer to the PNG-1.2 specification. - Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c - in makefile.knr, INSTALL, and README (L. Peter Deutsch) - Fixed bugs in calculation of the length of rowbytes when adding alpha - channels to 16-bit images, in pngrtran.c (Chris Nokleberg) - Added function png_set_user_transform_info() to store user_transform_ptr, - user_depth, and user_channels into the png_struct, and a function - png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) - Added function png_set_empty_plte_permitted() to make libpng useable - in MNG applications. - Corrected the typedef for png_free_ptr in png.h (Jesse Jones). - Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be - consistent with PNG-1.2, and allow variance of 500 before complaining. - Added assembler code contributed by Intel in file pngvcrd.c and modified - makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, Gilles Vollant) - Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. - Added some aliases for png_set_expand() in pngrtran.c, namely - png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() - (Greg Roelofs, in "PNG: The Definitive Guide"). - Added makefile.beo for BEOS on X86, contributed by Sander Stok. -version 1.0.3b [August 26, 1999] - Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h - Changed leading blanks to tabs in all makefiles. - Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. - Made alternate versions of png_set_expand() in pngrtran.c, namely - png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha - (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. - Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h - Revised calculation of num_blocks in pngmem.c to avoid a potentially - negative shift distance, whose results are undefined in the C language. - Added a check in pngset.c to prevent writing multiple tIME chunks. - Added a check in pngwrite.c to detect invalid small window_bits sizes. -version 1.0.3d [September 4, 1999] - Fixed type casting of igamma in pngrutil.c - Added new png_expand functions to scripts/pngdef.pas and pngos2.def - Added a demo read_user_transform_fn that examines the row filters in pngtest.c - -version 1.0.4 [September 24, 1999] - Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined - Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h - Made several minor corrections to pngtest.c - Renamed the makefiles with longer but more user friendly extensions. - Copied the PNG copyright and license to a separate LICENSE file. - Revised documentation, png.h, and example.c to remove reference to - "viewing_gamma" which no longer appears in the PNG specification. - Revised pngvcrd.c to use MMX code for interlacing only on the final pass. - Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a - Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX - assembler code) and makefile.vcwin32 (doesn't). - Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) - Added a copy of pngnow.png to the distribution. -version 1.0.4a [September 25, 1999] - Increase max_pixel_depth in pngrutil.c if a user transform needs it. - Changed several division operations to right-shifts in pngvcrd.c -version 1.0.4b [September 30, 1999] - Added parentheses in line 3732 of pngvcrd.c - Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 -version 1.0.4c [October 1, 1999] - Added a "png_check_version" function in png.c and pngtest.c that will generate - a helpful compiler error if an old png.h is found in the search path. - Changed type of png_user_transform_depth|channels from int to png_byte. -version 1.0.4d [October 6, 1999] - Changed 0.45 to 0.45455 in png_set_sRGB() - Removed unused PLTE entries from pngnow.png - Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. -version 1.0.4e [October 10, 1999] - Fixed sign error in pngvcrd.c (Greg Roelofs) - Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) -version 1.0.4f [October 15, 1999] - Surrounded example.c code with #if 0 .. #endif to prevent people from - inadvertently trying to compile it. - Changed png_get_header_version() from a function to a macro in png.h - Added type casting mostly in pngrtran.c and pngwtran.c - Removed some pointless "ptr = NULL" in pngmem.c - Added a "contrib" directory containing the source code from Greg's book. - -version 1.0.5 [October 15, 1999] - Minor editing of the INSTALL and README files. -version 1.0.5a [October 23, 1999] - Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) - Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) - Further optimization and bugfix of pngvcrd.c - Revised pngset.c so that it does not allocate or free memory in the user's - text_ptr structure. Instead, it makes its own copy. - Created separate write_end_info_struct in pngtest.c for a more severe test. - Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. -version 1.0.5b [November 23, 1999] - Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and - PNG_FLAG_WROTE_tIME from flags to mode. - Added png_write_info_before_PLTE() function. - Fixed some typecasting in contrib/gregbook/*.c - Updated scripts/makevms.com and added makevms.com to contrib/gregbook - and contrib/pngminus (Martin Zinser) -version 1.0.5c [November 26, 1999] - Moved png_get_header_version from png.h to png.c, to accommodate ansi2knr. - Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to - accommodate making DLL's: Moved usr_png_ver from global variable to function - png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and - eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays - into pngtypes.h. Eliminated use of global png_pass arrays. Declared the - png_CHNK and png_pass arrays to be "const". Made the global arrays - available to applications (although none are used in libpng itself) when - PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. - Removed some extraneous "-I" from contrib/pngminus/makefile.std - Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. - Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 -version 1.0.5d [November 29, 1999] - Add type cast (png_const_charp) two places in png.c - Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. - Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available - to applications a macro "PNG_USE_LOCAL_ARRAYS". - Remove all the new declarations with #ifdef/#endif when - PNG_USE_GLOBAL_ARRAYS is defined. - Added PNG_EXPORT_VAR macro to accommodate making DLL's. -version 1.0.5e [November 30, 1999] - Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text - structure; refactored the inflate/deflate support to make adding new chunks - with trailing compressed parts easier in the future, and added new functions - png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, - png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). - NOTE: Applications that write text chunks MUST define png_text->lang - before calling png_set_text(). It must be set to NULL if you want to - write tEXt or zTXt chunks. If you want your application to be able to - run with older versions of libpng, use - - #ifdef PNG_iTXt_SUPPORTED - png_text[i].lang = NULL; - #endif - - Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned - offsets (Eric S. Raymond). - Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into - PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED - macros, leaving the separate macros also available. - Removed comments on #endifs at the end of many short, non-nested #if-blocks. -version 1.0.5f [December 6, 1999] - Changed makefile.solaris to issue a warning about potential problems when - the ucb "ld" is in the path ahead of the ccs "ld". - Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. - Added sCAL chunk support (Eric S. Raymond). -version 1.0.5g [December 7, 1999] - Fixed "png_free_spallettes" typo in png.h - Added code to handle new chunks in pngpread.c - Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block - Added "translated_key" to png_text structure and png_write_iTXt(). - Added code in pngwrite.c to work around a newly discovered zlib bug. -version 1.0.5h [December 10, 1999] - NOTE: regarding the note for version 1.0.5e, the following must also - be included in your code: - png_text[i].translated_key = NULL; - Unknown chunk handling is now supported. - Option to eliminate all floating point support was added. Some new - fixed-point functions such as png_set_gAMA_fixed() were added. - Expanded tabs and removed trailing blanks in source files. -version 1.0.5i [December 13, 1999] - Added some type casts to silence compiler warnings. - Renamed "png_free_spalette" to "png_free_spalettes" for consistency. - Removed leading blanks from a #define in pngvcrd.c - Added some parameters to the new png_set_keep_unknown_chunks() function. - Added a test for up->location != 0 in the first instance of writing - unknown chunks in pngwrite.c - Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to - prevent recursion. - Added png_free_hIST() function. - Various patches to fix bugs in the sCAL and integer cHRM processing, - and to add some convenience macros for use with sCAL. -version 1.0.5j [December 21, 1999] - Changed "unit" parameter of png_write_sCAL from png_byte to int, to work - around buggy compilers. - Added new type "png_fixed_point" for integers that hold float*100000 values - Restored backward compatibility of tEXt/zTXt chunk processing: - Restored the first four members of png_text to the same order as v.1.0.5d. - Added members "lang_key" and "itxt_length" to png_text struct. Set - text_length=0 when "text" contains iTXt data. Use the "compression" - member to distinguish among tEXt/zTXt/iTXt types. Added - PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. - The "Note" above, about backward incompatibility of libpng-1.0.5e, no - longer applies. - Fixed png_read|write_iTXt() to read|write parameters in the right order, - and to write the iTXt chunk after IDAT if it appears in the end_ptr. - Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) - Reversed the order of trying to write floating-point and fixed-point gAMA. -version 1.0.5k [December 27, 1999] - Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" - Added png_handle_as_unknown() function (Glenn) - Added png_free_chunk_list() function and chunk_list and num_chunk_list members - of png_ptr. - Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. - Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings - about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) - Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). - Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. - Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). -version 1.0.5l [January 1, 2000] - Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() - for setting a callback function to handle unknown chunks and for - retrieving the associated user pointer (Glenn). -version 1.0.5m [January 7, 2000] - Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). -version 1.0.5n [January 9, 2000] - Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its - own memory for info_ptr->palette. This makes it safe for the calling - application to free its copy of the palette any time after it calls - png_set_PLTE(). -version 1.0.5o [January 20, 2000] - Cosmetic changes only (removed some trailing blanks and TABs) -version 1.0.5p [January 31, 2000] - Renamed pngdll.mak to makefile.bd32 - Cosmetic changes in pngtest.c -version 1.0.5q [February 5, 2000] - Relocated the makefile.solaris warning about PATH problems. - Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) - Revised makefile.gcmmx - Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros -version 1.0.5r [February 7, 2000] - Removed superfluous prototype for png_get_itxt from png.h - Fixed a bug in pngrtran.c that improperly expanded the background color. - Return *num_text=0 from png_get_text() when appropriate, and fix documentation - of png_get_text() in libpng.txt/libpng.3. -version 1.0.5s [February 18, 2000] - Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the - new error handler that's planned for the next libpng release, and changed - example.c, pngtest.c, and contrib programs to use this macro. - Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) - Fixed a bug in png_read_png() that caused it to fail to expand some images - that it should have expanded. - Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions - in pngget.c - Changed the allocation of palette, history, and trans arrays back to - the version 1.0.5 method (linking instead of copying) which restores - backward compatibility with version 1.0.5. Added some remarks about - that in example.c. Added "free_me" member to info_ptr and png_ptr - and added png_free_data() function. - Updated makefile.linux and makefile.gccmmx to make directories conditionally. - Made cosmetic changes to pngasmrd.h - Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). - Modified png_read_png() to allocate info_ptr->row_pointers only if it - hasn't already been allocated. -version 1.0.5t [March 4, 2000] - Changed png_jmp_env() migration aiding macro to png_jmpbuf(). - Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c - Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when - PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b - Files in contrib/gregbook were revised to use png_jmpbuf() and to select - a 24-bit visual if one is available, and to allow abbreviated options. - Files in contrib/pngminus were revised to use the png_jmpbuf() macro. - Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s -version 1.0.5u [March 5, 2000] - Simplified the code that detects old png.h in png.c and pngtest.c - Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) - Increased precision of rgb_to_gray calculations from 8 to 15 bits and - added png_set_rgb_to_gray_fixed() function. - Added makefile.bc32 (32-bit Borland C++, C mode) -version 1.0.5v [March 11, 2000] - Added some parentheses to the png_jmpbuf macro definition. - Updated references to the zlib home page, which has moved to freesoftware.com. - Corrected bugs in documentation regarding png_read_row() and png_write_row(). - Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. - Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, - revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) - -version 1.0.6 [March 20, 2000] - Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c - Added makefile.sggcc (SGI IRIX with gcc) -version 1.0.6d [April 7, 2000] - Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO - Added data_length parameter to png_decompress_chunk() function - Revised documentation to remove reference to abandoned png_free_chnk functions - Fixed an error in png_rgb_to_gray_fixed() - Revised example.c, usage of png_destroy_write_struct(). - Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file - Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c - Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). -version 1.0.6e [April 9, 2000] - Added png_data_freer() function. - In the code that checks for over-length tRNS chunks, added check of - info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) - Minor revisions of libpng.txt/libpng.3. - Check for existing data and free it if the free_me flag is set, in png_set_*() - and png_handle_*(). - Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED - is defined. - Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c - and mentioned the purposes of the two macros in libpng.txt/libpng.3. -version 1.0.6f [April 14, 2000] - Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. - Add checks in png_set_text() for NULL members of the input text structure. - Revised libpng.txt/libpng.3. - Removed superfluous prototype for png_set_itxt from png.h - Removed "else" from pngread.c, after png_error(), and changed "0" to "length". - Changed several png_errors about malformed ancillary chunks to png_warnings. -version 1.0.6g [April 24, 2000] - Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. - Relocated paragraph about png_set_background() in libpng.3/libpng.txt - and other revisions (Matthias Benckmann) - Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and - png_ptr members to restore binary compatibility with libpng-1.0.5 - (breaks compatibility with libpng-1.0.6). -version 1.0.6h [April 24, 2000] - Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds - libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) - This is a temporary change for test purposes. -version 1.0.6i [May 2, 2000] - Rearranged some members at the end of png_info and png_struct, to put - unknown_chunks_num and free_me within the original size of the png_structs - and free_me, png_read_user_fn, and png_free_fn within the original png_info, - because some old applications allocate the structs directly instead of - using png_create_*(). - Added documentation of user memory functions in libpng.txt/libpng.3 - Modified png_read_png so that it will use user_allocated row_pointers - if present, unless free_me directs that it be freed, and added description - of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. - Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version - 1.00) members of png_struct and png_info, to regain binary compatibility - when you define this macro. Capabilities lost in this event - are user transforms (new in version 1.0.0),the user transform pointer - (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, - the high-level interface, and unknown chunks support (all new in 1.0.6). - This was necessary because of old applications that allocate the structs - directly as authors were instructed to do in libpng-0.88 and earlier, - instead of using png_create_*(). - Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which - can be used to detect codes that directly allocate the structs, and - code to check these modes in png_read_init() and png_write_init() and - generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED - was not defined. - Added makefile.intel and updated makefile.watcom (Pawel Mrochen) -version 1.0.6j [May 3, 2000] - Overloaded png_read_init() and png_write_init() with macros that convert - calls to png_read_init_2() or png_write_init_2() that check the version - and structure sizes. -version 1.0.7beta11 [May 7, 2000] - Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes - which are no longer used. - Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is - defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED - is defined. - Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory - overrun when old applications fill the info_ptr->text structure directly. - Added PNGAPI macro, and added it to the definitions of all exported functions. - Relocated version macro definitions ahead of the includes of zlib.h and - pngconf.h in png.h. -version 1.0.7beta12 [May 12, 2000] - Revised pngset.c to avoid a problem with expanding the png_debug macro. - Deleted some extraneous defines from pngconf.h - Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. - Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. - Added png_access_version_number() function. - Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). - Expanded libpng.3/libpng.txt information about png_data_freer(). -version 1.0.7beta14 [May 17, 2000] (beta13 was not published) - Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as - warnings instead of errors, as pngrutil.c does. - Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() - will actually write IDATs. - Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. - Make png_free_data() ignore its final parameter except when freeing data - that can have multiple instances (text, sPLT, unknowns). - Fixed a new bug in png_set_rows(). - Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. - Added png_set_invalid() function. - Fixed incorrect illustrations of png_destroy_write_struct() in example.c. -version 1.0.7beta15 [May 30, 2000] - Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce - fewer error messages. - Rearranged checks for Z_OK to check the most likely path first in pngpread.c - and pngwutil.c. - Added checks in pngtest.c for png_create_*() returning NULL, and mentioned - in libpng.txt/libpng.3 the need for applications to check this. - Changed names of png_default_*() functions in pngtest to pngtest_*(). - Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. - Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c - Set each pointer to NULL after freeing it in png_free_data(). - Worked around a problem in pngconf.h; AIX's strings.h defines an "index" - macro that conflicts with libpng's png_color_16.index. (Dimitri Papadapoulos) - Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). -version 1.0.7beta16 [June 4, 2000] - Revised the workaround of AIX string.h "index" bug. - Added a check for overlength PLTE chunk in pngrutil.c. - Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer - indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. - Added a warning in png_decompress_chunk() when it runs out of data, e.g. - when it tries to read an erroneous PhotoShop iCCP chunk. - Added PNG_USE_DLL macro. - Revised the copyright/disclaimer/license notice. - Added contrib/msvctest directory -version 1.0.7rc1 [June 9, 2000] - Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) - Added contrib/visupng directory (Willem van Schaik) -version 1.0.7beta18 [June 23, 2000] - Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ - and do not redefine PNGAPI if it is passed in via a compiler directive. - Revised visupng/PngFile.c to remove returns from within the Try block. - Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. - Updated contrib/visupng/cexcept.h to version 1.0.0. - Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. -version 1.0.7rc2 [June 28, 2000] - Updated license to include disclaimers required by UCITA. - Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. - -version 1.0.7 [July 1, 2000] - Revised the definition of "trans_values" in libpng.3/libpng.txt -version 1.0.8beta1 [July 8, 2000] - Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. - Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and - pngwutil.c. - Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. - Removed unused "#include " from png.c - Added WindowsCE support. - Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. -version 1.0.8beta2 [July 10, 2000] - Added project files to the wince directory and made further revisions - of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. -version 1.0.8beta3 [July 11, 2000] - Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() - for indexed-color input files to avoid potential double-freeing trans array - under some unusual conditions; problem was introduced in version 1.0.6f. - Further revisions to pngtest.c and files in the wince subdirectory. -version 1.0.8beta4 [July 14, 2000] - Added the files pngbar.png and pngbar.jpg to the distribution. - Added makefile.cygwin, and cygwin support in pngconf.h - Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) -version 1.0.8rc1 [July 16, 2000] - Revised png_debug() macros and statements to eliminate compiler warnings. - -version 1.0.8 [July 24, 2000] - Added png_flush() in pngwrite.c, after png_write_IEND(). - Updated makefile.hpux to build a shared library. -version 1.0.9beta1 [November 10, 2000] - Fixed typo in scripts/makefile.hpux - Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) - Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) - Changed "cdrom.com" in documentation to "libpng.org" - Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). - Changed type of "params" from voidp to png_voidp in png_read|write_png(). - Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. - Revised the 3 instances of WRITEFILE in pngtest.c. - Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. - Updated png.rc in dll/msvc project - Revised makefile.dec to define and use LIBPATH and INCPATH - Increased size of global png_libpng_ver[] array from 12 to 18 chars. - Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. - Removed duplicate png_crc_finish() from png_handle_bKGD() function. - Added a warning when application calls png_read_update_info() multiple times. - Revised makefile.cygwin - Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. - Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). -version 1.0.9beta2 [November 19, 2000] - Renamed the "dll" subdirectory "projects". - Added borland project files to "projects" subdirectory. - Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. - Add error message in png_set_compression_buffer_size() when malloc fails. -version 1.0.9beta3 [November 23, 2000] - Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. - Removed the png_flush() in pngwrite.c that crashes some applications - that don't set png_output_flush_fn. - Added makefile.macosx and makefile.aix to scripts directory. -version 1.0.9beta4 [December 1, 2000] - Change png_chunk_warning to png_warning in png_check_keyword(). - Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). -version 1.0.9beta5 [December 15, 2000] - Added support for filter method 64 (for PNG datastreams embedded in MNG). -version 1.0.9beta6 [December 18, 2000] - Revised png_set_filter() to accept filter method 64 when appropriate. - Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to - help prevent applications from using MNG features in PNG datastreams. - Added png_permit_mng_features() function. - Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". -version 1.0.9rc1 [December 23, 2000] - Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c - Fixed error handling of unknown compression type in png_decompress_chunk(). - In pngconf.h, define __cdecl when _MSC_VER is defined. -version 1.0.9beta7 [December 28, 2000] - Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. - Revised memory management in png_set_hIST and png_handle_hIST in a backward - compatible manner. PLTE and tRNS were revised similarly. - Revised the iCCP chunk reader to ignore trailing garbage. -version 1.0.9beta8 [January 12, 2001] - Moved pngasmrd.h into pngconf.h. - Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. -version 1.0.9beta9 [January 15, 2001] - Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to - wince and msvc project module definition files. - Minor revision of makefile.cygwin. - Fixed bug with progressive reading of narrow interlaced images in pngpread.c -version 1.0.9beta10 [January 16, 2001] - Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. - Fixed "png_mmx_supported" typo in project definition files. -version 1.0.9beta11 [January 19, 2001] - Updated makefile.sgi to make shared library. - Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED - by default, for the benefit of DLL forward compatibility. These will - be re-enabled in version 1.2.0. -version 1.0.9rc2 [January 22, 2001] - Revised cygwin support. - -version 1.0.9 [January 31, 2001] - Added check of cygwin's ALL_STATIC in pngconf.h - Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. -version 1.0.10beta1 [March 14, 2001] - Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. - Reformatted libpng.3 to eliminate bad line breaks. - Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c - Added prototype for png_mmx_support() near the top of pnggccrd.c - Moved some error checking from png_handle_IHDR to png_set_IHDR. - Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. - Revised png_mmx_support() function in pnggccrd.c - Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c - Fixed memory leak in contrib/visupng/PngFile.c - Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) - Added warnings when retrieving or setting gamma=0. - Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). -version 1.0.10rc1 [March 23, 2001] - Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, - and png_strlen. - Revised png_mmx_supported() function in pnggccrd.c to return proper value. - Fixed bug in progressive reading (pngpread.c) with small images (height < 8). - -version 1.0.10 [March 30, 2001] - Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin - Added beos project files (Chris Herborth) -version 1.0.11beta1 [April 3, 2001] - Added type casts on several png_malloc() calls (Dimitri Papadapoulos). - Removed a no-longer needed AIX work-around from pngconf.h - Changed several "//" single-line comments to C-style in pnggccrd.c -version 1.0.11beta2 [April 11, 2001] - Removed PNGAPI from several functions whose prototypes did not have PNGAPI. - Updated scripts/pngos2.def -version 1.0.11beta3 [April 14, 2001] - Added checking the results of many instances of png_malloc() for NULL -version 1.0.11beta4 [April 20, 2001] - Undid the changes from version 1.0.11beta3. Added a check for NULL return - from user's malloc_fn(). - Removed some useless type casts of the NULL pointer. - Added makefile.netbsd - -version 1.0.11 [April 27, 2001] - Revised makefile.netbsd -version 1.0.12beta1 [May 14, 2001] - Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) - Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h - Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. - Eliminated the png_error about apps using png_read|write_init(). Instead, - libpng will reallocate the png_struct and info_struct if they are too small. - This retains future binary compatibility for old applications written for - libpng-0.88 and earlier. -version 1.2.0beta1 [May 6, 2001] - Bumped DLLNUM to 2. - Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED - by default. - Added runtime selection of MMX features. - Added png_set_strip_error_numbers function and related macros. -version 1.2.0beta2 [May 7, 2001] - Finished merging 1.2.0beta1 with version 1.0.11 - Added a check for attempts to read or write PLTE in grayscale PNG datastreams. -version 1.2.0beta3 [May 17, 2001] - Enabled user memory function by default. - Modified png_create_struct so it passes user mem_ptr to user memory allocator. - Increased png_mng_features flag from png_byte to png_uint_32. - Bumped shared-library (so-number) and dll-number to 3. -version 1.2.0beta4 [June 23, 2001] - Check for missing profile length field in iCCP chunk and free chunk_data - in case of truncated iCCP chunk. - Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc - Bumped dll-number from 2 to 3 in makefile.cygwin - Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly - if user attempts to run it on an 8-bit display. - Updated contrib/gregbook - Use png_malloc instead of png_zalloc to allocate palette in pngset.c - Updated makefile.ibmc - Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes - of png_write_oFFS width and height from png_uint_32 to png_int_32. - Updated example.c - Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c -version 1.2.0beta5 [August 8, 2001] - Revised contrib/gregbook - Revised makefile.gcmmx - Revised pnggccrd.c to conditionally compile some thread-unsafe code only - when PNG_THREAD_UNSAFE_OK is defined. - Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with - value exceeding 2^bit_depth-1 - Revised makefile.sgi and makefile.sggcc - Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c - Removed restriction that do_invert_mono only operate on 1-bit opaque files - -version 1.2.0 [September 1, 2001] - Changed a png_warning() to png_debug() in pnggccrd.c - Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). -version 1.2.1beta1 [October 19, 2001] - Revised makefile.std in contrib/pngminus - Include background_1 in png_struct regardless of gamma support. - Revised makefile.netbsd and makefile.macosx, added makefile.darwin. - Revised example.c to provide more details about using row_callback(). -version 1.2.1beta2 [October 25, 2001] - Added type cast to each NULL appearing in a function call, except for - WINCE functions. - Added makefile.so9. -version 1.2.1beta3 [October 27, 2001] - Removed type casts from all NULLs. - Simplified png_create_struct_2(). -version 1.2.1beta4 [November 7, 2001] - Revised png_create_info_struct() and png_creat_struct_2(). - Added error message if png_write_info() was omitted. - Type cast NULLs appearing in function calls when _NO_PROTO or - PNG_TYPECAST_NULL is defined. -version 1.2.1rc1 [November 24, 2001] - Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL - is defined. - Changed typecast of "size" argument to png_size_t in pngmem.c calls to - the user malloc_fn, to agree with the prototype in png.h - Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) - Updated makefile.sgi to recognize LIBPATH and INCPATH. - Updated various makefiles so "make clean" does not remove previous major - version of the shared library. -version 1.2.1rc2 [December 4, 2001] - Always allocate 256-entry internal palette, hist, and trans arrays, to - avoid out-of-bounds memory reference caused by invalid PNG datastreams. - Added a check for prefix_length > data_length in iCCP chunk handler. - -version 1.2.1 [December 7, 2001] - None. -version 1.2.2beta1 [February 22, 2002] - Fixed a bug with reading the length of iCCP profiles (Larry Reeves). - Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate - libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h - Revised makefile.darwin to remove "-undefined suppress" option. - Added checks for gamma and chromaticity values over 21474.83, which exceed - the limit for PNG unsigned 32-bit integers when encoded. - Revised calls to png_create_read_struct() and png_create_write_struct() - for simpler debugging. - Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) -version 1.2.2beta2 [February 23, 2002] - Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. - Check for invalid image dimensions in png_get_IHDR. - Added missing "fi;" in the install target of the SGI makefiles. - Added install-static to all makefiles that make shared libraries. - Always do gamma compensation when image is partially transparent. -version 1.2.2beta3 [March 7, 2002] - Compute background.gray and background_1.gray even when color_type is RGB - in case image gets reduced to gray later. - Modified shared-library makefiles to install pkgconfig/libpngNN.pc. - Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown - Removed unused png_write_destroy_info prototype from png.h - Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case - Added install-shared target to all makefiles that make shared libraries. - Stopped a double free of palette, hist, and trans when not using free_me. - Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. -version 1.2.2beta4 [March 8, 2002] - Compute background.gray and background_1.gray even when color_type is RGB - in case image gets reduced to gray later (Jason Summers). - Relocated a misplaced /bin/rm in the "install-shared" makefile targets - Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. -version 1.2.2beta5 [March 26, 2002] - Added missing PNGAPI to several function definitions. - Check for invalid bit_depth or color_type in png_get_IHDR(), and - check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). - Revised iTXt support to accept NULL for lang and lang_key. - Compute gamma for color components of background even when color_type is gray. - Changed "()" to "{}" in scripts/libpng.pc.in. - Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN - Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so -version 1.2.2beta6 [March 31, 2002] -version 1.0.13beta1 [March 31, 2002] - Prevent png_zalloc() from trying to memset memory that it failed to acquire. - Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). - Ensure that the right function (user or default) is used to free the - png_struct after an error in png_create_read_struct_2(). -version 1.2.2rc1 [April 7, 2002] -version 1.0.13rc1 [April 7, 2002] - Save the ebx register in pnggccrd.c (Sami Farin) - Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). - Updated makefiles to put headers in include/libpng and remove old include/*.h. - -version 1.2.2 [April 15, 2002] -version 1.0.13 [April 15, 2002] - Revised description of png_set_filter() in libpng.3/libpng.txt. - Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd -version 1.0.13patch01 [April 17, 2002] -version 1.2.2patch01 [April 17, 2002] - Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and makefile.sggcc - Fixed VER -> PNGVER typo in makefile.macosx and added install-static to install - Added install: target to makefile.32sunu and makefile.64sunu -version 1.0.13patch03 [April 18, 2002] -version 1.2.2patch03 [April 18, 2002] - Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng - subdirectory to libpngNN subdirectory without the full pathname. - Moved generation of libpng.pc from "install" to "all" in 15 makefiles. -version 1.2.3rc1 [April 28, 2002] - Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). - Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) - Fixed bug with $prefix, should be $(prefix) in makefile.hpux. - Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin - Added a link from libpngNN.pc to libpng.pc in 15 makefiles. - Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. - Revised makefile.darwin to make relative links without full pathname. - Added setjmp() at the end of png_create_*_struct_2() in case user forgets - to put one in their application. - Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and - removed them from module definition files. -version 1.2.3rc2 [May 1, 2002] - Fixed bug in reporting number of channels in pngget.c and pngset.c, - that was introduced in version 1.2.2beta5. - Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), - png_default_flush(), and png_push_fill_buffer() and included them in - module definition files. - Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. -version 1.2.3rc3 [May 1, 2002] - Revised prototype for png_default_flush() - Remove old libpng.pc and libpngNN.pc before installing new ones. -version 1.2.3rc4 [May 2, 2002] - Typos in *.def files (png_default_read|write -> png_default_read|write_data) - In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc - Added libpng-config and libpngNN-config and modified makefiles to install them. - Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles - Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp -version 1.2.3rc5 [May 11, 2002] - Changed "error" and "message" in prototypes to "error_message" and - "warning_message" to avoid namespace conflict. - Revised 15 makefiles to build libpng-config from libpng-config-*.in - Once more restored png_zalloc and png_zfree to regular nonexported form. - Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer - to nonexported form, but with PNGAPI, and removed them from module def files. -version 1.2.3rc6 [May 14, 2002] - Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c - Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. - Removed leftover libpng-config "sed" script from four makefiles. - Revised libpng-config creating script in 16 makefiles. - -version 1.2.3 [May 22, 2002] - Revised libpng-config target in makefile.cygwin. - Removed description of png_set_mem_fn() from documentation. - Revised makefile.freebsd. - Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). - Revised projects/msvc/README.txt - Changed -lpng to -lpngNN in LDFLAGS in several makefiles. -version 1.2.4beta1 [May 24, 2002] - Added libpng.pc and libpng-config to "all:" target in 16 makefiles. - Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) - Added missing "\" before closing double quote in makefile.gcmmx. - Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() - functions. -version 1.2.4beta2 [June 25, 2002] - Plugged memory leak of png_ptr->current_text (Matt Holgate). - Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) - Added -soname to the loader flags in makefile.dec, makefile.sgi, and - makefile.sggcc. - Added "test-installed" target to makefile.linux, makefile.gcmmx, - makefile.sgi, and makefile.sggcc. -version 1.2.4beta3 [June 28, 2002] - Plugged memory leak of row_buf in pngtest.c when there is a png_error(). - Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. - Added "test-installed" target to makefile.32sunu, makefile.64sunu, - makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, - makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. -version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] - Added "test-installed" target to makefile.cygwin and makefile.sco. - Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. - -version 1.2.4 and 1.0.14 [July 8, 2002] - Changed png_warning() to png_error() when width is too large to process. -version 1.2.4patch01 [July 20, 2002] - Revised makefile.cygwin to use DLL number 12 instead of 13. -version 1.2.5beta1 [August 6, 2002] - Added code to contrib/gregbook/readpng2.c to ignore unused chunks. - Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) - Removed some stray *.o files from contrib/gregbook. - Changed png_error() to png_warning() about "Too much data" in pngpread.c - and about "Extra compressed data" in pngrutil.c. - Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). - Updated makefile.hpgcc - Updated png.c and pnggccrd.c handling of return from png_mmx_support() -version 1.2.5beta2 [August 15, 2002] - Only issue png_warning() about "Too much data" in pngpread.c when avail_in - is nonzero. - Updated makefiles to install a separate libpng.so.3 with its own rpath. -version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] - Revised makefiles to not remove previous minor versions of shared libraries. -version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] - Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared - library loader directive. - Added missing "$OBJSDLL" line to makefile.gcmmx. - Added missing "; fi" to makefile.32sunu. -version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] - Revised libpng-config script. - -version 1.2.5 and 1.0.15 [October 3, 2002] - Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, - and makefile.aix. - Relocated two misplaced PNGAPI lines in pngtest.c -version 1.2.6beta1 [October 22, 2002] - Commented out warning about uninitialized mmx_support in pnggccrd.c. - Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. - Relocated two more misplaced PNGAPI lines in pngtest.c - Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, - introduced in version 1.0.2. - Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. -version 1.2.6beta2 [November 1, 2002] - Added libpng-config "--ldopts" output. - Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" - in makefiles. -version 1.2.6beta3 [July 18, 2004] - Reverted makefile changes from version 1.2.6beta2 and some of the changes - from version 1.2.6beta1; these will be postponed until version 1.2.7. - Version 1.2.6 is going to be a simple bugfix release. - Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. - Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. - Added "#!/bin/sh" at the top of configure, for recognition of the - 'x' flag under Cygwin (Cosmin). - Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). - Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). - Fixed the special memory handler for Borland C under DOS, in pngmem.c - (Cosmin). - Removed some spurious assignments in pngrutil.c (Cosmin). - Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings - on 16-bit platforms (Cosmin). - Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). - Used proper type png_fixed_point, to avoid problems on 16-bit platforms, - in png_handle_sRGB() (Cosmin). - Added compression_type to png_struct, and optimized the window size - inside the deflate stream (Cosmin). - Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). - Fixed handling of unknown chunks that come after IDAT (Cosmin). - Allowed png_error() and png_warning() to work even if png_ptr == NULL - (Cosmin). - Replaced row_info->rowbytes with row_bytes in png_write_find_filter() - (Cosmin). - Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). - Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded - values in png.c (Simon-Pierre, Cosmin). - Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). - Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc - (Simon-Pierre). - Moved the definition of PNG_HEADER_VERSION_STRING near the definitions - of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). - Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). - Updated scripts/makefile.vc(a)win32 (Cosmin). - Updated the MSVC project (Simon-Pierre, Cosmin). - Updated the Borland C++ Builder project (Cosmin). - Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). - Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). - Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). - Added extra guard around inclusion of Turbo C memory headers, in pngconf.h - (Cosmin). - Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to - projects/cbuilder5/ (Cosmin). - Moved projects/visualc6/png32ms.def to scripts/pngw32.def, - and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). - Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). - Changed line endings to DOS style in cbuilder5 and visualc6 files, even - in the tar.* distributions (Cosmin). - Updated contrib/visupng/VisualPng.dsp (Cosmin). - Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). - Added a separate distribution with "configure" and supporting files (Junichi). -version 1.2.6beta4 [July 28, 2004] - Added user ability to change png_size_t via a PNG_SIZE_T macro. - Added png_sizeof() and png_convert_size() functions. - Added PNG_SIZE_MAX (maximum value of a png_size_t variable. - Added check in png_malloc_default() for (size_t)size != (png_uint_32)size - which would indicate an overflow. - Changed sPLT failure action from png_error to png_warning and abandon chunk. - Changed sCAL and iCCP failures from png_error to png_warning and abandon. - Added png_get_uint_31(png_ptr, buf) function. - Added PNG_UINT_32_MAX macro. - Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. - Made png_zalloc() issue a png_warning and return NULL on potential - overflow. - Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x - Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. - Revised Borland portion of png_malloc() to return NULL or issue - png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. - Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove - sequential read support. - Added some "#if PNG_WRITE_SUPPORTED" blocks. - Removed some redundancy with #ifdef/#endif in png_malloc_default(). - Use png_malloc instead of png_zalloc to allocate the pallete. -version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] - Fixed buffer overflow vulnerability in png_handle_tRNS() - Fixed integer arithmetic overflow vulnerability in png_read_png(). - Fixed some harmless bugs in png_handle_sBIT, etc, that would cause - duplicate chunk types to go undetected. - Fixed some timestamps in the -config version - Rearranged order of processing of color types in png_handle_tRNS(). - Added ROWBYTES macro to calculate rowbytes without integer overflow. - Updated makefile.darwin and removed makefile.macosx from scripts directory. - Imposed default one million column, one-million row limits on the image - dimensions, and added png_set_user_limits() function to override them. - Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. - Fixed wrong cast of returns from png_get_user_width|height_max(). - Changed some "keep the compiler happy" from empty statements to returns, - Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution -version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] - Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. - Revised pngtest's png_debug_malloc() to use png_malloc() instead of - png_malloc_default() which is not supposed to be exported. - Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in - pngpread.c. Bug was introduced in 1.2.6rc1. - Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. - Fixed old bug in RGB to Gray transformation. - Fixed problem with 64-bit compilers by casting arguments to abs() - to png_int_32. - Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). - Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) - Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. - Added code to update the row_info->colortype in png_do_read_filler() (MSB). -version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] - Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid - trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. - Revised documentation of png_set_keep_unknown_chunks(). - Check handle_as_unknown status in pngpread.c, as in pngread.c previously. - Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h - Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c -version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] - Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of - "pinfo" was out of place). -version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] - Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED - section of png.h where they were inadvertently placed in version rc3. - -version 1.2.6 and 1.0.16 [August 15, 2004] - Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. -version 1.2.7beta1 [August 26, 2004] - Removed unused pngasmrd.h file. - Removed references to uu.net for archived files. Added references to - PNG Spec (second edition) and the PNG ISO/IEC Standard. - Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. - Fixed bug with "optimized window size" in the IDAT datastream, that - causes libpng to write PNG files with incorrect zlib header bytes. -version 1.2.7beta2 [August 28, 2004] - Fixed bug with sCAL chunk and big-endian machines (David Munro). - Undid new code added in 1.2.6rc2 to update the color_type in - png_set_filler(). - Added png_set_add_alpha() that updates color type. -version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] - Revised png_set_strip_filler() to not remove alpha if color_type has alpha. - -version 1.2.7 and 1.0.17 [September 12, 2004] - Added makefile.hp64 - Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin -version 1.2.8beta1 [November 1, 2004] - Fixed bug in png_text_compress() that would fail to complete a large block. - Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during - strip alpha operation in png_do_strip_filler(). - Added PNG_1_2_X definition in pngconf.h - Comment out with #ifdef/#endif png_info_init in png.c and png_read_init - in pngread.c (as of 1.3.0) -version 1.2.8beta2 [November 2, 2004] - Reduce color_type to a nonalpha type after strip alpha operation in - png_do_strip_filler(). -version 1.2.8beta3 [November 3, 2004] - Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM -version 1.2.8beta4 [November 12, 2004] - Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). - Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). - Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection - of data type in deflate (Cosmin). - Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of - PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. -version 1.2.8beta5 [November 20, 2004] - Use png_ptr->flags instead of png_ptr->transformations to pass - PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI - compatibility. - Revised handling of SPECIALBUILD, PRIVATEBUILD, - PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. -version 1.2.8rc1 [November 24, 2004] - Moved handling of BUILD macros from pngconf.h to png.h - Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently - omitted from beta5. - Revised scripts/pngw32.rc - Despammed mailing addresses by masking "@" with "at". - Inadvertently installed a supposedly faster test version of pngrutil.c -version 1.2.8rc2 [November 26, 2004] - Added two missing "\" in png.h - Change tests in pngread.c and pngpread.c to - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); -version 1.2.8rc3 [November 28, 2004] - Reverted pngrutil.c to version libpng-1.2.8beta5. - Added scripts/makefile.elf with supporting code in pngconf.h for symbol - versioning (John Bowler). -version 1.2.8rc4 [November 29, 2004] - Added projects/visualc7 (Simon-pierre). -version 1.2.8rc5 [November 29, 2004] - Fixed new typo in scripts/pngw32.rc - -version 1.2.8 [December 3, 2004] - Removed projects/visualc7, added projects/visualc71. - -version 1.2.9beta1 [February 21, 2006] - - Initialized some structure members in pngwutil.c to avoid gcc-4.0.0 complaints - Revised man page and libpng.txt to make it clear that one should not call - png_read_end or png_write_end after png_read_png or png_write_png. - Updated references to png-mng-implement mailing list. - Fixed an incorrect typecast in pngrutil.c - Added PNG_NO_READ_SUPPORTED conditional for making a write-only library. - Added PNG_NO_WRITE_INTERLACING_SUPPORTED conditional. - Optimized alpha-inversion loops in pngwtran.c - Moved test for nonzero gamma outside of png_build_gamma_table() in pngrtran.c - Make sure num_trans is <= 256 before copying data in png_set_tRNS(). - Make sure num_palette is <= 256 before copying data in png_set_PLTE(). - Interchanged order of write_swap_alpha and write_invert_alpha transforms. - Added parentheses in the definition of PNG_LIBPNG_BUILD_TYPE (Cosmin). - Optimized zlib window flag (CINFO) in contrib/pngsuite/*.png (Cosmin). - Updated scripts/makefile.bc32 for Borland C++ 5.6 (Cosmin). - Exported png_get_uint_32, png_save_uint_32, png_get_uint_16, png_save_uint_16, - png_get_int_32, png_save_int_32, png_get_uint_31 (Cosmin). - Added type cast (png_byte) in png_write_sCAL() (Cosmin). - Fixed scripts/makefile.cygwin (Christian Biesinger, Cosmin). - Default iTXt support was inadvertently enabled. - -version 1.2.9beta2 [February 21, 2006] - - Check for png_rgb_to_gray and png_gray_to_rgb read transformations before - checking for png_read_dither in pngrtran.c - Revised checking of chromaticity limits to accommodate extended RGB - colorspace (John Denker). - Changed line endings in some of the project files to CRLF, even in the - "Unix" tar distributions (Cosmin). - Made png_get_int_32 and png_save_int_32 always available (Cosmin). - Updated scripts/pngos2.def, scripts/pngw32.def and projects/wince/png32ce.def - with the newly exported functions. - Eliminated distributions without the "configure" script. - Updated INSTALL instructions. - -version 1.2.9beta3 [February 24, 2006] - - Fixed CRCRLF line endings in contrib/visupng/VisualPng.dsp - Made libpng.pc respect EXEC_PREFIX (D. P. Kreil, J. Bowler) - Removed reference to pngasmrd.h from Makefile.am - Renamed CHANGES to ChangeLog. - Renamed LICENSE to COPYING. - Renamed ANNOUNCE to NEWS. - Created AUTHORS file. - -version 1.2.9beta4 [March 3, 2006] - - Changed definition of PKGCONFIG from $prefix/lib to $libdir in configure.ac - Reverted to filenames LICENSE and ANNOUNCE; removed AUTHORS and COPYING. - Removed newline from the end of some error and warning messages. - Removed test for sqrt() from configure.ac and configure. - Made swap tables in pngtrans.c PNG_CONST (Carlo Bramix). - Disabled default iTXt support that was inadvertently enabled in - libpng-1.2.9beta1. - Added "OS2" to list of systems that don't need underscores, in pnggccrd.c - Removed libpng version and date from *.c files. - -version 1.2.9beta5 [March 4, 2006] - Removed trailing blanks from source files. - Put version and date of latest change in each source file, and changed - copyright year accordingly. - More cleanup of configure.ac, Makefile.ac, and associated scripts. - Restored scripts/makefile.elf which was inadvertently deleted. - -version 1.2.9beta6 [March 6, 2006] - Fixed typo (RELEASE) in configuration files. - -version 1.2.9beta7 [March 7, 2006] - Removed libpng.vers and libpng.sym from libpng12_la_SOURCES in Makefile.am - Fixed inconsistent #ifdef's around png_sig_bytes() and png_set_sCAL_s() - in png.h. - Updated makefile.elf as suggested by debian. - Made cosmetic changes to some makefiles, adding LN_SF and other macros. - Made some makefiles accept "exec_prefix". - -version 1.2.9beta8 [March 9, 2006] - Fixed some "#if defined (..." which should be "#if defined(..." - Bug introduced in libpng-1.2.8. - Fixed inconsistency in definition of png_default_read_data() - Restored blank that was lost from makefile.sggcc "clean" target in beta7. - Revised calculation of "current" and "major" for irix in ltmain.sh - Changed "mkdir" to "MKDIR_P" in some makefiles. - Separated PNG_EXPAND and PNG_EXPAND_tRNS. - Added png_set_expand_gray_1_2_4_to_8() and deprecated - png_set_gray_1_2_4_to_8() which also expands tRNS to alpha. - -version 1.2.9beta9 [March 10, 2006] - Include "config.h" in pngconf.h when available. - Added some checks for NULL png_ptr or NULL info_ptr (timeless) - -version 1.2.9beta10 [March 20, 2006] - Removed extra CR from contrib/visualpng/VisualPng.dsw (Cosmin) - Made pnggccrd.c PIC-compliant (Christian Aichinger). - Added makefile.mingw (Wolfgang Glas). - Revised pngconf.h MMX checking. - -version 1.2.9beta11 [March 22, 2006] - Fixed out-of-order declaration in pngwrite.c that was introduced in beta9 - Simplified some makefiles by using LIBSO, LIBSOMAJ, and LIBSOVER macros. - -version 1.2.9rc1 [March 31, 2006] - Defined PNG_USER_PRIVATEBUILD when including "pngusr.h" (Cosmin). - Removed nonsensical assertion check from pngtest.c (Cosmin). - -version 1.2.9 [April 14, 2006] - Revised makefile.beos and added "none" selector in ltmain.sh - -version 1.2.10beta1 [April 15, 2006] - Renamed "config.h" to "png_conf.h" and revised Makefile.am to add - -DPNG_BUILDING_LIBPNG to compile directive, and modified pngconf.h - to include png_conf.h only when PNG_BUILDING_LIBPNG is defined. - -version 1.2.10beta2 [April 15, 2006] - Manually updated Makefile.in and configure. Changed png_conf.h.in - back to config.h. - -version 1.2.10beta3 [April 15, 2006] - Change png_conf.h back to config.h in pngconf.h. - -version 1.2.10beta4 [April 16, 2006] - Change PNG_BUILDING_LIBPNG to PNG_CONFIGURE_LIBPNG in config/Makefile*. - -version 1.2.10beta5 [April 16, 2006] - Added a configure check for compiling assembler code in pnggccrd.c - -version 1.2.10beta6 [April 17, 2006] - Revised the configure check for pnggccrd.c - Moved -DPNG_CONFIGURE_LIBPNG into @LIBPNG_DEFINES@ - Added @LIBPNG_DEFINES@ to arguments when building libpng.sym - -version 1.2.10beta7 [April 18, 2006] - Change "exec_prefix=$prefix" to "exec_prefix=$(prefix)" in makefiles. - -version 1.2.10rc1 [April 19, 2006] - Ensure pngconf.h doesn't define both PNG_USE_PNGGCCRD and PNG_USE_PNGVCRD - Fixed "LN_FS" typo in makefile.sco and makefile.solaris. - -version 1.2.10rc2 [April 20, 2006] - Added a backslash between -DPNG_CONFIGURE_LIBPNG and -DPNG_NO_ASSEMBLER_CODE - in configure.ac and configure - Made the configure warning about versioned symbols less arrogant. - -version 1.2.10rc3 [April 21, 2006] - Added a note in libpng.txt that png_set_sig_bytes(8) can be used when - writing an embedded PNG without the 8-byte signature. - Revised makefiles and configure to avoid making links to libpng.so.* - -version 1.2.10 [April 23, 2006] - Reverted configure to "rc2" state. - -version 1.2.11beta1 [May 31, 2006] - scripts/libpng.pc.in contained "configure" style version info and would - not work with makefiles. - The shared-library makefiles were linking to libpng.so.0 instead of - libpng.so.3 compatibility as the library. - -version 1.2.11beta2 [June 2, 2006] - Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - Fixed bug in example.c (png_set_palette_rgb -> png_set_palette_to_rgb) - -version 1.2.11beta3 [June 5, 2006] - Prepended "#! /bin/sh" to ltmail.sh and contrib/pngminus/*.sh (Cosmin). - Removed the accidental leftover Makefile.in~ (Cosmin). - Avoided potential buffer overflow and optimized buffer in - png_write_sCAL(), png_write_sCAL_s() (Cosmin). - Removed the include directories and libraries from CFLAGS and LDFLAGS - in scripts/makefile.gcc (Nelson A. de Oliveira, Cosmin). - -version 1.2.11beta4 [June 6, 2006] - Allow zero-length IDAT chunks after the entire zlib datastream, but not - after another intervening chunk type. - -version 1.0.19rc1, 1.2.11rc1 [June 13, 2006] - Deleted extraneous square brackets from [config.h] in configure.ac - -version 1.0.19rc2, 1.2.11rc2 [June 14, 2006] - Added prototypes for PNG_INCH_CONVERSIONS functions to png.h - Revised INSTALL and autogen.sh - Fixed typo in several makefiles (-W1 should be -Wl) - Added typedef for png_int_32 and png_uint_32 on 64-bit systems. - -version 1.0.19rc3, 1.2.11rc3 [June 15, 2006] - Removed the new typedefs for 64-bit systems (delay until version 1.4.0) - Added one zero element to png_gamma_shift[] array in pngrtran.c to avoid - reading out of bounds. - -version 1.0.19rc4, 1.2.11rc4 [June 15, 2006] - Really removed the new typedefs for 64-bit systems. - -version 1.0.19rc5, 1.2.11rc5 [June 22, 2006] - Removed png_sig_bytes entry from scripts/pngw32.def - -version 1.0.19, 1.2.11 [June 26, 2006] - None. - -version 1.0.20, 1.2.12 [June 27, 2006] - Really increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid - buffer overflow. - -version 1.2.13beta1 [October 2, 2006] - Removed AC_FUNC_MALLOC from configure.ac - Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h - Change "logical" to "bitwise" throughout documentation. - Detect and fix attempt to write wrong iCCP profile length. - -version 1.0.21, 1.2.13 [November 14, 2006] - Fix potential buffer overflow in sPLT chunk handler. - Fix Makefile.am to not try to link to noexistent files. - Check all exported functions for NULL png_ptr. - -version 1.2.14beta1 [November 17, 2006] - Relocated three misplaced tests for NULL png_ptr. - Built Makefile.in with automake-1.9.6 instead of 1.9.2. - Build configure with autoconf-2.60 instead of 2.59 - -version 1.2.14beta2 [November 17, 2006] - Added some typecasts in png_zalloc(). - -version 1.2.14rc1 [November 20, 2006] - Changed "strtod" to "png_strtod" in pngrutil.c - -version 1.0.22, 1.2.14 [November 27, 2006] - Added missing "$(srcdir)" in Makefile.am and Makefile.in - -version 1.2.15beta1 [December 3, 2006] - Generated configure with autoconf-2.61 instead of 2.60 - Revised configure.ac to update libpng.pc and libpng-config. - -version 1.2.15beta2 [December 3, 2006] - Always export MMX asm functions, just stubs if not building pnggccrd.c - -version 1.2.15beta3 [December 4, 2006] - Add "png_bytep" typecast to profile while calculating length in pngwutil.c - -version 1.2.15beta4 [December 7, 2006] - Added scripts/CMakeLists.txt - Changed PNG_NO_ASSEMBLER_CODE to PNG_NO_MMX_CODE in scripts, like 1.4.0beta - -version 1.2.15beta5 [December 7, 2006] - Changed some instances of PNG_ASSEMBLER_* to PNG_MMX_* in pnggccrd.c - Revised scripts/CMakeLists.txt - -version 1.2.15beta6 [December 13, 2006] - Revised scripts/CMakeLists.txt and configure.ac - -version 1.2.15rc1 [December 18, 2006] - Revised scripts/CMakeLists.txt - -version 1.2.15rc2 [December 21, 2006] - Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. - Added scripts/makefile.nommx - -version 1.2.15rc3 [December 25, 2006] - Fixed shared library numbering error that was introduced in 1.2.15beta6. - -version 1.2.15rc4 [December 27, 2006] - Fixed handling of rgb_to_gray when png_ptr->color.gray isn't set. - -version 1.2.15rc5 [December 31, 2006] - Revised handling of rgb_to_gray. - -version 1.0.23, 1.2.15 [January 5, 2007] - Added some (unsigned long) typecasts in pngtest.c to avoid printing errors. - -version 1.2.16beta1 [January 6, 2007] - Fix bugs in makefile.nommx - -version 1.2.16beta2 [January 16, 2007] - Revised scripts/CMakeLists.txt - -version 1.0.24, 1.2.16 [January 31, 2007] - No changes. - -version 1.2.17beta1 [March 6, 2007] - Revised scripts/CMakeLists.txt to install both shared and static libraries. - Deleted a redundant line from pngset.c. - -version 1.2.17beta2 [April 26, 2007] - Relocated misplaced test for png_ptr == NULL in pngpread.c - Change "==" to "&" for testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN - flags. - Changed remaining instances of PNG_ASSEMBLER_* to PNG_MMX_* - Added pngerror() when write_IHDR fails in deflateInit2(). - Added "const" to some array declarations. - Mention examples of libpng usage in the libpng*.txt and libpng.3 documents. - -version 1.2.17rc1 [May 4, 2007] - No changes. - -version 1.2.17rc2 [May 8, 2007] - Moved several PNG_HAVE_* macros out of PNG_INTERNAL because applications - calling set_unknown_chunk_location() need them. - Changed transformation flag from PNG_EXPAND_tRNS to PNG_EXPAND in - png_set_expand_gray_1_2_4_to_8(). - Added png_ptr->unknown_chunk to hold working unknown chunk data, so it - can be free'ed in case of error. Revised unknown chunk handling in - pngrutil.c and pngpread.c to use this structure. - -version 1.2.17rc3 [May 8, 2007] - Revised symbol-handling in configure script. - -version 1.2.17rc4 [May 10, 2007] - Revised unknown chunk handling to avoid storing unknown critical chunks. - -version 1.0.25 [May 15, 2007] -version 1.2.17 [May 15, 2007] - Added "png_ptr->num_trans=0" before error return in png_handle_tRNS, - to eliminate a vulnerability (CVE-2007-2445, CERT VU#684664) - -version 1.0.26 [May 15, 2007] -version 1.2.18 [May 15, 2007] - Reverted the libpng-1.2.17rc3 change to symbol-handling in configure script - -version 1.2.19beta1 [May 18, 2007] - Changed "const static" to "static PNG_CONST" everywhere, mostly undoing - change of libpng-1.2.17beta2. Changed other "const" to "PNG_CONST" - Changed some handling of unused parameters, to avoid compiler warnings. - "if (unused == NULL) return;" becomes "unused = unused". - -version 1.2.19beta2 [May 18, 2007] - Only use the valid bits of tRNS value in png_do_expand() (Brian Cartier) - -version 1.2.19beta3 [May 19, 2007] - Add some "png_byte" typecasts in png_check_keyword() and write new_key - instead of key in zTXt chunk (Kevin Ryde). - -version 1.2.19beta4 [May 21, 2007] - Add png_snprintf() function and use it in place of sprint() for improved - defense against buffer overflows. - -version 1.2.19beta5 [May 21, 2007] - Fixed png_handle_tRNS() to only use the valid bits of tRNS value. - Changed handling of more unused parameters, to avoid compiler warnings. - Removed some PNG_CONST in pngwutil.c to avoid compiler warnings. - -version 1.2.19beta6 [May 22, 2007] - Added some #ifdef PNG_MMX_CODE_SUPPORTED where needed in pngvcrd.c - Added a special "_MSC_VER" case that defines png_snprintf to _snprintf - -version 1.2.19beta7 [May 22, 2007] - Squelched png_squelch_warnings() in pnggccrd.c and added - an #ifdef PNG_MMX_CODE_SUPPORTED/#endif block around the declarations - that caused the warnings that png_squelch_warnings was squelching. - -version 1.2.19beta8 [May 22, 2007] - Removed __MMX__ from test in pngconf.h. - -version 1.2.19beta9 [May 23, 2007] - Made png_squelch_warnings() available via PNG_SQUELCH_WARNINGS macro. - Revised png_squelch_warnings() so it might work. - Updated makefile.sgcc and makefile.solaris; added makefile.solaris-x86. - -version 1.2.19beta10 [May 24, 2007] - Resquelched png_squelch_warnings(), use "__attribute__((used))" instead. - -version 1.2.19beta11 [May 28, 2007] - Return 0 from png_get_sPLT() and png_get_unknown_chunks() if png_ptr is NULL; - changed three remaining instances of png_strcpy() to png_strncpy() (David - Hill). - Make test for NULL row_buf at the beginning of png_do_read_transformations - unconditional. - -version 1.2.19beta12 [May 28, 2007] - Revised pnggccrd.c. - -version 1.2.19beta13 [June 14, 2007] - Prefer PNG_USE_PNGVCRD when _MSC_VER is defined in pngconf.h - -version 1.2.19beta14 [June 16, 2007] - Fix bug with handling of 16-bit transparency, introduced in 1.2.19beta2 - -version 1.2.19beta15 [June 17, 2007] - Revised pnggccrd.c. - -version 1.2.19beta16 [June 18, 2007] - Revised pnggccrd.c again. - Updated contrib/gregbook. - Changed '#include "pnggccrd.c"' to 'include "$srcdir/pnggccrd.c"' - in configure.ac - -version 1.2.19beta17 [June 19, 2007] - Revised many of the makefiles, to set -DPNG_NO_MMX_CODE where needed - and to not use -O3 unless -DPNG_NO_MMX_CODE is also set. - -version 1.2.19beta18 [June 23, 2007] - Replaced some C++ style comments with C style comments in pnggccrd.c. - Copied optimized C code from pnggccrd.c to pngrutil.c, removed dependency - on pnggccrd.o from many makefiles. - Added sl and dylib to list of extensions be installed by Makefile.am - -version 1.2.19beta19 [June 28, 2007] - Fixed testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN in pngrtran.c - More cleanup of pnggccrd.c and pngvcrd.c - -version 1.2.19beta20 [June 29, 2007] - Rebuilt Makefile.in and configure using libtool-1.5.24. - Fixed typo in pnggccrd.c - -version 1.2.19beta21 [June 30, 2007] - More revision of pnggccrd.c - Added "test" target to Makefile.in and Makefile.am - -version 1.2.19beta22 [July 3, 2007] - Added info about pngrutil/pnggccrd/pngvcrd to png_get_header_version() - Fix type definition of dummy_value_a, b in pnggccrd.c - -version 1.2.19beta23 [July 10, 2007] - Revert change to type definition of dummy_value_a, b in pnggccrd.c - Make sure __PIC__ is defined in pnggccrd.c when PIC is defined. - Require gcc-4.1 or better to use PNG_HAVE_MMX_FILTER_ROW on x86_64 platforms - -version 1.2.19beta24 [July 14, 2007] - Added PNG_NO_READ_FILTER, PNG_NO_WRITE_FILTER, PNG_NO_WARNING macros. - Added contrib/pngminim to demonstrate building minimal encoder and decoder - -version 1.2.19beta25 [July 15, 2007] - Removed the new PNG_NO_READ_FILTER macro since it would make the library - unable to read valid PNG files, and filtering is at the heart of the - PNG format. - -version 1.2.19beta26 [July 16, 2007] - Changed "png_free(str)" to "png_free(png_ptr,str)" in pngrutil.c WinCE - code (Yves Piguet). This bug was introduced in libpng-1.2.14. - Updated scripts/CMakeLists.txt - Relocated a misplaced #endif in pnggccrd.c - -version 1.2.19beta27 [July 17, 2007] - Fixed incorrect stride and number of bytes copied (was 4 instead of - 6 bytes) in the cleanup loop of pnggccrd.c and pngvcrd.c for handling - the end of 48-bit interlaced rows (Glenn R-P). - -version 1.2.19beta28 [July 19, 2007] - Removed requirement for gcc-4.1 or better to use PNG_HAVE_MMX_FILTER_ROW - on x86_64 platforms - Added png_warning() in pngrutil.c for short iCCP, iTXt, sPLT, or zTXT chunks. - Revised pngtest.c so warnings are displayed regardless of PNG_NO_STDIO. - -version 1.2.19beta29 [July 20, 2007] - Fix typo in pnggccrd.c (%%eax should be %%ax in secondloop48) - -version 1.2.19beta30 [July 26, 2007] - Revised pnggccrd.c - -version 1.2.19beta31 [July 27, 2007] - Fix typos in pnggccrd.c - -version 1.0.27rc1 and 1.2.19rc1 [July 31, 2007] - Disable PNG_MMX_CODE_SUPPORTED when PNG_ASSEMBLER_CODE_SUPPORTED is off. - Enable PNG_MMX_READ_FILTER_* by default, except when gcc-3.x is being - used (they were inadvertently disabled in libpng-1.2.19beta23). - Fix some debugging statements in pnggccrd.c and pngrutil.c - Added information about disabling the MMX code in libpng documentation. - -version 1.0.27rc2 and 1.2.19rc2 [August 4, 2007] - Removed some "#if 0" blocks. - Made a global struct local in pngvcrd.c to make it thread safe. - Issue a png_error() if application attempts to transform a row tht - has not been initialized. - -version 1.0.27rc3 and 1.2.19rc3 [August 9, 2007] - Slightly revised pngvcrd.c - -version 1.0.27rc4 and 1.2.19rc4 [August 9, 2007] - Revised pnggccrd.c debugging change of rc1, which was broken. - Revised scripts/CMakeLists.txt - Change default to PNG_NO_GLOBAL_ARRAYS for MSVC. - Turn off PNG_FLAG_ROW_INIT flag when setting transforms that expand pixels. - -version 1.0.27rc5 and 1.2.19rc5 [August 10, 2007] - Fix typo (missing '"') in pnggccrd.c - Revise handling of png_strtod in recent versions of WINCE - -version 1.0.27rc6 and 1.2.19rc6 [August 15, 2007] - Fix typo (missing ',') in contrib/gregbook/readpng2.c - Undid row initialization error exit added to rc2 and rc4. - -version 1.0.27 and 1.2.19 [August 18, 2007] - Conditionally restored row initialization error exit. - -version 1.2.20beta01 [August 19, 2007] - Fixed problem with compiling pnggccrd.c on Intel-Apple platforms. - Changed png_malloc() to png_malloc_warn() in png_set_sPLT(). - Added PNG_NO_ERROR_TEXT feature, with demo in contrib/pngminim - Removed define PNG_WARN_UNINITIALIZED_ROW 1 /* 0: warning; 1: error */ - because it caused some trouble. - -version 1.2.20beta02 [August 20, 2007] - Avoid compiling pnggccrd.c on Intel-Apple platforms. - -version 1.2.20beta03 [August 20, 2007] - Added "/D PNG_NO_MMX_CODE" to the non-mmx builds of projects/visualc6 - and visualc71. - -version 1.2.20beta04 [August 21, 2007] - Revised pngvcrd.c for improved efficiency (Steve Snyder). - -version 1.2.20rc1 [August 23, 2007] - Revised pngconf.h to set PNG_NO_MMX_CODE for gcc-3.x compilers. - -version 1.2.20rc2 [August 27, 2007] - Revised scripts/CMakeLists.txt - Revised #ifdefs to ensure one and only one of pnggccrd.c, pngvcrd.c, - or part of pngrutil.c is selected. - -version 1.2.20rc3 [August 30, 2007] - Remove a little more code in pngwutil.c when PNG_NO_WRITE_FILTER is selected. - Added /D _CRT_SECURE_NO_WARNINGS to visual6c and visualc71 projects. - Compile png_mmx_support() in png.c even when PNG_NO_MMX_CODE is defined. - Restored a "superfluous" #ifdef that was removed from 1.2.20rc2 pnggccrd.c, - breaking the png_mmx_support() function. - -version 1.2.20rc4 [September 1, 2007] - Removed Intel contributions (MMX, Optimized C). - -version 1.2.20rc5 [September 2, 2007] - Restored configure and Makefile.in to rc3 and put a snippet of code in - pnggccrd.c, to ensure configure makes the same PNG_NO_MMX_CODE selection - -version 1.2.20rc6 [September 2, 2007] - Fixed bugs in scripts/CMakeLists.txt - Removed pngvcrd.c references from msvc projects. - -version 1.0.28 and 1.2.20 [September 8, 2007] - Removed "(NO READ SUPPORT)" from png_get_header_version() string. - -version 1.2.21beta1 [September 14, 2007] - Fixed various mistakes reported by George Cook and Jeff Phillips: - logical vs bitwise NOT in pngrtran.c, bug introduced in 1.2.19rc2 - 16-bit cheap transparency expansion, bug introduced in 1.2.19beta2 - errors with sizeof(unknown_chunk.name), bugs introduced in 1.2.19beta11 - <= compare with unsigned var in pngset.c, should be ==. - -version 1.2.21beta2 [September 18, 2007] - Removed some extraneous typecasts. - -version 1.2.21rc1 [September 25, 2007] - Fixed potential out-of-bounds reads in png_handle_pCAL() and - png_handle_ztXt() ("flayer" results reported by Tavis Ormandy). - -version 1.2.21rc2 [September 26, 2007] - Fixed potential out-of-bounds reads in png_handle_sCAL(), - png_handle_iTXt(), and png_push_read_tEXt(). - Remove some PNG_CONST declarations from pngwutil.c to avoid compiler warnings - Revised makefiles to update paths in libpng.pc properly. - -version 1.2.21rc3 [September 27, 2007] - Revised makefiles to update "Libs" in libpng.pc properly. - -version 1.0.29 and 1.2.21rc3 [October 4, 2007] - No changes. - -version 1.2.22beta1 [October 4, 2007] - Again, fixed logical vs bitwise NOT in pngrtran.c, bug introduced - in 1.2.19rc2 - -version 1.2.22beta2 [October 5, 2007] - Fixed string length error in pngset.c (caused crashes while decoding iCCP) - Add terminating NULL after each instance of png_strncpy(). - -version 1.2.22beta3 [October 6, 2007] - Fix two off-by-one terminating NULL after png_strncpy(). - -version 1.2.22beta4 [October 7, 2007] - Changed some 0 to '\0'. - -version 1.0.30rc1 and 1.2.22rc1 [October 8, 2007] - No changes. - -version 1.0.30 and 1.2.22 [October 13, 2007] - No changes. - -version 1.2.23beta01 [October 15, 2007] - Reduced number of invocations of png_strlen() in pngset.c. - Changed [azAZ09_] to [_abcde...89] in Makefile.am for better localization. - -version 1.2.23beta02 [October 16, 2007] - Eliminated png_strncpy() and png_strcpy() (Pierre Poissinger) - Changed $AN to $(AN) in Makefile.am. - -version 1.2.23beta03 [October 16, 2007] - Fixed off-by-one error in pngset.c - Restore statement to set last character of buffer to \0 in pngerror.c - -version 1.2.23beta04 [October 23, 2007] - Reject attempt to set all-zero cHRM values. - -version 1.2.23beta05 [October 26, 2007] - Add missing quotes in projects/visualc6, lost in version 1.2.20rc3 - -version 1.2.23rc01 [November 2, 2007] - No changes. - -version 1.2.23 [November 6, 2007] - No changes. - -version 1.2.24beta01 [November 19, 2007] - Moved misplaced test for malloc failure in png_set_sPLT(). This bug was - introduced in libpng-1.2.20beta01. - Ifdef out avg_row etc from png.h and pngwrite.c when PNG_NO_WRITE_FILTER - Do not use png_ptr->free_fn and png_ptr->mem_fn in png_destroy_read_struct() - when png_ptr is NULL (Marshall Clow). - Updated handling of symbol prefixes in Makefile.am and configure.ac (Mike - Frysinger). - -version 1.2.24beta02 [November 30, 2007] - Removed a useless test and fixed incorrect test in png_set_cHRM_fixed() - (David Hill). - -version 1.2.24rc01 [December 7, 2007] - No changes. - -version 1.2.24 [December 14, 2007] - Make sure not to redefine _BSD_SOURCE in pngconf.h - Revised gather.sh and makefile.std in contrib/pngminim to avoid compiling - unused files. - -version 1.2.25beta01 [January 7, 2008] - Fixed bug with unknown chunk handling, introduced in version 1.2.17rc2 - -version 1.2.25beta02 [January 10, 2008] - Prevent gamma from being applied twice. - -version 1.2.25rc01 [January 17, 2008] - No changes. - -version 1.2.25beta03 [January 22, 2008] - Fixed some continue-after-malloc-failure errors in pngset.c (David Hill) - Check for info_ptr == NULL in png_read_info() and png_process_data(). - Check for possible use of NULL user_png_ver[] in png_create_read_struct(). - Change "if (swidth == NULL)" to "if (sheight == NULL)" in png_handle_sCAL - (bug introduced in libpng-1.2.4/1.0.13). - Return from png_destroy_read_struct() if png_ptr_ptr is NULL. - Fix overflow of "msg" in png_decompress_chunk(). - -version 1.2.25beta04 [January 26, 2008] - Work around Coverity bug report by slightly refactoring - png_read_push_finish_row() - -version 1.2.25beta05 [January 31, 2008] - Added libpng-1.2.25beta05.tar.lzma to distribution. Get the lzma codec - from . - Added lp1225b05.7z to distribution. Get the 7-zip decoder from - from . - Fixed some broken links in the README file. - -version 1.2.25beta06 [February 6, 2008] - Refactored png_read_push_finish_row() again, trying to satisfy Coverity. - Fixed potential NULL dereference of png_ptr in png_destroy_write_struct(); - clarified potential NULL dereference of png_ptr in png_destroy_read_struct(); - fixed potential NULL dereference of info_ptr in png_handle_bKGD(); - fixed potential NULL dereference of user_png_ver[] in - png_create_write_struct_2(). (Coverity) - -version 1.2.25rc02 [February 10, 2008] - Reset png_ptr->pass in png_read_push_finish_row() before break. - Changed "pass" from png_byte to int. - -version 1.2.25 and 1.0.31 [February 18, 2008] - No changes. - -version 1.2.26beta01 [February 21, 2008] - Added missing "(" in pngmem.c. Bug introduced in libpng-1.2.2/1.0.13 - -version 1.2.26beta02 [March 12, 2008] - Refined error message returned from deflateInit2 in pngwutil.c - Check IHDR length in png_push_read_chunk() before saving it. - -version 1.2.26beta03 [March 16, 2008] - Revised contrib/gregbook to handle premature end-of-file and file - read errors correctly. - -version 1.2.26beta04 [March 18, 2008] - Free png_ptr->big_row_buf and png_ptr->prev_row before allocating - new copies in png_read_start_row(). Bug introduced in libpng-1.2.22. - -version 1.2.26beta05 [March 19, 2008] - Removed extra png_free() added in libpng-1.2.26beta04. - -version 1.2.26beta06 [March 19, 2008] - Avoid reallocating big_row_buf and prev_row when the size does not increase. - -version 1.2.26rc01 [March 26, 2008] - Ifdef out some code that is unused when interlacing is not supported. - -versions 1.0.32 and 1.2.26 [April 2, 2008] - No changes. - -version 1.2.27beta01 [April 12, 2008] - Fixed bug (introduced in libpng-1.0.5h) with handling zero-length - unknown chunks. - Added more information about png_set_keep_unknown_chunks() to the - documentation. - Reject tRNS chunk with out-of-range samples instead of masking off - the invalid high bits as done in since libpng-1.2.19beta5. - -version 1.2.27beta02 [April 13, 2008] - Revised documentation about unknown chunk and user chunk handling. - Keep tRNS chunk with out-of-range samples and issue a png_warning(). - -version 1.2.27beta03 [April 14, 2008] - Added check for NULL ptr in TURBOC version of png_free_default(). - Removed several unnecessary checks for NULL before calling png_free(). - Revised png_set_tRNS() so that calling it twice removes and invalidates - the previous call. - Revised pngtest to check for out-of-range tRNS samples. - -version 1.2.27beta04 [April 18, 2008] - Added AC_LIBTOOL_WIN32_DLL to configure.ac - Rebuilt Makefile.in, aclocal.m4, and configure with autoconf-2.62 - -version 1.2.27beta05 [April 19, 2008] - Added MAINTAINERCLEANFILES variable to Makefile.am - -version 1.2.27beta06 [April 21, 2008] - Avoid changing color_type from GRAY to RGB by - png_set_expand_gray_1_2_4_to_8(). - -version 1.2.27rc01 [April 23, 2008] - Fix broken URL for rfc2083 in png.5 and libpng-*.txt - -version 1.0.33 and 1.2.27 [April 30, 2008] - No changes. - -version 1.0.34 and 1.2.28 [April 30, 2008] - Rebuilt Makefile.in, aclocal.m4, and configure with autoconf-2.61 - due to backward incompatibilities. - Removed a stray object file from contrib/gregbook - -version 1.2.29beta01 [May 1, 2008] - Removed some stray *.diff and *.orig files - -version 1.2.29beta02 [May 1, 2008] - Reverted Makefile.in, aclocal.m4, and configure to the libpng-1.2.26 - versions. - -version 1.2.29beta03 [May 2, 2008] - Added --force to autogen libtoolize options and --force-missing to - automake options. - Changed $(ECHO) to echo in Makefile.am and Makefile.in - Updated all configure files to autoconf-2.62 - Comment out pnggcrd.c code with #ifdef/#endif if using MSC_VER - -version 1.2.29rc01 [May 4, 2008] - No changes. - -version 1.0.35 and 1.2.29 [May 8, 2008] - No changes. - -version 1.0.37 [May 9, 2008] - Updated Makefile.in and configure (omitted version 1.0.36). - -version 1.2.30beta01 [May 29, 2008] - Updated libpng.pc-configure.in and libpng-config.in per debian bug reports. - -version 1.2.30beta02 [June 25, 2008] - Restored png_flush(png_ptr) at the end of png_write_end(), that was - removed from libpng-1.0.9beta03. - -version 1.2.30beta03 [July 6, 2008] - Merged some cosmetic whitespace changes from libpng-1.4.0beta19. - Inline call of png_get_uint_32() in png_get_uint_31(), as in 1.4.0beta19. - Added demo of decoding vpAg and sTER chunks to pngtest.c, from 1.4.0beta19. - Changed PNGMAJ from 0 to 12 in makefile.darwin, which does not like 0. - Added new private function png_read_chunk_header() from 1.4.0beta19. - Merge reading of chunk length and chunk type into a single 8-byte read. - Merge writing of chunk length and chunk type into a single 8-byte write. - -version 1.2.30beta04 [July 10, 2008] - Merged more cosmetic whitespace changes from libpng-1.4.0beta19. - -version 1.0.38rc01, 1.2.30rc01 [July 18, 2008] - No changes. - -version 1.0.38rc02, 1.2.30rc02 [July 21, 2008] - Moved local array "chunkdata" from pngrutil.c to the png_struct, so - it will be freed by png_read_destroy() in case of a read error (Kurt - Christensen). - -version 1.0.38rc03, 1.2.30rc03 [July 21, 2008] - Changed "purpose" and "buffer" to png_ptr->chunkdata to avoid memory leaking. - -version 1.0.38rc04, 1.2.30rc04 [July 22, 2008] - Changed "chunkdata = NULL" to "png_ptr->chunkdata = NULL" several places in - png_decompress_chunk(). - -version 1.0.38rc05, 1.2.30rc05 [July 25, 2008] - Changed all remaining "chunkdata" to "png_ptr->chunkdata" in - png_decompress_chunk() and remove chunkdata from parameter list. - Put a call to png_check_chunk_name() in png_read_chunk_header(). - Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. - Removed two calls to png_check_chunk_name() occuring later in the process. - -version 1.0.38rc06, 1.2.30rc06 [July 29, 2008] - Added a call to png_check_chunk_name() in pngpread.c - Reverted png_check_chunk_name() to accept a name with a lowercase 3rd byte. - -version 1.0.38r07, 1.2.30r07 [August 2, 2008] - Changed "-Wall" to "-W -Wall" in the CFLAGS in all makefiles (Cosmin Truta) - Declared png_ptr "volatile" in pngread.c and pngwrite.c to avoid warnings. - Added code in pngset.c to quiet compiler warnings. - Updated contrib/visupng/cexcept.h to version 2.0.1 - Relocated a misplaced "#endif /* PNG_NO_WRITE_FILTER */" in pngwutil.c - -version 1.0.38r08, 1.2.30r08 [August 2, 2008] - Enclose "volatile" declarations in #ifdef PNG_SETJMP_SUPPORTED (Cosmin). - -version 1.0.38, 1.2.30 [August 14, 2008] - No changes. - -version 1.2.31rc01 [August 19, 2008] - Removed extra crc check at the end of png_handle_cHRM(). Bug introduced - in libpng-1.2.30beta03 (Heiko Nitzsche). - -version 1.2.31rc02 [August 19, 2008] - Added PNG_WRITE_FLUSH_SUPPORTED block around new png_flush() call. - -version 1.2.31rc03 [August 19, 2008] - Added PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED block, off by default, around - new png_flush(). - -version 1.0.39, 1.2.31 [August 21, 2008] - No changes. - -version 1.2.32beta01 [September 6, 2008] - Shortened tIME_string to 29 bytes in pngtest.c (bug introduced in - libpng-1.2.22). - Fixed off-by-one error introduced in png_push_read_zTXt() function in - libpng-1.2.30beta04/pngpread.c (Harald van Dijk) - These bugs have been given the vulnerability id CVE-2008-3964. - -version 1.0.40, 1.2.32 [September 18, 2008] - No changes. - -version 1.2.33beta01 [October 6, 2008] - Revised makefile.darwin to fix shared library numbering. - Change png_set_gray_1_2_4_to_8() to png_set_expand_gray_1_2_4_to_8() - in example.c (debian bug report) - -version 1.2.33rc01 [October 15, 2008] - No changes. - -version 1.0.41rc01, version 1.2.33rc02 [October 23, 2008] - Changed remaining "key" to "png_ptr->chunkdata" in png_handle_tEXt() - to avoid memory leak after memory failure while reading tEXt chunk.` - -version 1.2.33 [October 31, 2008] - No changes. - -version 1.2.34beta01 [November 27, 2008] - Revised png_warning() to write its message on standard output by default - when warning_fn is NULL. This was the behavior prior to libpng-1.2.9beta9. - Fixed string vs pointer-to-string error in png_check_keyword(). - Added png_check_cHRM_fixed() in png.c and moved checking from pngget.c, - pngrutil.c, and pngwrite.c, and eliminated floating point cHRM checking. - Added check for zero-area RGB cHRM triangle in png_check_cHRM_fixed(). - In png_check_cHRM_fixed(), ensure white_y is > 0, and removed redundant - check for all-zero coordinates that is detected by the triangle check. - Revised png_warning() to write its message on standard output by default - when warning_fn is NULL. - -version 1.2.34beta02 [November 28, 2008] - Corrected off-by-one error in bKGD validity check in png_write_bKGD() - and in png_handle_bKGD(). - -version 1.2.34beta03 [December 1, 2008] - Revised bKGD validity check to use >= x instead of > x + 1 - Merged with png_debug from libpng-1.4.0 to remove newlines. - -version 1.2.34beta04 [December 2, 2008] - More merging with png_debug from libpng-1.4.0 to remove newlines. - -version 1.2.34beta05 [December 5, 2008] - Removed redundant check for key==NULL before calling png_check_keyword() - to ensure that new_key gets initialized and removed extra warning - (Arvan Pritchard). - -version 1.2.34beta06 [December 9, 2008] - In png_write_png(), respect the placement of the filler bytes in an earlier - call to png_set_filler() (Jim Barry). - -version 1.2.34beta07 [December 9, 2008] - Undid previous change and added PNG_TRANSFORM_STRIP_FILLER_BEFORE and - PNG_TRANSFORM_STRIP_FILLER_AFTER conditionals and deprecated - PNG_TRANSFORM_STRIP_FILLER (Jim Barry). - -version 1.0.42rc01, 1.2.34rc01 [December 11, 2008] - No changes. - -version 1.0.42, 1.2.34 [December 18, 2008] - No changes. - -version 1.2.35beta01 [February 4, 2009] - Zero out some arrays of pointers after png_malloc(). (Tavis Ormandy) - -version 1.2.35beta02 [February 4, 2009] - Zero out more arrays of pointers after png_malloc(). - -version 1.2.35beta03 [February 5, 2009] - Use png_memset() instead of a loop to intialize pointers. We realize - this will not work on platforms where the NULL pointer is not all zeroes. - -version 1.2.35rc01 [February 11, 2009] - No changes. - -version 1.2.35rc02 [February 12, 2009] - Fix typo in new png_memset call in pngset.c (png_color should be png_charp) - -version 1.0.43 and 1.2.35 [February 14, 2009] - No changes. - -version 1.2.36beta01 [February 28, 2009] - Revised comments in png_set_read_fn() and png_set_write_fn(). - Revised order of #ifdef's and indentation in png_debug definitions of png.h - bug introduced in libpng-1.2.34. - -version 1.2.36beta02 [March 21, 2009] - Use png_memset() after png_malloc() of big_row_buf when reading an - interlaced file, to avoid a possible UMR. - Undid recent revision of PNG_NO_STDIO version of png_write_flush(). Users - having trouble with fflush() can build with PNG_NO_WRITE_FLUSH defined. - Revised libpng*.txt documentation about use of png_write_flush(). - Removed fflush() from pngtest.c. - Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h - -version 1.2.36beta03 [March 27, 2009] - Relocated misplaced PNG_1_0_X define in png.h that caused the prototype - for png_set_strip_error_numbers() to be omitted from PNG_NO_ASSEMBLER_CODE - builds. This bug was introduced in libpng-1.2.15beta4. - Added a section on differences between 1.0.x and 1.2.x to libpng.3/libpng.txt - -version 1.2.36beta04 [April 5, 2009] - Fixed potential memory leak of "new_name" in png_write_iCCP() (Ralph Giles) - -version 1.2.36beta05 [April 24, 2009] - Added "ifndef PNG_SKIP_SETJMP_CHECK" block in pngconf.h to allow - application code writers to bypass the check for multiple inclusion - of setjmp.h when they know that it is safe to ignore the situation. - Made some cosmetic changes to whitespace in pngtest output. - Renamed "user_chunk_data" to "my_user_chunk_data" in pngtest.c to suppress - "shadowed declaration" warning from gcc-4.3.3. - Renamed "gamma" to "png_gamma" in pngset.c to avoid "shadowed declaration" - warning about a global "gamma" variable in math.h on some platforms. - -version 1.2.36rc01 [April 30, 2009] - No changes. - -version 1.0.44 and 1.2.36 [May 7, 2009] - No changes. - -version 1.2.37beta01 [May 14, 2009] - Fixed inconsistency in pngrutil.c, introduced in libpng-1.2.36. The - memset() was using "png_ptr->rowbytes" instead of "row_bytes", which - the corresponding png_malloc() uses (Joe Drew). - Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri) - Updated some of the makefiles in the scripts directory (merged with - those in libpng-1.4.0beta57). - -version 1.2.37beta02 [May 19, 2009] - Fixed typo in libpng documentation (FILTER_AVE should be FILTER_AVG) - Relocated misplaced #endif in pngwrite.c, sCAL chunk handler. - Conditionally compile png_read_finish_row() which is not used by - progressive readers. - Added contrib/pngminim/preader to demonstrate building minimal progressive - decoder, based on contrib/gregbook with embedded libpng and zlib. - -version 1.2.37beta03 [May 20, 2009] - In contrib/pngminim/*, renamed "makefile.std" to "makefile", since there - is only one makefile in those directories, and revised the README files - accordingly. - Reformated sources in libpng style (3-space indentation, comment format) - -version 1.2.37rc01 [May 27, 2009] - No changes. - -versions 1.2.37 and 1.0.45 [June 4, 2009] - Reformatted several remaining "else statement;" and "if () statement;" into - two lines. - Added "#define PNG_NO_WRITE_SWAP" to contrib/pngminim/encoder/pngusr.h - and "define PNG_NO_READ_SWAP" to decoder/pngusr.h and preader/pngusr.h - Added sections about the git repository and our coding style to the - documentation (merged from libpng-1.4.0beta62) - Added a section to the libpng documentation about using png_get_io_ptr() - in configure scripts to detect the presence of libpng. - -version 1.2.38beta01 [June 17, 2009] - Revised libpng*.txt and libpng.3 to mention calling png_set_IHDR() - multiple times and to specify the sample order in the tRNS chunk, - because the ISO PNG specification has a typo in the tRNS table. - Changed several PNG_UNKNOWN_CHUNK_SUPPORTED to - PNG_HANDLE_AS_UNKNOWN_SUPPORTED, to make the png_set_keep mechanism - available for ignoring known chunks even when not saving unknown chunks. - Adopted preference for consistent use of "#ifdef" and "#ifndef" versus - "#if defined()" and "if !defined()" where possible. - Added PNG_NO_HANDLE_AS_UNKNOWN in the PNG_LEGACY_SUPPORTED block of - pngconf.h, and moved the various unknown chunk macro definitions - outside of the PNG_READ|WRITE_ANCILLARY_CHUNK_SUPPORTED blocks. - -version 1.0.46 [June 18, 2009] - Removed some editing cruft from scripts/libpng.pc.in and some makefiles. - -version 1.2.38rc01 [June 24, 2009] - No changes. - -version 1.2.38rc02 [June 29, 2009] - Added a reference to the libpng license in each source file. - -version 1.2.38rc03 [July 11, 2009] - Revised references to the libpng license in pngconf.h and contrib/visupng - source files. - Rebuilt configure scripts with autoconf-2.63. - -version 1.0.47 and 1.2.38 [July 16, 2009] - No changes. - -version 1.2.39beta01 [July 25, 2009] - Added a prototype for png_64bit_product() in png.c - -version 1.2.39beta02 [July 27, 2009] - Avoid a possible NULL dereference in debug build, in png_set_text_2(). - (bug introduced in libpng-0.95, discovered by Evan Rouault) - -version 1.2.39beta03 [July 29, 2009] - Relocated new png_64_bit_product() prototype into png.h - Expanded the information about prototypes in the libpng style section of - the documentation. - Rebuilt configure scripts with autoconf-2.64. - -version 1.2.39beta04 [August 1, 2009] - Replaced *.tar.lzma with *.txz in distribution. Get the xz codec - from . - -version 1.2.39beta05 [August 1, 2009] - Reject attempt to write iCCP chunk with negative embedded profile length - (JD Chen) - -version 1.2.39c01 [August 6, 2009] - No changes. - -version 1.2.39 and 1.0.48 [August 13, 2009] - No changes. - -version 1.2.40beta01 [August 20, 2009] - Removed an extra png_debug() recently added to png_write_find_filter(). - Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. - -version 1.2.40rc01 [September 2, 2009] - Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) - -version 1.2.40 and 1.0.49 [September 10, 2009] - No changes. - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) -or to glennrp at users.sourceforge.net - -Glenn R-P -*/ diff --git a/src/3rdparty/libpng/INSTALL b/src/3rdparty/libpng/INSTALL deleted file mode 100644 index 2986ae3..0000000 --- a/src/3rdparty/libpng/INSTALL +++ /dev/null @@ -1,199 +0,0 @@ - -Installing libpng version 1.2.40 - September 10, 2009 - -On Unix/Linux and similar systems, you can simply type - - ./configure [--prefix=/path] - make check - make install - -and ignore the rest of this document. - -If configure does not work on your system and you have a reasonably -up-to-date set of tools, running ./autogen.sh before running ./configure -may fix the problem. You can also run the individual commands in -autogen.sh with the --force option, if supported by your version of -the tools. If you run 'libtoolize --force', though, this will replace -the distributed, patched, version of ltmain.sh with an unpatched version -and your shared library builds may fail to produce libraries with the -correct version numbers. - -Instead, you can use one of the custom-built makefiles in the -"scripts" directory - - cp scripts/makefile.system makefile - make test - make install - -Or you can use one of the "projects" in the "projects" directory. - -If you want to use "cmake" (see www.cmake.org), copy CMakeLists.txt -from the "scripts" directory to this directory and type - - cmake . [-DPNG_MMX=YES] -DCMAKE_INSTALL_PREFIX=/path - make - make install - -Before installing libpng, you must first install zlib, if it -is not already on your system. zlib can usually be found -wherever you got libpng. zlib can be placed in another directory, -at the same level as libpng. - -If your system already has a preinstalled zlib you will still need -to have access to the zlib.h and zconf.h include files that -correspond to the version of zlib that's installed. - -You can rename the directories that you downloaded (they -might be called "libpng-1.2.40" or "lpng109" and "zlib-1.2.1" -or "zlib121") so that you have directories called "zlib" and "libpng". - -Your directory structure should look like this: - - .. (the parent directory) - libpng (this directory) - INSTALL (this file) - README - *.h - *.c - contrib - gregbook - pngminus - pngsuite - visupng - projects - beos - c5builder (Borland) - visualc6 (msvc) - netware.txt - wince.txt - scripts - makefile.* - pngtest.png - etc. - zlib - README - *.h - *.c - contrib - etc. - -If the line endings in the files look funny, you may wish to get the other -distribution of libpng. It is available in both tar.gz (UNIX style line -endings) and zip (DOS style line endings) formats. - -If you are building libpng with MSVC, you can enter the -libpng projects\visualc6 directory and follow the instructions in -projects\visualc6\README.txt. - -You can build libpng for WindowsCE by downloading and installing -the projects\wince directory as instructed in the projects\wince.txt file, and -then following the instructions in the README* files. Similarly, you can -build libpng for Netware or Beos as instructed in projects\netware.txt -or projects\beos. - -Else enter the zlib directory and follow the instructions in zlib/README, -then come back here and run "configure" or choose the appropriate -makefile.sys in the scripts directory. - -The files that are presently available in the scripts directory -include - - CMakeLists.txt => "cmake" script - makefile.std => Generic UNIX makefile (cc, creates static libpng.a) - makefile.elf => Linux/ELF makefile symbol versioning, - gcc, creates libpng12.so.0.1.2.40) - makefile.linux => Linux/ELF makefile - (gcc, creates libpng12.so.0.1.2.40) - makefile.gcc => Generic makefile (gcc, creates static libpng.a) - makefile.knr => Archaic UNIX Makefile that converts files with - ansi2knr (Requires ansi2knr.c from - ftp://ftp.cs.wisc.edu/ghost) - makefile.aix => AIX/gcc makefile - makefile.cygwin => Cygwin/gcc makefile - makefile.darwin => Darwin makefile, can use on MacosX - makefile.dec => DEC Alpha UNIX makefile - makefile.freebsd => FreeBSD makefile - makefile.hpgcc => HPUX makefile using gcc - makefile.hpux => HPUX (10.20 and 11.00) makefile - makefile.hp64 => HPUX (10.20 and 11.00) makefile, 64-bit - makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static) - makefile.intel => Intel C/C++ version 4.0 and later - libpng.icc => Project file for IBM VisualAge/C++ version 4.0 or later - makefile.netbsd => NetBSD/cc makefile, uses PNGGCCRD, makes libpng.so. - makefile.ne12bsd => NetBSD/cc makefile, uses PNGGCCRD, - makes libpng12.so - makefile.openbsd => OpenBSD makefile - makefile.sgi => Silicon Graphics IRIX makefile (cc, creates static lib) - makefile.sggcc => Silicon Graphics (gcc, - creates libpng12.so.0.1.2.40) - makefile.sunos => Sun makefile - makefile.solaris => Solaris 2.X makefile (gcc, - creates libpng12.so.0.1.2.40) - makefile.solaris-x86 => Solaris/intelMMX 2.X makefile (gcc, - creates libpng12.so.0.1.2.40) - makefile.so9 => Solaris 9 makefile (gcc, - creates libpng12.so.0.1.2.40) - makefile.32sunu => Sun Ultra 32-bit makefile - makefile.64sunu => Sun Ultra 64-bit makefile - makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc - makefile.mips => MIPS makefile - makefile.acorn => Acorn makefile - makefile.amiga => Amiga makefile - smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC compiler - (Requires SCOPTIONS, copied from scripts/SCOPTIONS.ppc) - makefile.atari => Atari makefile - makefile.beos => BEOS makefile for X86 - makefile.bor => Borland makefile (uses bcc) - makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) - makefile.tc3 => Turbo C 3.0 makefile - makefile.dj2 => DJGPP 2 makefile - makefile.msc => Microsoft C makefile - makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and later - makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) - pngos2.def => OS/2 module definition file used by makefile.os2 - makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model - makevms.com => VMS build script - descrip.mms => VMS makefile for MMS or MMK - SCOPTIONS.ppc => Used with smakefile.ppc - -Copy the file (or files) that you need from the -scripts directory into this directory, for example - - MSDOS example: copy scripts\makefile.msc makefile - UNIX example: cp scripts/makefile.std makefile - -Read the makefile to see if you need to change any source or -target directories to match your preferences. - -Then read pngconf.h to see if you want to make any configuration -changes. - -Then just run "make" which will create the libpng library in -this directory and "make test" which will run a quick test that reads -the "pngtest.png" file and writes a "pngout.png" file that should be -identical to it. Look for "9782 zero samples" in the output of the -test. For more confidence, you can run another test by typing -"pngtest pngnow.png" and looking for "289 zero samples" in the output. -Also, you can run "pngtest -m contrib/pngsuite/*.png" and compare -your output with the result shown in contrib/pngsuite/README. - -Most of the makefiles will allow you to run "make install" to -put the library in its final resting place (if you want to -do that, run "make install" in the zlib directory first if necessary). -Some also allow you to run "make test-installed" after you have -run "make install". - -If you encounter a compiler error message complaining about the -lines - __png.h__ already includes setjmp.h; - __dont__ include it again.; -This means you have compiled another module that includes setjmp.h, -which is hazardous because the two modules might not include exactly -the same setjmp.h. If you are sure that you know what you are doing -and that they are exactly the same, then you can comment out or -delete the two lines. Better yet, use the cexcept interface -instead, as demonstrated in contrib/visupng of the libpng distribution. - -Further information can be found in the README and libpng.txt -files, in the individual makefiles, in png.h, and the manual pages -libpng.3 and png.5. diff --git a/src/3rdparty/libpng/KNOWNBUG b/src/3rdparty/libpng/KNOWNBUG deleted file mode 100644 index 5e0c96f..0000000 --- a/src/3rdparty/libpng/KNOWNBUG +++ /dev/null @@ -1,22 +0,0 @@ - -Known bugs in libpng version 1.2.40 - -1. February 23, 2006: The custom makefiles don't build libpng with -lz. - - STATUS: This is a subject of debate. The change will probably be made - as a part of a major overhaul of the makefiles in libpng version 1.4.0. - -2. February 24, 2006: The Makefile generated by the "configure" script - fails to install symbolic links - libpng12.so => libpng12.so.0.1.2.9betaN - that are generated by the custom makefiles. - -3. September 4, 2007: There is a report that pngtest crashes on MacOS 10. - - STATUS: workarounds are - 1) Compile without optimization (crashes are observed with - -arch i386 and -O2 or -O3, using gcc-4.0.1). - 2) Compile pngtest.c with PNG_DEBUG defined (the bug goes away if - you try to look at it). - 3) Ignore the crash. The library itself seems to be OK. - diff --git a/src/3rdparty/libpng/LICENSE b/src/3rdparty/libpng/LICENSE deleted file mode 100644 index 93dd04a..0000000 --- a/src/3rdparty/libpng/LICENSE +++ /dev/null @@ -1,111 +0,0 @@ - -This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail. - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.2.6, August 15, 2004, through 1.2.40, September 10, 2009, are -Copyright (c) 2004, 2006-2009 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.2.5 -with the following individual added to the list of Contributing Authors - - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are -Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6 -with the following individuals added to the list of Contributing Authors - - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your enjoyment of the - library or against infringement. There is no warranty that our - efforts or the library will fulfill any of your particular purposes - or needs. This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and effort is with - the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-0.96, -with the following individuals added to the list of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88, -with the following individuals added to the list of Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and must not - be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from any - source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about" -boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a -certification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -September 10, 2009 diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README deleted file mode 100644 index 171b65a..0000000 --- a/src/3rdparty/libpng/README +++ /dev/null @@ -1,267 +0,0 @@ -README for libpng version 1.2.40 - September 10, 2009 (shared library 12.0) -See the note about version numbers near the top of png.h - -See INSTALL for instructions on how to install libpng. - -Libpng comes in several distribution formats. Get libpng-*.tar.gz, -libpng-*.tar.lzma, or libpng-*.tar.bz2 if you want UNIX-style line -endings in the text files, or lpng*.7z or lpng*.zip if you want DOS-style -line endings. You can get UNIX-style line endings from the *.zip file -by using "unzip -a" but there seems to be no simple way to recover -UNIX-style line endings from the *.7z file. The *.tar.lzma file is -recommended for *NIX users instead. - -Version 0.89 was the first official release of libpng. Don't let the -fact that it's the first release fool you. The libpng library has been in -extensive use and testing since mid-1995. By late 1997 it had -finally gotten to the stage where there hadn't been significant -changes to the API in some time, and people have a bad feeling about -libraries with versions < 1.0. Version 1.0.0 was released in -March 1998. - -**** -Note that some of the changes to the png_info structure render this -version of the library binary incompatible with libpng-0.89 or -earlier versions if you are using a shared library. The type of the -"filler" parameter for png_set_filler() has changed from png_byte to -png_uint_32, which will affect shared-library applications that use -this function. - -To avoid problems with changes to the internals of png_info_struct, -new APIs have been made available in 0.95 to avoid direct application -access to info_ptr. These functions are the png_set_ and -png_get_ functions. These functions should be used when -accessing/storing the info_struct data, rather than manipulating it -directly, to avoid such problems in the future. - -It is important to note that the APIs do not make current programs -that access the info struct directly incompatible with the new -library. However, it is strongly suggested that new programs use -the new APIs (as shown in example.c and pngtest.c), and older programs -be converted to the new format, to facilitate upgrades in the future. -**** - -Additions since 0.90 include the ability to compile libpng as a -Windows DLL, and new APIs for accessing data in the info struct. -Experimental functions include the ability to set weighting and cost -factors for row filter selection, direct reads of integers from buffers -on big-endian processors that support misaligned data access, faster -methods of doing alpha composition, and more accurate 16->8 bit color -conversion. - -The additions since 0.89 include the ability to read from a PNG stream -which has had some (or all) of the signature bytes read by the calling -application. This also allows the reading of embedded PNG streams that -do not have the PNG file signature. As well, it is now possible to set -the library action on the detection of chunk CRC errors. It is possible -to set different actions based on whether the CRC error occurred in a -critical or an ancillary chunk. - -The changes made to the library, and bugs fixed are based on discussions -on the png-mng-implement mailing list -and not on material submitted privately to Guy, Andreas, or Glenn. They will -forward any good suggestions to the list. - -For a detailed description on using libpng, read libpng.txt. For -examples of libpng in a program, see example.c and pngtest.c. For usage -information and restrictions (what little they are) on libpng, see -png.h. For a description on using zlib (the compression library used by -libpng) and zlib's restrictions, see zlib.h - -I have included a general makefile, as well as several machine and -compiler specific ones, but you may have to modify one for your own needs. - -You should use zlib 1.0.4 or later to run this, but it MAY work with -versions as old as zlib 0.95. Even so, there are bugs in older zlib -versions which can cause the output of invalid compression streams for -some images. You will definitely need zlib 1.0.4 or later if you are -taking advantage of the MS-DOS "far" structure allocation for the small -and medium memory models. You should also note that zlib is a -compression library that is useful for more things than just PNG files. -You can use zlib as a drop-in replacement for fread() and fwrite() if -you are so inclined. - -zlib should be available at the same place that libpng is, or at -ftp://ftp.simplesystems.org/pub/png/src/ - -You may also want a copy of the PNG specification. It is available -as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find -these at http://www.libpng.org/pub/png/pngdocs.html - -This code is currently being archived at libpng.sf.net in the -[DOWNLOAD] area, and on CompuServe, Lib 20 (PNG SUPPORT) -at GO GRAPHSUP. If you can't find it in any of those places, -e-mail me, and I'll help you find it. - -If you have any code changes, requests, problems, etc., please e-mail -them to me. Also, I'd appreciate any make files or project files, -and any modifications you needed to make to get libpng to compile, -along with a #define variable to tell what compiler/system you are on. -If you needed to add transformations to libpng, or wish libpng would -provide the image in a different way, drop me a note (and code, if -possible), so I can consider supporting the transformation. -Finally, if you get any warning messages when compiling libpng -(note: not zlib), and they are easy to fix, I'd appreciate the -fix. Please mention "libpng" somewhere in the subject line. Thanks. - -This release was created and will be supported by myself (of course -based in a large way on Guy's and Andreas' earlier work), and the PNG group. - -Send comments/corrections/commendations to png-mng-implement at lists.sf.net -(subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe) or to glennrp at users.sourceforge.net - -You can't reach Guy, the original libpng author, at the addresses -given in previous versions of this document. He and Andreas will read mail -addressed to the png-mng-implement list, however. - -Please do not send general questions about PNG. Send them to -the (png-mng-misc at lists.sourceforge.net, subscription required, visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement to subscribe) -On the other hand, -please do not send libpng questions to that address, send them to me -or to the png-mng-implement list. I'll -get them in the end anyway. If you have a question about something -in the PNG specification that is related to using libpng, send it -to me. Send me any questions that start with "I was using libpng, -and ...". If in doubt, send questions to me. I'll bounce them -to others, if necessary. - -Please do not send suggestions on how to change PNG. We have -been discussing PNG for twelve years now, and it is official and -finished. If you have suggestions for libpng, however, I'll -gladly listen. Even if your suggestion is not used immediately, -it may be used later. - -Files in this distribution: - - ANNOUNCE => Announcement of this version, with recent changes - CHANGES => Description of changes between libpng versions - KNOWNBUG => List of known bugs and deficiencies - LICENSE => License to use and redistribute libpng - README => This file - TODO => Things not implemented in the current library - Y2KINFO => Statement of Y2K compliance - example.c => Example code for using libpng functions - libpng-*-*-diff.txt => Diff from previous release - libpng.3 => manual page for libpng (includes libpng.txt) - libpng.txt => Description of libpng and its functions - libpngpf.3 => manual page for libpng's private functions - png.5 => manual page for the PNG format - png.c => Basic interface functions common to library - png.h => Library function and interface declarations - pngconf.h => System specific library configuration - pngerror.c => Error/warning message I/O functions - pngget.c => Functions for retrieving info from struct - pngmem.c => Memory handling functions - pngbar.png => PNG logo, 88x31 - pngnow.png => PNG logo, 98x31 - pngpread.c => Progressive reading functions - pngread.c => Read data/helper high-level functions - pngrio.c => Lowest-level data read I/O functions - pngrtran.c => Read data transformation functions - pngrutil.c => Read data utility functions - pngset.c => Functions for storing data into the info_struct - pngtest.c => Library test program - pngtest.png => Library test sample image - pngtrans.c => Common data transformation functions - pngwio.c => Lowest-level write I/O functions - pngwrite.c => High-level write functions - pngwtran.c => Write data transformations - pngwutil.c => Write utility functions - contrib => Contributions - gregbook => source code for PNG reading and writing, from - Greg Roelofs' "PNG: The Definitive Guide", - O'Reilly, 1999 - msvctest => Builds and runs pngtest using a MSVC workspace - pngminus => Simple pnm2png and png2pnm programs - pngsuite => Test images - visupng => Contains a MSVC workspace for VisualPng - projects => Contains project files and workspaces for building DLL - beos => Contains a Beos workspace for building libpng - c5builder => Contains a Borland workspace for building libpng - and zlib - visualc6 => Contains a Microsoft Visual C++ (MSVC) workspace - for building libpng and zlib - netware.txt => Contains instructions for downloading a set of - project files for building libpng and zlib on - Netware. - wince.txt => Contains instructions for downloading a Microsoft - Visual C++ (Windows CD Toolkit) workspace for - building libpng and zlib on WindowsCE - scripts => Directory containing scripts for building libpng: - descrip.mms => VMS makefile for MMS or MMK - makefile.std => Generic UNIX makefile (cc, creates static libpng.a) - makefile.elf => Linux/ELF makefile symbol versioning, - gcc, creates libpng12.so.0.1.2.40) - makefile.linux => Linux/ELF makefile - (gcc, creates libpng12.so.0.1.2.40) - makefile.gcmmx => Linux/ELF makefile - (gcc, creates libpng12.so.0.1.2.40, - uses assembler code tuned for Intel MMX platform) - makefile.gcc => Generic makefile (gcc, creates static libpng.a) - makefile.knr => Archaic UNIX Makefile that converts files with - ansi2knr (Requires ansi2knr.c from - ftp://ftp.cs.wisc.edu/ghost) - makefile.aix => AIX makefile - makefile.cygwin => Cygwin/gcc makefile - makefile.darwin => Darwin makefile - makefile.dec => DEC Alpha UNIX makefile - makefile.freebsd => FreeBSD makefile - makefile.hpgcc => HPUX makefile using gcc - makefile.hpux => HPUX (10.20 and 11.00) makefile - makefile.hp64 => HPUX (10.20 and 11.00) makefile, 64 bit - makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static) - makefile.intel => Intel C/C++ version 4.0 and later - libpng.icc => Project file, IBM VisualAge/C++ 4.0 or later - makefile.netbsd => NetBSD/cc makefile, PNGGCCRD, makes libpng.so. - makefile.ne12bsd => NetBSD/cc makefile, PNGGCCRD, makes libpng12.so - makefile.openbsd => OpenBSD makefile - makefile.sgi => Silicon Graphics IRIX (cc, creates static lib) - makefile.sggcc => Silicon Graphics - (gcc, creates libpng12.so.0.1.2.40) - makefile.sunos => Sun makefile - makefile.solaris => Solaris 2.X makefile - (gcc, creates libpng12.so.0.1.2.40) - makefile.so9 => Solaris 9 makefile - (gcc, creates libpng12.so.0.1.2.40) - makefile.32sunu => Sun Ultra 32-bit makefile - makefile.64sunu => Sun Ultra 64-bit makefile - makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc - makefile.mips => MIPS makefile - makefile.acorn => Acorn makefile - makefile.amiga => Amiga makefile - smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC - compiler (Requires SCOPTIONS, copied from - scripts/SCOPTIONS.ppc) - makefile.atari => Atari makefile - makefile.beos => BEOS makefile for X86 - makefile.bor => Borland makefile (uses bcc) - makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) - makefile.tc3 => Turbo C 3.0 makefile - makefile.dj2 => DJGPP 2 makefile - makefile.msc => Microsoft C makefile - makefile.vcawin32=> makefile for Microsoft Visual C++ 5.0 and - later (uses assembler code tuned for Intel MMX - platform) - makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and - later (does not use assembler code) - makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) - pngos2.def => OS/2 module definition file used by makefile.os2 - makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model - makevms.com => VMS build script - SCOPTIONS.ppc => Used with smakefile.ppc - -Good luck, and happy coding. - --Glenn Randers-Pehrson (current maintainer) - Internet: glennrp at users.sourceforge.net - --Andreas Eric Dilger (former maintainer, 1996-1997) - Internet: adilger at enel.ucalgary.ca - Web: http://members.shaw.ca/adilger/ - --Guy Eric Schalnat (original author and former maintainer, 1995-1996) - (formerly of Group 42, Inc) - Internet: gschal at infinet.com diff --git a/src/3rdparty/libpng/TODO b/src/3rdparty/libpng/TODO deleted file mode 100644 index face765..0000000 --- a/src/3rdparty/libpng/TODO +++ /dev/null @@ -1,25 +0,0 @@ -TODO - list of things to do for libpng: - -Final bug fixes. -Improve API by hiding the png_struct and png_info structs. -Finish work on the no-floating-point version (including gamma compensation) -Better C++ wrapper/full C++ implementation? -Fix problem with C++ and EXTERN "C". -cHRM transformation. -Improve setjmp/longjmp usage or remove it in favor of returning error codes. -Add "grayscale->palette" transformation and "palette->grayscale" detection. -Improved dithering. -Multi-lingual error and warning message support. -Complete sRGB transformation (presently it simply uses gamma=0.45455). -Man pages for function calls. -Better documentation. -Better filter selection - (counting huffman bits/precompression? filter inertia? filter costs?). -Histogram creation. -Text conversion between different code pages (Latin-1 -> Mac and DOS). -Should we always malloc 2^bit_depth PLTE/tRNS/hIST entries for safety? -Build gamma tables using fixed point (and do away with floating point entirely). -Use greater precision when changing to linear gamma for compositing against - background and doing rgb-to-gray transformation. -Investigate pre-incremented loop counters and other loop constructions. -Add interpolated method of handling interlacing. diff --git a/src/3rdparty/libpng/Y2KINFO b/src/3rdparty/libpng/Y2KINFO deleted file mode 100644 index e31bb7f..0000000 --- a/src/3rdparty/libpng/Y2KINFO +++ /dev/null @@ -1,55 +0,0 @@ - Y2K compliance in libpng: - ========================= - - September 10, 2009 - - Since the PNG Development group is an ad-hoc body, we can't make - an official declaration. - - This is your unofficial assurance that libpng from version 0.71 and - upward through 1.2.40 are Y2K compliant. It is my belief that earlier - versions were also Y2K compliant. - - Libpng only has three year fields. One is a 2-byte unsigned integer - that will hold years up to 65535. The other two hold the date in text - format, and will hold years up to 9999. - - The integer is - "png_uint_16 year" in png_time_struct. - - The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. - - There are seven time-related functions: - - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) - png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c - png_convert_from_time_t() in pngwrite.c - png_get_tIME() in pngget.c - png_handle_tIME() in pngrutil.c, called in pngread.c - png_set_tIME() in pngset.c - png_write_tIME() in pngwutil.c, called in pngwrite.c - - All appear to handle dates properly in a Y2K environment. The - png_convert_from_time_t() function calls gmtime() to convert from system - clock time, which returns (year - 1900), which we properly convert to - the full 4-digit year. There is a possibility that applications using - libpng are not passing 4-digit years into the png_convert_to_rfc_1123() - function, or that they are incorrectly passing only a 2-digit year - instead of "year - 1900" into the png_convert_from_struct_tm() function, - but this is not under our control. The libpng documentation has always - stated that it works with 4-digit years, and the APIs have been - documented as such. - - The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned - integer to hold the year, and can hold years as large as 65535. - - zlib, upon which libpng depends, is also Y2K compliant. It contains - no date-related code. - - - Glenn Randers-Pehrson - libpng maintainer - PNG Development Group diff --git a/src/3rdparty/libpng/configure b/src/3rdparty/libpng/configure deleted file mode 100755 index 4871efc..0000000 --- a/src/3rdparty/libpng/configure +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -echo " - There is no \"configure\" script in this distribution of - libpng-1.2.40. - - Instead, please copy the appropriate makefile for your system from the - \"scripts\" directory. Read the INSTALL file for more details. - - Update, July 2004: you can get a \"configure\" based distribution - from the libpng distribution sites. Download the file - libpng-1.2.40.tar.gz, libpng-1.2.40.tar.lzma, or libpng-1.2.40.tar.bz2 -" - diff --git a/src/3rdparty/libpng/example.c b/src/3rdparty/libpng/example.c deleted file mode 100644 index dcf38de..0000000 --- a/src/3rdparty/libpng/example.c +++ /dev/null @@ -1,835 +0,0 @@ - -#if 0 /* in case someone actually tries to compile this */ - -/* example.c - an example of using libpng - * Last changed in libpng 1.2.37 [June 4, 2009] - * This file has been placed in the public domain by the authors. - * Maintained 1998-2009 Glenn Randers-Pehrson - * Maintained 1996, 1997 Andreas Dilger) - * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - */ - -/* This is an example of how to use libpng to read and write PNG files. - * The file libpng.txt is much more verbose then this. If you have not - * read it, do so first. This was designed to be a starting point of an - * implementation. This is not officially part of libpng, is hereby placed - * in the public domain, and therefore does not require a copyright notice. - * - * This file does not currently compile, because it is missing certain - * parts, like allocating memory to hold an image. You will have to - * supply these parts to get it to compile. For an example of a minimal - * working PNG reader/writer, see pngtest.c, included in this distribution; - * see also the programs in the contrib directory. - */ - -#include "png.h" - - /* The png_jmpbuf() macro, used in error handling, became available in - * libpng version 1.0.6. If you want to be able to run your code with older - * versions of libpng, you must define the macro yourself (but only if it - * is not already defined by libpng!). - */ - -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#endif - -/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() - * returns zero if the image is a PNG and nonzero if it isn't a PNG. - * - * The function check_if_png() shown here, but not used, returns nonzero (true) - * if the file can be opened and is a PNG, 0 (false) otherwise. - * - * If this call is successful, and you are going to keep the file open, - * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once - * you have created the png_ptr, so that libpng knows your application - * has read that many bytes from the start of the file. Make sure you - * don't call png_set_sig_bytes() with more than 8 bytes read or give it - * an incorrect number of bytes read, or you will either have read too - * many bytes (your fault), or you are telling libpng to read the wrong - * number of magic bytes (also your fault). - * - * Many applications already read the first 2 or 4 bytes from the start - * of the image to determine the file type, so it would be easiest just - * to pass the bytes to png_sig_cmp() or even skip that if you know - * you have a PNG file, and call png_set_sig_bytes(). - */ -#define PNG_BYTES_TO_CHECK 4 -int check_if_png(char *file_name, FILE **fp) -{ - char buf[PNG_BYTES_TO_CHECK]; - - /* Open the prospective PNG file. */ - if ((*fp = fopen(file_name, "rb")) == NULL) - return 0; - - /* Read in some of the signature bytes */ - if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) - return 0; - - /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. - Return nonzero (true) if they match */ - - return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); -} - -/* Read a PNG file. You may want to return an error code if the read - * fails (depending upon the failure). There are two "prototypes" given - * here - one where we are given the filename, and we need to open the - * file, and the other where we are given an open file (possibly with - * some or all of the magic bytes read - see comments above). - */ -#ifdef open_file /* prototype 1 */ -void read_png(char *file_name) /* We need to open the file */ -{ - png_structp png_ptr; - png_infop info_ptr; - unsigned int sig_read = 0; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - FILE *fp; - - if ((fp = fopen(file_name, "rb")) == NULL) - return (ERROR); - -#else no_open_file /* prototype 2 */ -void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ -{ - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; -#endif no_open_file /* Only use one prototype! */ - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also supply the - * the compiler header file version, so that we know if the application - * was compiled with a compatible version of the library. REQUIRED - */ - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (png_ptr == NULL) - { - fclose(fp); - return (ERROR); - } - - /* Allocate/initialize the memory for image information. REQUIRED. */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return (ERROR); - } - - /* Set error handling if you are using the setjmp/longjmp method (this is - * the normal method of doing things with libpng). REQUIRED unless you - * set up your own error handlers in the png_create_read_struct() earlier. - */ - - if (setjmp(png_jmpbuf(png_ptr))) - { - /* Free all of the memory associated with the png_ptr and info_ptr */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - fclose(fp); - /* If we get here, we had a problem reading the file */ - return (ERROR); - } - - /* One of the following I/O initialization methods is REQUIRED */ -#ifdef streams /* PNG file I/O method 1 */ - /* Set up the input control if you are using standard C streams */ - png_init_io(png_ptr, fp); - -#else no_streams /* PNG file I/O method 2 */ - /* If you are using replacement read functions, instead of calling - * png_init_io() here you would call: - */ - png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); - /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* Use only one I/O method! */ - - /* If we have already read some of the signature */ - png_set_sig_bytes(png_ptr, sig_read); - -#ifdef hilevel - /* - * If you have enough memory to read in the entire image at once, - * and you need to specify only transforms that can be controlled - * with one of the PNG_TRANSFORM_* bits (this presently excludes - * dithering, filling, setting background, and doing gamma - * adjustment), then you can read the entire image (including - * pixels) into the info structure with this call: - */ - png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); - -#else - /* OK, you're doing it the hard way, with the lower-level functions */ - - /* The call to png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). REQUIRED - */ - png_read_info(png_ptr, info_ptr); - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, int_p_NULL, int_p_NULL); - - /* Set up the data transformations you want. Note that these are all - * optional. Only call them if you want/need them. Many of the - * transformations only work on specific types of images, and many - * are mutually exclusive. - */ - - /* Tell libpng to strip 16 bit/color files down to 8 bits/color */ - png_set_strip_16(png_ptr); - - /* Strip alpha bytes from the input data without combining with the - * background (not recommended). - */ - png_set_strip_alpha(png_ptr); - - /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). - */ - png_set_packing(png_ptr); - - /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). */ - png_set_packswap(png_ptr); - - /* Expand paletted colors into true RGB triplets */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(png_ptr); - - /* Expand paletted or RGB images with transparency to full alpha channels - * so the data will be available as RGBA quartets. - */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - - /* Set the background color to draw transparent and alpha images over. - * It is possible to set the red, green, and blue components directly - * for paletted images instead of supplying a palette index. Note that - * even if the PNG file supplies a background, you are not required to - * use it - you should use the (solid) application background if it has one. - */ - - png_color_16 my_background, *image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - - /* Some suggestions as to how to get a screen gamma value - * - * Note that screen gamma is the display_exponent, which includes - * the CRT_exponent and any correction for viewing conditions - */ - if (/* We have a user-defined screen gamma value */) - { - screen_gamma = user-defined screen_gamma; - } - /* This is one way that applications share the same screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) - { - screen_gamma = atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a PC monitor in a dimly - lit room */ - screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ - } - - /* Tell libpng to handle the gamma conversion for you. The final call - * is a good guess for PC generated images, but it should be configurable - * by the user at run time by the user. It is strongly suggested that - * your application support gamma correction. - */ - - int intent; - - if (png_get_sRGB(png_ptr, info_ptr, &intent)) - png_set_gamma(png_ptr, screen_gamma, 0.45455); - else - { - double image_gamma; - if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) - png_set_gamma(png_ptr, screen_gamma, image_gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - } - - /* Dither RGB files down to 8 bit palette or reduce palettes - * to the number of colors available on your screen. - */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - int num_palette; - png_colorp palette; - - /* This reduces the image to the application supplied palette */ - if (/* We have our own palette */) - { - /* An array of colors to which the image should be dithered */ - png_color std_color_cube[MAX_SCREEN_COLORS]; - - png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, - MAX_SCREEN_COLORS, png_uint_16p_NULL, 0); - } - /* This reduces the image to the palette supplied in the file */ - else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, &histogram); - - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 0); - } - } - - /* Invert monochrome files to have 0 as white and 1 as black */ - png_set_invert_mono(png_ptr); - - /* If you want to shift the pixel values from the range [0,255] or - * [0,65535] to the original [0,7] or [0,31], or whatever range the - * colors were originally in: - */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) - { - png_color_8p sig_bit_p; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); - png_set_shift(png_ptr, sig_bit_p); - } - - /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ - if (color_type & PNG_COLOR_MASK_COLOR) - png_set_bgr(png_ptr); - - /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ - png_set_swap_alpha(png_ptr); - - /* Swap bytes of 16 bit files to least significant byte first */ - png_set_swap(png_ptr); - - /* Add filler (or alpha) byte (before/after each RGB triplet) */ - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - - /* Turn on interlace handling. REQUIRED if you are not using - * png_read_image(). To see how to handle interlacing passes, - * see the png_read_row() method below: - */ - number_passes = png_set_interlace_handling(png_ptr); - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (ie you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - /* Allocate the memory to hold the image using the fields of info_ptr. */ - - /* The easiest way to read the image: */ - png_bytep row_pointers[height]; - - /* Clear the pointer array */ - for (row = 0; row < height; row++) - row_pointers[row] = NULL; - - for (row = 0; row < height; row++) - row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, - info_ptr)); - - /* Now it's time to read the image. One of these methods is REQUIRED */ -#ifdef entire /* Read the entire image in one go */ - png_read_image(png_ptr, row_pointers); - -#else no_entire /* Read the image one or more scanlines at a time */ - /* The other way to read images - deal with interlacing: */ - - for (pass = 0; pass < number_passes; pass++) - { -#ifdef single /* Read the image a single row at a time */ - for (y = 0; y < height; y++) - { - png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1); - } - -#else no_single /* Read the image several rows at a time */ - for (y = 0; y < height; y += number_of_rows) - { -#ifdef sparkle /* Read the image using the "sparkle" effect. */ - png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, - number_of_rows); -#else no_sparkle /* Read the image using the "rectangle" effect */ - png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y], - number_of_rows); -#endif no_sparkle /* Use only one of these two methods */ - } - - /* If you want to display the image after every pass, do so here */ -#endif no_single /* Use only one of these two methods */ - } -#endif no_entire /* Use only one of these two methods */ - - /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); -#endif hilevel - - /* At this point you have read the entire image */ - - /* Clean up after the read, and free any memory allocated - REQUIRED */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - - /* Close the file */ - fclose(fp); - - /* That's it */ - return (OK); -} - -/* Progressively read a file */ - -int -initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) -{ - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible in case we are using dynamically - * linked libraries. - */ - *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (*png_ptr == NULL) - { - *info_ptr = NULL; - return (ERROR); - } - - *info_ptr = png_create_info_struct(png_ptr); - - if (*info_ptr == NULL) - { - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf((*png_ptr)))) - { - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - /* This one's new. You will need to provide all three - * function callbacks, even if you aren't using them all. - * If you aren't using all functions, you can specify NULL - * parameters. Even when all three functions are NULL, - * you need to call png_set_progressive_read_fn(). - * These functions shouldn't be dependent on global or - * static variables if you are decoding several images - * simultaneously. You should store stream specific data - * in a separate struct, given as the second parameter, - * and retrieve the pointer from inside the callbacks using - * the function png_get_progressive_ptr(png_ptr). - */ - png_set_progressive_read_fn(*png_ptr, (void *)stream_data, - info_callback, row_callback, end_callback); - - return (OK); -} - -int -process_data(png_structp *png_ptr, png_infop *info_ptr, - png_bytep buffer, png_uint_32 length) -{ - if (setjmp(png_jmpbuf((*png_ptr)))) - { - /* Free the png_ptr and info_ptr memory on error */ - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - /* This one's new also. Simply give it chunks of data as - * they arrive from the data stream (in order, of course). - * On segmented machines, don't give it any more than 64K. - * The library seems to run fine with sizes of 4K, although - * you can give it much less if necessary (I assume you can - * give it chunks of 1 byte, but I haven't tried with less - * than 256 bytes yet). When this function returns, you may - * want to display any rows that were generated in the row - * callback, if you aren't already displaying them there. - */ - png_process_data(*png_ptr, *info_ptr, buffer, length); - return (OK); -} - -info_callback(png_structp png_ptr, png_infop info) -{ - /* Do any setup here, including setting any of the transformations - * mentioned in the Reading PNG files section. For now, you _must_ - * call either png_start_read_image() or png_read_update_info() - * after all the transformations are set (even if you don't set - * any). You may start getting rows before png_process_data() - * returns, so this is your last chance to prepare for that. - */ -} - -row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) -{ - /* - * This function is called for every row in the image. If the - * image is interlaced, and you turned on the interlace handler, - * this function will be called for every row in every pass. - * - * In this function you will receive a pointer to new row data from - * libpng called new_row that is to replace a corresponding row (of - * the same data format) in a buffer allocated by your application. - * - * The new row data pointer "new_row" may be NULL, indicating there is - * no new data to be replaced (in cases of interlace loading). - * - * If new_row is not NULL then you need to call - * png_progressive_combine_row() to replace the corresponding row as - * shown below: - */ - - /* Check if row_num is in bounds. */ - if ((row_num >= 0) && (row_num < height)) - { - /* Get pointer to corresponding row in our - * PNG read buffer. - */ - png_bytep old_row = ((png_bytep *)our_data)[row_num]; - - /* If both rows are allocated then copy the new row - * data to the corresponding row data. - */ - if ((old_row != NULL) && (new_row != NULL)) - png_progressive_combine_row(png_ptr, old_row, new_row); - } - /* - * The rows and passes are called in order, so you don't really - * need the row_num and pass, but I'm supplying them because it - * may make your life easier. - * - * For the non-NULL rows of interlaced images, you must call - * png_progressive_combine_row() passing in the new row and the - * old row, as demonstrated above. You can call this function for - * NULL rows (it will just return) and for non-interlaced images - * (it just does the png_memcpy for you) if it will make the code - * easier. Thus, you can just do this for all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, new_row); - - /* where old_row is what was displayed for previous rows. Note - * that the first pass (pass == 0 really) will completely cover - * the old row, so the rows do not have to be initialized. After - * the first pass (and only for interlaced images), you will have - * to pass the current row as new_row, and the function will combine - * the old row and the new row. - */ -} - -end_callback(png_structp png_ptr, png_infop info) -{ - /* This function is called when the whole image has been read, - * including any chunks after the image (up to and including - * the IEND). You will usually have the same info chunk as you - * had in the header, although some data may have been added - * to the comments and time fields. - * - * Most people won't do much here, perhaps setting a flag that - * marks the image as finished. - */ -} - -/* Write a png file */ -void write_png(char *file_name /* , ... other image information ... */) -{ - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - png_colorp palette; - - /* Open the file */ - fp = fopen(file_name, "wb"); - if (fp == NULL) - return (ERROR); - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible with the one used at compile time, - * in case we are using dynamically linked libraries. REQUIRED. - */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (png_ptr == NULL) - { - fclose(fp); - return (ERROR); - } - - /* Allocate/initialize the image information data. REQUIRED */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_write_struct(&png_ptr, png_infopp_NULL); - return (ERROR); - } - - /* Set error handling. REQUIRED if you aren't supplying your own - * error handling functions in the png_create_write_struct() call. - */ - if (setjmp(png_jmpbuf(png_ptr))) - { - /* If we get here, we had a problem writing the file */ - fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - return (ERROR); - } - - /* One of the following I/O initialization functions is REQUIRED */ - -#ifdef streams /* I/O initialization method 1 */ - /* Set up the output control if you are using standard C streams */ - png_init_io(png_ptr, fp); - -#else no_streams /* I/O initialization method 2 */ - /* If you are using replacement write functions, instead of calling - * png_init_io() here you would call - */ - png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, - user_IO_flush_function); - /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* Only use one initialization method */ - -#ifdef hilevel - /* This is the easy way. Use it if you already have all the - * image info living in the structure. You could "|" many - * PNG_TRANSFORM flags into the png_transforms integer here. - */ - png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); - -#else - /* This is the hard way */ - - /* Set the image information here. Width and height are up to 2^31, - * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on - * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, - * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, - * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or - * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST - * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED - */ - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, - PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - /* Set the palette if there is one. REQUIRED for indexed-color images */ - palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH - * png_sizeof(png_color)); - /* ... Set palette colors ... */ - png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - /* You must not free palette here, because png_set_PLTE only makes a link to - * the palette that you malloced. Wait until you are about to destroy - * the png structure. - */ - - /* Optional significant bit (sBIT) chunk */ - png_color_8 sig_bit; - /* If we are dealing with a grayscale image then */ - sig_bit.gray = true_bit_depth; - /* Otherwise, if we are dealing with a color image then */ - sig_bit.red = true_red_bit_depth; - sig_bit.green = true_green_bit_depth; - sig_bit.blue = true_blue_bit_depth; - /* If the image has an alpha channel then */ - sig_bit.alpha = true_alpha_bit_depth; - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - - - /* Optional gamma chunk is strongly suggested if you have any guess - * as to the correct gamma of the image. - */ - png_set_gAMA(png_ptr, info_ptr, gamma); - - /* Optionally write comments into the image */ - text_ptr[0].key = "Title"; - text_ptr[0].text = "Mona Lisa"; - text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr[1].key = "Author"; - text_ptr[1].text = "Leonardo DaVinci"; - text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr[2].key = "Description"; - text_ptr[2].text = ""; - text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; -#ifdef PNG_iTXt_SUPPORTED - text_ptr[0].lang = NULL; - text_ptr[1].lang = NULL; - text_ptr[2].lang = NULL; -#endif - png_set_text(png_ptr, info_ptr, text_ptr, 3); - - /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ - - /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored - * on read and, if your application chooses to write them, they must - * be written in accordance with the sRGB profile - */ - - /* Write the file header information. REQUIRED */ - png_write_info(png_ptr, info_ptr); - - /* If you want, you can write the info in two steps, in case you need to - * write your private chunk ahead of PLTE: - * - * png_write_info_before_PLTE(write_ptr, write_info_ptr); - * write_my_chunk(); - * png_write_info(png_ptr, info_ptr); - * - * However, given the level of known- and unknown-chunk support in 1.2.0 - * and up, this should no longer be necessary. - */ - - /* Once we write out the header, the compression type on the text - * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or - * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again - * at the end. - */ - - /* Set up the transformations you want. Note that these are - * all optional. Only call them if you want them. - */ - - /* Invert monochrome pixels */ - png_set_invert_mono(png_ptr); - - /* Shift the pixels up to a legal bit depth and fill in - * as appropriate to correctly scale the image. - */ - png_set_shift(png_ptr, &sig_bit); - - /* Pack pixels into bytes */ - png_set_packing(png_ptr); - - /* Swap location of alpha bytes from ARGB to RGBA */ - png_set_swap_alpha(png_ptr); - - /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into - * RGB (4 channels -> 3 channels). The second parameter is not used. - */ - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - - /* Flip BGR pixels to RGB */ - png_set_bgr(png_ptr); - - /* Swap bytes of 16-bit files to most significant byte first */ - png_set_swap(png_ptr); - - /* Swap bits of 1, 2, 4 bit packed pixel formats */ - png_set_packswap(png_ptr); - - /* Turn on interlace handling if you are not using png_write_image() */ - if (interlacing) - number_passes = png_set_interlace_handling(png_ptr); - else - number_passes = 1; - - /* The easiest way to write the image (you may have a different memory - * layout, however, so choose what fits your needs best). You need to - * use the first method if you aren't handling interlacing yourself. - */ - png_uint_32 k, height, width; - png_byte image[height][width*bytes_per_pixel]; - png_bytep row_pointers[height]; - - if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) - png_error (png_ptr, "Image is too tall to process in memory"); - - for (k = 0; k < height; k++) - row_pointers[k] = image + k*width*bytes_per_pixel; - - /* One of the following output methods is REQUIRED */ - -#ifdef entire /* Write out the entire image data in one call */ - png_write_image(png_ptr, row_pointers); - - /* The other way to write the image - deal with interlacing */ - -#else no_entire /* Write out the image data by one or more scanlines */ - - /* The number of passes is either 1 for non-interlaced images, - * or 7 for interlaced images. - */ - for (pass = 0; pass < number_passes; pass++) - { - /* Write a few rows at a time. */ - png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); - - /* If you are only writing one row at a time, this works */ - for (y = 0; y < height; y++) - png_write_rows(png_ptr, &row_pointers[y], 1); - } -#endif no_entire /* Use only one output method */ - - /* You can write optional chunks like tEXt, zTXt, and tIME at the end - * as well. Shouldn't be necessary in 1.2.0 and up as all the public - * chunks are supported and you can use png_set_unknown_chunks() to - * register unknown chunks into the info structure to be written out. - */ - - /* It is REQUIRED to call this to finish writing the rest of the file */ - png_write_end(png_ptr, info_ptr); -#endif hilevel - - /* If you png_malloced a palette, free it here (don't free info_ptr->palette, - * as recommended in versions 1.0.5m and earlier of this example; if - * libpng mallocs info_ptr->palette, libpng will free it). If you - * allocated it with malloc() instead of png_malloc(), use free() instead - * of png_free(). - */ - png_free(png_ptr, palette); - palette = NULL; - - /* Similarly, if you png_malloced any data that you passed in with - * png_set_something(), such as a hist or trans array, free it here, - * when you can be sure that libpng is through with it. - */ - png_free(png_ptr, trans); - trans = NULL; - /* Whenever you use png_free() it is a good idea to set the pointer to - * NULL in case your application inadvertently tries to png_free() it - * again. When png_free() sees a NULL it returns without action, thus - * avoiding the double-free security problem. - */ - - /* Clean up after the write, and free any memory allocated */ - png_destroy_write_struct(&png_ptr, &info_ptr); - - /* Close the file */ - fclose(fp); - - /* That's it */ - return (OK); -} - -#endif /* if 0 */ diff --git a/src/3rdparty/libpng/libpng-1.2.40.txt b/src/3rdparty/libpng/libpng-1.2.40.txt deleted file mode 100644 index 019c886..0000000 --- a/src/3rdparty/libpng/libpng-1.2.40.txt +++ /dev/null @@ -1,3112 +0,0 @@ -libpng.txt - A description on how to use and modify libpng - - libpng version 1.2.40 - September 10, 2009 - Updated and distributed by Glenn Randers-Pehrson - - Copyright (c) 1998-2009 Glenn Randers-Pehrson - - This document is released under the libpng license. - For conditions of distribution and use, see the disclaimer - and license in png.h - - Based on: - - libpng versions 0.97, January 1998, through 1.2.40 - September 10, 2009 - Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2009 Glenn Randers-Pehrson - - libpng 1.0 beta 6 version 0.96 May 28, 1997 - Updated and distributed by Andreas Dilger - Copyright (c) 1996, 1997 Andreas Dilger - - libpng 1.0 beta 2 - version 0.88 January 26, 1996 - For conditions of distribution and use, see copyright - notice in png.h. Copyright (c) 1995, 1996 Guy Eric - Schalnat, Group 42, Inc. - - Updated/rewritten per request in the libpng FAQ - Copyright (c) 1995, 1996 Frank J. T. Wojcik - December 18, 1995 & January 20, 1996 - -I. Introduction - -This file describes how to use and modify the PNG reference library -(known as libpng) for your own use. There are five sections to this -file: introduction, structures, reading, writing, and modification and -configuration notes for various special platforms. In addition to this -file, example.c is a good starting point for using the library, as -it is heavily commented and should include everything most people -will need. We assume that libpng is already installed; see the -INSTALL file for instructions on how to install libpng. - -For examples of libpng usage, see the files "example.c", "pngtest.c", -and the files in the "contrib" directory, all of which are included in the -libpng distribution. - -Libpng was written as a companion to the PNG specification, as a way -of reducing the amount of time and effort it takes to support the PNG -file format in application programs. - -The PNG specification (second edition), November 2003, is available as -a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at -. It is technically equivalent -to the PNG specification (second edition) but has some additional material. - -The PNG-1.0 specification is available -as RFC 2083 and as a -W3C Recommendation . - -Some additional chunks are described in the special-purpose public chunks -documents at . - -Other information -about PNG, and the latest version of libpng, can be found at the PNG home -page, . - -Most users will not have to modify the library significantly; advanced -users may want to modify it more. All attempts were made to make it as -complete as possible, while keeping the code easy to understand. -Currently, this library only supports C. Support for other languages -is being considered. - -Libpng has been designed to handle multiple sessions at one time, -to be easily modifiable, to be portable to the vast majority of -machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy -to use. The ultimate goal of libpng is to promote the acceptance of -the PNG file format in whatever way possible. While there is still -work to be done (see the TODO file), libpng should cover the -majority of the needs of its users. - -Libpng uses zlib for its compression and decompression of PNG files. -Further information about zlib, and the latest version of zlib, can -be found at the zlib home page, . -The zlib compression utility is a general purpose utility that is -useful for more than PNG files, and can be used without libpng. -See the documentation delivered with zlib for more details. -You can usually find the source files for the zlib utility wherever you -find the libpng source files. - -Libpng is thread safe, provided the threads are using different -instances of the structures. Each thread should have its own -png_struct and png_info instances, and thus its own image. -Libpng does not protect itself against two threads using the -same instance of a structure. - -II. Structures - -There are two main structures that are important to libpng, png_struct -and png_info. The first, png_struct, is an internal structure that -will not, for the most part, be used by a user except as the first -variable passed to every libpng function call. - -The png_info structure is designed to provide information about the -PNG file. At one time, the fields of png_info were intended to be -directly accessible to the user. However, this tended to cause problems -with applications using dynamically loaded libraries, and as a result -a set of interface functions for png_info (the png_get_*() and png_set_*() -functions) was developed. The fields of png_info are still available for -older applications, but it is suggested that applications use the new -interfaces if at all possible. - -Applications that do make direct access to the members of png_struct (except -for png_ptr->jmpbuf) must be recompiled whenever the library is updated, -and applications that make direct access to the members of png_info must -be recompiled if they were compiled or loaded with libpng version 1.0.6, -in which the members were in a different order. In version 1.0.7, the -members of the png_info structure reverted to the old order, as they were -in versions 0.97c through 1.0.5. Starting with version 2.0.0, both -structures are going to be hidden, and the contents of the structures will -only be accessible through the png_get/png_set functions. - -The png.h header file is an invaluable reference for programming with libpng. -And while I'm on the topic, make sure you include the libpng header file: - -#include - -III. Reading - -We'll now walk you through the possible functions to call when reading -in a PNG file sequentially, briefly explaining the syntax and purpose -of each one. See example.c and png.h for more detail. While -progressive reading is covered in the next section, you will still -need some of the functions discussed in this section to read a PNG -file. - -Setup - -You will want to do the I/O initialization(*) before you get into libpng, -so if it doesn't work, you don't have much to undo. Of course, you -will also want to insure that you are, in fact, dealing with a PNG -file. Libpng provides a simple check to see if a file is a PNG file. -To use it, pass in the first 1 to 8 bytes of the file to the function -png_sig_cmp(), and it will return 0 (false) if the bytes match the -corresponding bytes of the PNG signature, or nonzero (true) otherwise. -Of course, the more bytes you pass in, the greater the accuracy of the -prediction. - -If you are intending to keep the file pointer open for use in libpng, -you must ensure you don't read more than 8 bytes from the beginning -of the file, and you also have to make a call to png_set_sig_bytes_read() -with the number of bytes you read from the beginning. Libpng will -then only check the bytes (if any) that your program didn't read. - -(*): If you are not using the standard I/O functions, you will need -to replace them with custom functions. See the discussion under -Customizing libpng. - - - FILE *fp = fopen(file_name, "rb"); - if (!fp) - { - return (ERROR); - } - fread(header, 1, number, fp); - is_png = !png_sig_cmp(header, 0, number); - if (!is_png) - { - return (NOT_PNG); - } - - -Next, png_struct and png_info need to be allocated and initialized. In -order to ensure that the size of these structures is correct even with a -dynamically linked libpng, there are functions to initialize and -allocate the structures. We also pass the library version, optional -pointers to error handling functions, and a pointer to a data struct for -use by the error functions, if necessary (the pointer and functions can -be NULL if the default error handlers are to be used). See the section -on Changes to Libpng below regarding the old initialization functions. -The structure allocation functions quietly return NULL if they fail to -create the structure, so your application should check for that. - - png_structp png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, - (png_infopp)NULL, (png_infopp)NULL); - return (ERROR); - } - - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_read_struct_2() instead of png_create_read_struct(): - - png_structp png_ptr = png_create_read_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -The error handling routines passed to png_create_read_struct() -and the memory alloc/free routines passed to png_create_struct_2() -are only necessary if you are not using the libpng supplied error -handling and memory alloc/free functions. - -When libpng encounters an error, it expects to longjmp back -to your routine. Therefore, you will need to call setjmp and pass -your png_jmpbuf(png_ptr). If you read the file from different -routines, you will need to update the jmpbuf field every time you enter -a new routine that will call a png_*() function. - -See your documentation of setjmp/longjmp for your compiler for more -information on setjmp/longjmp. See the discussion on libpng error -handling in the Customizing Libpng section below for more information -on the libpng error handling. If an error occurs, and libpng longjmp's -back to your setjmp, you will want to call png_destroy_read_struct() to -free any memory. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - fclose(fp); - return (ERROR); - } - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the input code. The default for libpng is to -use the C function fread(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. If you wish to handle reading data in another -way, you need not call the png_init_io() function, but you must then -implement the libpng I/O methods discussed in the Customizing Libpng -section below. - - png_init_io(png_ptr, fp); - -If you had previously opened the file and read any of the signature from -the beginning in order to see if this was a PNG file, you need to let -libpng know that there are some bytes missing from the start of the file. - - png_set_sig_bytes(png_ptr, number); - -Setting up callback code - -You can set up a callback function to handle any unknown chunks in the -input stream. You must supply the function - - read_chunk_callback(png_ptr ptr, - png_unknown_chunkp chunk); - { - /* The unknown chunk structure contains your - chunk data, along with similar data for any other - unknown chunks: */ - - png_byte name[5]; - png_byte *data; - png_size_t size; - - /* Note that libpng has already taken care of - the CRC handling */ - - /* put your code here. Search for your chunk in the - unknown chunk structure, process it, and return one - of the following: */ - - return (-n); /* chunk had an error */ - return (0); /* did not recognize */ - return (n); /* success */ - } - -(You can give your function another name that you like instead of -"read_chunk_callback") - -To inform libpng about your function, use - - png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, - read_chunk_callback); - -This names not only the callback function, but also a user pointer that -you can retrieve with - - png_get_user_chunk_ptr(png_ptr); - -If you call the png_set_read_user_chunk_fn() function, then all unknown -chunks will be saved when read, in case your callback function will need -one or more of them. This behavior can be changed with the -png_set_keep_unknown_chunks() function, described below. - -At this point, you can set up a callback function that will be -called after each row has been read, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void read_row_callback(png_ptr ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "read_row_callback") - -To inform libpng about your function, use - - png_set_read_status_fn(png_ptr, read_row_callback); - -Unknown-chunk handling - -Now you get to set the way the library processes unknown chunks in the -input PNG stream. Both known and unknown chunks will be read. Normal -behavior is that known chunks will be parsed into information in -various info_ptr members while unknown chunks will be discarded. This -behavior can be wasteful if your application will never use some known -chunk types. To change this, you can call: - - png_set_keep_unknown_chunks(png_ptr, keep, - chunk_list, num_chunks); - keep - 0: default unknown chunk handling - 1: ignore; do not keep - 2: keep only if safe-to-copy - 3: keep even if unsafe-to-copy - You can use these definitions: - PNG_HANDLE_CHUNK_AS_DEFAULT 0 - PNG_HANDLE_CHUNK_NEVER 1 - PNG_HANDLE_CHUNK_IF_SAFE 2 - PNG_HANDLE_CHUNK_ALWAYS 3 - chunk_list - list of chunks affected (a byte string, - five bytes per chunk, NULL or '\0' if - num_chunks is 0) - num_chunks - number of chunks affected; if 0, all - unknown chunks are affected. If nonzero, - only the chunks in the list are affected - -Unknown chunks declared in this way will be saved as raw data onto a -list of png_unknown_chunk structures. If a chunk that is normally -known to libpng is named in the list, it will be handled as unknown, -according to the "keep" directive. If a chunk is named in successive -instances of png_set_keep_unknown_chunks(), the final instance will -take precedence. The IHDR and IEND chunks should not be named in -chunk_list; if they are, libpng will process them normally anyway. - -Here is an example of the usage of png_set_keep_unknown_chunks(), -where the private "vpAg" chunk will later be processed by a user chunk -callback function: - - png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - png_byte unused_chunks[]= - { - 104, 73, 83, 84, (png_byte) '\0', /* hIST */ - 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ - 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ - 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ - 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ - 116, 73, 77, 69, (png_byte) '\0', /* tIME */ - }; - #endif - - ... - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - /* ignore all unknown chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, NULL, 0); - /* except for vpAg: */ - png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); - /* also ignore unused known chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - #endif - -User limits - -The PNG specification allows the width and height of an image to be as -large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. -Since very few applications really need to process such large images, -we have imposed an arbitrary 1-million limit on rows and columns. -Larger images will be rejected immediately with a png_error() call. If -you wish to override this limit, you can use - - png_set_user_limits(png_ptr, width_max, height_max); - -to set your own limits, or use width_max = height_max = 0x7fffffffL -to allow all valid dimensions (libpng may reject some very large images -anyway because of potential buffer overflow conditions). - -You should put this statement after you create the PNG structure and -before calling png_read_info(), png_read_png(), or png_process_data(). -If you need to retrieve the limits that are being applied, use - - width_max = png_get_user_width_max(png_ptr); - height_max = png_get_user_height_max(png_ptr); - -The high-level read interface - -At this point there are two ways to proceed; through the high-level -read interface, or through a sequence of low-level read operations. -You can use the high-level interface if (a) you are willing to read -the entire image into memory, and (b) the input transformations -you want to do are limited to the following set: - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to - 8 bits - PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel - PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit - samples to bytes - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_EXPAND Perform set_expand() - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - -(This excludes setting a background color, doing gamma transformation, -dithering, and setting filler.) If this is the case, simply do this: - - png_read_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of -some set of transformation flags. This call is equivalent to png_read_info(), -followed the set of transformations indicated by the transform mask, -then png_read_image(), and finally png_read_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future input transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_read_png(). - -After you have called png_read_png(), you can retrieve the image data -with - - row_pointers = png_get_rows(png_ptr, info_ptr); - -where row_pointers is an array of pointers to the pixel data for each row: - - png_bytep row_pointers[height]; - -If you know your image size and pixel size ahead of time, you can allocate -row_pointers prior to calling png_read_png() with - - if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) - png_error (png_ptr, - "Image is too tall to process in memory"); - if (width > PNG_UINT_32_MAX/pixel_size) - png_error (png_ptr, - "Image is too wide to process in memory"); - row_pointers = png_malloc(png_ptr, - height*png_sizeof(png_bytep)); - for (int i=0; i) and -png_get_(png_ptr, info_ptr, ...) functions return non-zero if the -data has been read, or zero if it is missing. The parameters to the -png_get_ are set directly if they are simple data types, or a pointer -into the info_ptr is returned for any complex types. - - png_get_PLTE(png_ptr, info_ptr, &palette, - &num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_get_gAMA(png_ptr, info_ptr, &gamma); - gamma - the gamma the file is written - at (PNG_INFO_gAMA) - - png_get_sRGB(png_ptr, info_ptr, &srgb_intent); - srgb_intent - the rendering intent (PNG_INFO_sRGB) - The presence of the sRGB chunk - means that the pixel data is in the - sRGB color space. This chunk also - implies specific values of gAMA and - cHRM. - - png_get_iCCP(png_ptr, info_ptr, &name, - &compression_type, &profile, &proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, - red, green, and blue channels, - whichever are appropriate for the - given color type (png_color_16) - - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, - &trans_values); - trans - array of transparent entries for - palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values of - the single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_get_hIST(png_ptr, info_ptr, &hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_get_tIME(png_ptr, info_ptr, &mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_get_bKGD(png_ptr, info_ptr, &background); - background - background color (PNG_VALID_bKGD) - valid 16-bit red, green and blue - values, regardless of color_type - - num_comments = png_get_text(png_ptr, info_ptr, - &text_ptr, &num_text); - num_comments - number of comments - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (empty - string for unknown). - text_ptr[i].lang_key - keyword in UTF-8 - (empty string for unknown). - num_text - number of comments (same as - num_comments; you can put NULL here - to avoid the duplication) - Note while png_set_text() will accept text, language, - and translated keywords that can be NULL pointers, the - structure returned by png_get_text will always contain - regular zero-terminated C strings. They might be - empty strings but they will never be NULL pointers. - - num_spalettes = png_get_sPLT(png_ptr, info_ptr, - &palette_ptr); - palette_ptr - array of palette structures holding - contents of one or more sPLT chunks - read. - num_spalettes - number of sPLT chunks read. - - png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, - &unit_type); - offset_x - positive offset from the left edge - of the screen - offset_y - positive offset from the top edge - of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, - &unit_type); - res_x - pixels/unit physical resolution in - x direction - res_y - pixels/unit physical resolution in - x direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_get_sCAL(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - num_unknown_chunks = png_get_unknown_chunks(png_ptr, - info_ptr, &unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position of chunk in file - - The value of "i" corresponds to the order in which the - chunks were read from the PNG file or inserted with the - png_set_unknown_chunks() function. - -The data from the pHYs chunk can be retrieved in several convenient -forms: - - res_x = png_get_x_pixels_per_meter(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_meter(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_meter(png_ptr, - info_ptr) - res_x = png_get_x_pixels_per_inch(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_inch(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_inch(png_ptr, - info_ptr) - aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, - info_ptr) - - (Each of these returns 0 [signifying "unknown"] if - the data is not present or if res_x is 0; - res_x_and_y is 0 if res_x != res_y) - -The data from the oFFs chunk can be retrieved in several convenient -forms: - - x_offset = png_get_x_offset_microns(png_ptr, info_ptr); - y_offset = png_get_y_offset_microns(png_ptr, info_ptr); - x_offset = png_get_x_offset_inches(png_ptr, info_ptr); - y_offset = png_get_y_offset_inches(png_ptr, info_ptr); - - (Each of these returns 0 [signifying "unknown" if both - x and y are 0] if the data is not present or if the - chunk is present but the unit is the pixel) - -For more information, see the png_info definition in png.h and the -PNG specification for chunk contents. Be careful with trusting -rowbytes, as some of the transformations could increase the space -needed to hold a row (expand, filler, gray_to_rgb, etc.). -See png_read_update_info(), below. - -A quick word about text_ptr and num_text. PNG stores comments in -keyword/text pairs, one pair per chunk, with no limit on the number -of text chunks, and a 2^31 byte limit on their size. While there are -suggested keywords, there is no requirement to restrict the use to these -strings. It is strongly suggested that keywords and text be sensible -to humans (that's the point), so don't use abbreviations. Non-printing -symbols are not allowed. See the PNG specification for more details. -There is also no requirement to have text after the keyword. - -Keywords should be limited to 79 Latin-1 characters without leading or -trailing spaces, but non-consecutive spaces are allowed within the -keyword. It is possible to have the same keyword any number of times. -The text_ptr is an array of png_text structures, each holding a -pointer to a language string, a pointer to a keyword and a pointer to -a text string. The text string, language code, and translated -keyword may be empty or NULL pointers. The keyword/text -pairs are put into the array in the order that they are received. -However, some or all of the text chunks may be after the image, so, to -make sure you have read all the text chunks, don't mess with these -until after you read the stuff after the image. This will be -mentioned again below in the discussion that goes with png_read_end(). - -Input transformations - -After you've read the header information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -The colors used for the background and transparency values should be -supplied in the same format/depth as the current image data. They -are stored in the same format/depth as the image data in a bKGD or tRNS -chunk, so this is what libpng expects for this data. The colors are -transformed to keep in sync with the image data when an application -calls the png_read_update_info() routine (see below). - -Data will be decoded into the supplied row buffers packed into bytes -unless the library has been told to transform it into another format. -For example, 4 bit/pixel paletted or grayscale data will be returned -2 pixels/byte with the leftmost pixel in the high-order bits of the -byte, unless png_set_packing() is called. 8-bit RGB data will be stored -in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() -is called to insert filler bytes, either before or after each RGB triplet. -16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant -byte of the color value first, unless png_set_strip_16() is called to -transform it to regular RGB RGB triplets, or png_set_filler() or -png_set_add alpha() is called to insert filler bytes, either before or -after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can -be modified with -png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). - -The following code transforms grayscale images of less than 8 to 8 bits, -changes paletted images to RGB, and adds a full alpha channel if there is -transparency information in a tRNS chunk. This is most useful on -grayscale images with bit depths of 2 or 4 or if there is a multiple-image -viewing application that wishes to treat all images in the same way. - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && - bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); - - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); - -These three functions are actually aliases for png_set_expand(), added -in libpng version 1.0.4, with the function names expanded to improve code -readability. In some future version they may actually do different -things. - -As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was -added. It expands the sample depth without changing tRNS to alpha. - -PNG can have files with 16 bits per channel. If you only can handle -8 bits per channel, this will strip the pixels down to 8 bit. - - if (bit_depth == 16) - png_set_strip_16(png_ptr); - -If, for some reason, you don't need the alpha channel on an image, -and you want to remove it rather than combining it with the background -(but the image author certainly had in mind that you *would* combine -it with the background, so that's what you should probably do): - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(png_ptr); - -In PNG files, the alpha channel in an image -is the level of opacity. If you need the alpha channel in an image to -be the level of transparency instead of opacity, you can invert the -alpha channel (or the tRNS chunk data) after it's read, so that 0 is -fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit -images) is fully transparent, with - - png_set_invert_alpha(png_ptr); - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit -files. This code expands to 1 pixel per byte without changing the -values of the pixels: - - if (bit_depth < 8) - png_set_packing(png_ptr); - -PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels -stored in a PNG image have been "scaled" or "shifted" up to the next -higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to -8 bits/sample in the range [0, 255]). However, it is also possible to -convert the PNG pixel data back to the original bit depth of the image. -This call reduces the pixels back down to the original bit depth: - - png_color_8p sig_bit; - - if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) - png_set_shift(png_ptr, sig_bit); - -PNG files store 3-color pixels in red, green, blue order. This code -changes the storage of the pixels to blue, green, red: - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_bgr(png_ptr); - -PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them -into 4 or 8 bytes for windowing systems that need them in this format: - - if (color_type == PNG_COLOR_TYPE_RGB) - png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); - -where "filler" is the 8 or 16-bit number to fill with, and the location is -either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether -you want the filler before the RGB or after. This transformation -does not affect images that already have full alpha channels. To add an -opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which -will generate RGBA pixels. - -Note that png_set_filler() does not change the color type. If you want -to do that, you can add a true alpha channel with - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY) - png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); - -where "filler" contains the alpha value to assign to each pixel. -This function was added in libpng-1.2.7. - -If you are reading an image with an alpha channel, and you need the -data as ARGB instead of the normal PNG format RGBA: - - if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_swap_alpha(png_ptr); - -For some uses, you may want a grayscale image to be represented as -RGB. This code will do that conversion: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - -Conversely, you can convert an RGB or RGBA image to grayscale or grayscale -with alpha. - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, error_action, - int red_weight, int green_weight); - - error_action = 1: silently do the conversion - error_action = 2: issue a warning if the original - image has any pixel where - red != green or red != blue - error_action = 3: issue an error and abort the - conversion if the original - image has any pixel where - red != green or red != blue - - red_weight: weight of red component times 100000 - green_weight: weight of green component times 100000 - If either weight is negative, default - weights (21268, 71514) are used. - -If you have set error_action = 1 or 2, you can -later check whether the image really was gray, after processing -the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. -It will return a png_byte that is zero if the image was gray or -1 if there were any non-gray pixels. bKGD and sBIT data -will be silently converted to grayscale, using the green channel -data, regardless of the error_action setting. - -With red_weight+green_weight<=100000, -the normalized graylevel is computed: - - int rw = red_weight * 65536; - int gw = green_weight * 65536; - int bw = 65536 - (rw + gw); - gray = (rw*red + gw*green + bw*blue)/65536; - -The default values approximate those recommended in the Charles -Poynton's Color FAQ, -Copyright (c) 1998-01-04 Charles Poynton - - Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - -Libpng approximates this with - - Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - -which can be expressed with integers as - - Y = (6969 * R + 23434 * G + 2365 * B)/32768 - -The calculation is done in a linear colorspace, if the image gamma -is known. - -If you have a grayscale and you are using png_set_expand_depth(), -png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to -a higher bit-depth, you must either supply the background color as a gray -value at the original file bit-depth (need_expand = 1) or else supply the -background color as an RGB triplet at the final, expanded bit depth -(need_expand = 0). Similarly, if you are reading a paletted image, you -must either supply the background color as a palette index (need_expand = 1) -or as an RGB triplet that may or may not be in the palette (need_expand = 0). - - png_color_16 my_background; - png_color_16p image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - -The png_set_background() function tells libpng to composite images -with alpha or simple transparency against the supplied background -color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), -you may use this color, or supply another color more suitable for -the current display (e.g., the background color from a web page). You -need to tell libpng whether the color is in the gamma space of the -display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file -(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one -that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't -know why anyone would use this, but it's here). - -To properly display PNG images on any kind of system, the application needs -to know what the display gamma is. Ideally, the user will know this, and -the application will allow them to set it. One method of allowing the user -to set the display gamma separately for each system is to check for a -SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be -correctly set. - -Note that display_gamma is the overall gamma correction required to produce -pleasing results, which depends on the lighting conditions in the surrounding -environment. In a dim or brightly lit room, no compensation other than -the physical gamma exponent of the monitor is needed, while in a dark room -a slightly smaller exponent is better. - - double gamma, screen_gamma; - - if (/* We have a user-defined screen - gamma value */) - { - screen_gamma = user_defined_screen_gamma; - } - /* One way that applications can share the same - screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) - != NULL) - { - screen_gamma = (double)atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a - PC monitor in a bright office or a dim room */ - screen_gamma = 2.0; /* A good guess for a - PC monitor in a dark room */ - screen_gamma = 1.7 or 1.0; /* A good - guess for Mac systems */ - } - -The png_set_gamma() function handles gamma transformations of the data. -Pass both the file gamma and the current screen_gamma. If the file does -not have a gamma value, you can pass one anyway if you have an idea what -it is (usually 0.45455 is a good guess for GIF images on PCs). Note -that file gammas are inverted from screen gammas. See the discussions -on gamma in the PNG specification for an excellent description of what -gamma is, and why all applications should support it. It is strongly -recommended that PNG viewers support gamma correction. - - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma(png_ptr, screen_gamma, gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - -If you need to reduce an RGB file to a paletted file, or if a paletted -file has more entries then will fit on your screen, png_set_dither() -will do that. Note that this is a simple match dither that merely -finds the closest color available. This should work fairly well with -optimized palettes, and fairly badly with linear color cubes. If you -pass a palette that is larger then maximum_colors, the file will -reduce the number of colors in the palette so it will fit into -maximum_colors. If there is a histogram, it will use it to make -more intelligent choices when reducing the palette. If there is no -histogram, it may not do as good a job. - - if (color_type & PNG_COLOR_MASK_COLOR) - { - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_PLTE)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, - &histogram); - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 1); - } - else - { - png_color std_color_cube[MAX_SCREEN_COLORS] = - { ... colors ... }; - - png_set_dither(png_ptr, std_color_cube, - MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, - NULL,0); - } - } - -PNG files describe monochrome as black being zero and white being one. -The following code will reverse this (make black be one and white be -zero): - - if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) - png_set_invert_mono(png_ptr); - -This function can also be used to invert grayscale and gray-alpha images: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_invert_mono(png_ptr); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code changes the storage to the -other way (little-endian, i.e. least significant bits first, the -way PCs store them): - - if (bit_depth == 16) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_read_user_transform_fn(png_ptr, - read_transform_fn); - -You must supply the function - - void read_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -after all of the other transformations have been processed. - -You can also set up a pointer to a user structure for use by your -callback function, and you can inform libpng that your transform -function will change the number of channels or bit depth with the -function - - png_set_user_transform_info(png_ptr, user_ptr, - user_depth, user_channels); - -The user's application, not libpng, is responsible for allocating and -freeing any memory required for the user structure. - -You can retrieve the pointer via the function -png_get_user_transform_ptr(). For example: - - voidp read_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -The last thing to handle is interlacing; this is covered in detail below, -but you must call the function here if you want libpng to handle expansion -of the interlaced image. - - number_of_passes = png_set_interlace_handling(png_ptr); - -After setting the transformations, libpng can update your png_info -structure to reflect any transformations you've requested with this -call. This is most useful to update the info structure's rowbytes -field so you can use it to allocate your image memory. This function -will also update your palette with the correct screen_gamma and -background if these have been given with the calls above. - - png_read_update_info(png_ptr, info_ptr); - -After you call png_read_update_info(), you can allocate any -memory you need to hold the image. The row data is simply -raw byte data for all forms of images. As the actual allocation -varies among applications, no example will be given. If you -are allocating one large chunk, you will need to build an -array of pointers to each row, as it will be needed for some -of the functions below. - -Reading image data - -After you've allocated memory, you can read the image data. -The simplest way to do this is in one function call. If you are -allocating enough memory to hold the whole image, you can just -call png_read_image() and libpng will read in all the image data -and put it in the memory area supplied. You will need to pass in -an array of pointers to each row. - -This function automatically handles interlacing, so you don't need -to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_read_rows(). - - png_read_image(png_ptr, row_pointers); - -where row_pointers is: - - png_bytep row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to read in the whole image at once, you can -use png_read_rows() instead. If there is no interlacing (check -interlace_type == PNG_INTERLACE_NONE), this is simple: - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -where row_pointers is the same as in the png_read_image() call. - -If you are doing this just one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - png_read_row(png_ptr, row_pointer, NULL); - -If the file is interlaced (interlace_type != 0 in the IHDR chunk), things -get somewhat harder. The only current (PNG Specification version 1.2) -interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) -is a somewhat complicated 2D interlace scheme, known as Adam7, that -breaks down an image into seven smaller images of varying size, based -on an 8x8 grid. - -libpng can fill out those images or it can give them to you "as is". -If you want them filled out, there are two ways to do that. The one -mentioned in the PNG specification is to expand each pixel to cover -those pixels that have not been read yet (the "rectangle" method). -This results in a blocky image for the first pass, which gradually -smooths out as more pixels are read. The other method is the "sparkle" -method, where pixels are drawn only in their final locations, with the -rest of the image remaining whatever colors they were initialized to -before the start of the read. The first method usually looks better, -but tends to be slower, as there are more pixels to put in the rows. - -If you don't want libpng to handle the interlacing details, just call -png_read_rows() seven times to read in all seven images. Each of the -images is a valid image by itself, or they can all be combined on an -8x8 grid to form a single image (although if you intend to combine them -you would be far better off using the libpng interlace handling). - -The first pass will return an image 1/8 as wide as the entire image -(every 8th column starting in column 0) and 1/8 as high as the original -(every 8th row starting in row 0), the second will be 1/8 as wide -(starting in column 4) and 1/8 as high (also starting in row 0). The -third pass will be 1/4 as wide (every 4th pixel starting in column 0) and -1/8 as high (every 8th row starting in row 4), and the fourth pass will -be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, -and every 4th row starting in row 0). The fifth pass will return an -image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), -while the sixth pass will be 1/2 as wide and 1/2 as high as the original -(starting in column 1 and row 0). The seventh and final pass will be as -wide as the original, and 1/2 as high, containing all of the odd -numbered scanlines. Phew! - -If you want libpng to expand the images, call this before calling -png_start_read_image() or png_read_update_info(): - - if (interlace_type == PNG_INTERLACE_ADAM7) - number_of_passes - = png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this -is seven, but may change if another interlace type is added. -This function can be called even if the file is not interlaced, -where it will return one pass. - -If you are not going to display the image after each pass, but are -going to wait until the entire image is read in, use the sparkle -effect. This effect is faster and the end result of either method -is exactly the same. If you are planning on displaying the image -after each pass, the "rectangle" effect is generally considered the -better looking one. - -If you only want the "sparkle" effect, just call png_read_rows() as -normal, with the third parameter NULL. Make sure you make pass over -the image number_of_passes times, and you don't change the data in the -rows between calls. You can change the locations of the data, just -not the data. Each pass only writes the pixels appropriate for that -pass, and assumes the data from previous passes is still valid. - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -If you only want the first effect (the rectangles), do the same as -before except pass the row buffer in the third parameter, and leave -the second parameter NULL. - - png_read_rows(png_ptr, NULL, row_pointers, - number_of_rows); - -Finishing a sequential read - -After you are finished reading the image through the -low-level interface, you can finish reading the file. If you are -interested in comments or time, which may be stored either before or -after the image data, you should pass the separate png_info struct if -you want to keep the comments from before and after the image -separate. If you are not interested, you can pass NULL. - - png_read_end(png_ptr, end_info); - -When you are done, you can free all memory allocated by libpng like this: - - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those -cases do nothing. The "seq" parameter is ignored if only one item -of the selected data type, such as PLTE, is allowed. If "seq" is not --1, and multiple items are allowed for the data type identified in -the mask, such as text or sPLT, only the n'th item in the structure -is freed, where n is "seq". - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -This function only affects data that has already been allocated. -You can call this function after reading the PNG data but before calling -any png_set_*() functions, to control whether the user or the png_set_*() -function is responsible for freeing any existing data that might be present, -and again after the png_set_*() functions to control whether the user -or png_destroy_*() is supposed to free the data. When the user assumes -responsibility for libpng-allocated data, the application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated your row_pointers in a single block, as suggested above in -the description of the high level read interface, you must not transfer -responsibility for freeing it to the png_set_rows or png_read_destroy function, -because they would also try to free the individual row_pointers[i]. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. - -The png_free_data() function will turn off the "valid" flag for anything -it frees. If you need to turn the flag off for a chunk that was freed by your -application instead of by libpng, you can use - - png_set_invalid(png_ptr, info_ptr, mask); - mask - identifies the chunks to be made invalid, - containing the bitwise OR of one or - more of - PNG_INFO_gAMA, PNG_INFO_sBIT, - PNG_INFO_cHRM, PNG_INFO_PLTE, - PNG_INFO_tRNS, PNG_INFO_bKGD, - PNG_INFO_hIST, PNG_INFO_pHYs, - PNG_INFO_oFFs, PNG_INFO_tIME, - PNG_INFO_pCAL, PNG_INFO_sRGB, - PNG_INFO_iCCP, PNG_INFO_sPLT, - PNG_INFO_sCAL, PNG_INFO_IDAT - -For a more compact example of reading a PNG image, see the file example.c. - -Reading PNG files progressively - -The progressive reader is slightly different then the non-progressive -reader. Instead of calling png_read_info(), png_read_rows(), and -png_read_end(), you make one call to png_process_data(), which calls -callbacks when it has the info, a row, or the end of the image. You -set up these callbacks with png_set_progressive_read_fn(). You don't -have to worry about the input/output functions of libpng, as you are -giving the library the data directly in png_process_data(). I will -assume that you have read the section on reading PNG files above, -so I will only highlight the differences (although I will show -all of the code). - -png_structp png_ptr; -png_infop info_ptr; - - /* An example code fragment of how you would - initialize the progressive reader in your - application. */ - int - initialize_png_reader() - { - png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, - (png_infopp)NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new. You can provide functions - to be called when the header info is valid, - when each row is completed, and when the image - is finished. If you aren't using all functions, - you can specify NULL parameters. Even when all - three functions are NULL, you need to call - png_set_progressive_read_fn(). You can use - any struct as the user_ptr (cast to a void pointer - for the function call), and retrieve the pointer - from inside the callbacks using the function - - png_get_progressive_ptr(png_ptr); - - which will return a void pointer, which you have - to cast appropriately. - */ - png_set_progressive_read_fn(png_ptr, (void *)user_ptr, - info_callback, row_callback, end_callback); - - return 0; - } - - /* A code fragment that you call as you receive blocks - of data */ - int - process_data(png_bytep buffer, png_uint_32 length) - { - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new also. Simply give it a chunk - of data from the file stream (in order, of - course). On machines with segmented memory - models machines, don't give it any more than - 64K. The library seems to run fine with sizes - of 4K. Although you can give it much less if - necessary (I assume you can give it chunks of - 1 byte, I haven't tried less then 256 bytes - yet). When this function returns, you may - want to display any rows that were generated - in the row callback if you don't already do - so there. - */ - png_process_data(png_ptr, info_ptr, buffer, length); - return 0; - } - - /* This function is called (as set by - png_set_progressive_read_fn() above) when enough data - has been supplied so all of the header has been - read. - */ - void - info_callback(png_structp png_ptr, png_infop info) - { - /* Do any setup here, including setting any of - the transformations mentioned in the Reading - PNG files section. For now, you _must_ call - either png_start_read_image() or - png_read_update_info() after all the - transformations are set (even if you don't set - any). You may start getting rows before - png_process_data() returns, so this is your - last chance to prepare for that. - */ - } - - /* This function is called when each row of image - data is complete */ - void - row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) - { - /* If the image is interlaced, and you turned - on the interlace handler, this function will - be called for every row in every pass. Some - of these rows will not be changed from the - previous pass. When the row is not changed, - the new_row variable will be NULL. The rows - and passes are called in order, so you don't - really need the row_num and pass, but I'm - supplying them because it may make your life - easier. - - For the non-NULL rows of interlaced images, - you must call png_progressive_combine_row() - passing in the row and the old row. You can - call this function for NULL rows (it will just - return) and for non-interlaced images (it just - does the memcpy for you) if it will make the - code easier. Thus, you can just do this for - all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, - new_row); - - /* where old_row is what was displayed for - previously for the row. Note that the first - pass (pass == 0, really) will completely cover - the old row, so the rows do not have to be - initialized. After the first pass (and only - for interlaced images), you will have to pass - the current row, and the function will combine - the old row and the new row. - */ - } - - void - end_callback(png_structp png_ptr, png_infop info) - { - /* This function is called after the whole image - has been read, including any chunks after the - image (up to and including the IEND). You - will usually have the same info chunk as you - had in the header, although some data may have - been added to the comments and time fields. - - Most people won't do much here, perhaps setting - a flag that marks the image as finished. - */ - } - - - -IV. Writing - -Much of this is very similar to reading. However, everything of -importance is repeated here, so you won't have to constantly look -back up in the reading section to understand writing. - -Setup - -You will want to do the I/O initialization before you get into libpng, -so if it doesn't work, you don't have anything to undo. If you are not -using the standard I/O functions, you will need to replace them with -custom writing functions. See the discussion under Customizing libpng. - - FILE *fp = fopen(file_name, "wb"); - if (!fp) - { - return (ERROR); - } - -Next, png_struct and png_info need to be allocated and initialized. -As these can be both relatively large, you may not want to store these -on the stack, unless you have stack space to spare. Of course, you -will want to check if they return NULL. If you are also reading, -you won't want to name your read structure and your write structure -both "png_ptr"; you can call them anything you like, such as -"read_ptr" and "write_ptr". Look at pngtest.c, for example. - - png_structp png_ptr = png_create_write_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_write_struct(&png_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_write_struct_2() instead of png_create_write_struct(): - - png_structp png_ptr = png_create_write_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -After you have these structures, you will need to set up the -error handling. When libpng encounters an error, it expects to -longjmp() back to your routine. Therefore, you will need to call -setjmp() and pass the png_jmpbuf(png_ptr). If you -write the file from different routines, you will need to update -the png_jmpbuf(png_ptr) every time you enter a new routine that will -call a png_*() function. See your documentation of setjmp/longjmp -for your compiler for more information on setjmp/longjmp. See -the discussion on libpng error handling in the Customizing Libpng -section below for more information on the libpng error handling. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return (ERROR); - } - ... - return; - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the output code. The default for libpng is to -use the C function fwrite(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. Again, if you wish to handle writing data in -another way, see the discussion on libpng I/O handling in the Customizing -Libpng section below. - - png_init_io(png_ptr, fp); - -If you are embedding your PNG into a datastream such as MNG, and don't -want libpng to write the 8-byte signature, or if you have already -written the signature in your application, use - - png_set_sig_bytes(png_ptr, 8); - -to inform libpng that it should not write a signature. - -Write callbacks - -At this point, you can set up a callback function that will be -called after each row has been written, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void write_row_callback(png_ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "write_row_callback") - -To inform libpng about your function, use - - png_set_write_status_fn(png_ptr, write_row_callback); - -You now have the option of modifying how the compression library will -run. The following functions are mainly for testing, but may be useful -in some cases, like if you need to write PNG files extremely fast and -are willing to give up some compression, or if you want to get the -maximum possible compression at the expense of slower writing. If you -have no special needs in this area, let the library do what it wants by -not calling this function at all, as it has been tuned to deliver a good -speed/compression ratio. The second parameter to png_set_filter() is -the filter method, for which the only valid values are 0 (as of the -July 1999 PNG specification, version 1.2) or 64 (if you are writing -a PNG datastream that is to be embedded in a MNG datastream). The third -parameter is a flag that indicates which filter type(s) are to be tested -for each scanline. See the PNG specification for details on the specific filter -types. - - - /* turn on or off filtering, and/or choose - specific filters. You can use either a single - PNG_FILTER_VALUE_NAME or the bitwise OR of one - or more PNG_FILTER_NAME masks. */ - png_set_filter(png_ptr, 0, - PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | - PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | - PNG_FILTER_UP | PNG_FILTER_VALUE_UP | - PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | - PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| - PNG_ALL_FILTERS); - -If an application -wants to start and stop using particular filters during compression, -it should start out with all of the filters (to ensure that the previous -row of pixels will be stored in case it's needed later), and then add -and remove them after the start of compression. - -If you are writing a PNG datastream that is to be embedded in a MNG -datastream, the second parameter can be either 0 or 64. - -The png_set_compression_*() functions interface to the zlib compression -library, and should mostly be ignored unless you really know what you are -doing. The only generally useful call is png_set_compression_level() -which changes how much time zlib spends on trying to compress the image -data. See the Compression Library (zlib.h and algorithm.txt, distributed -with zlib) for details on the compression levels. - - /* set the zlib compression level */ - png_set_compression_level(png_ptr, - Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr, - Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192) - -extern PNG_EXPORT(void,png_set_zbuf_size) - -Setting the contents of info for output - -You now need to fill in the png_info structure with all the data you -wish to write before the actual image. Note that the only thing you -are allowed to write after the image is the text chunks and the time -chunk (as of PNG Specification 1.2, anyway). See png_write_end() and -the latest PNG specification for more information on that. If you -wish to write them before the image, fill them in now, and flag that -data as being valid. If you want to wait until after the data, don't -fill them until png_write_end(). For all the fields in png_info and -their data types, see png.h. For explanations of what the fields -contain, see the PNG specification. - -Some of the more important parts of the png_info are: - - png_set_IHDR(png_ptr, info_ptr, width, height, - bit_depth, color_type, interlace_type, - compression_type, filter_method) - width - holds the width of the image - in pixels (up to 2^31). - height - holds the height of the image - in pixels (up to 2^31). - bit_depth - holds the bit depth of one of the - image channels. - (valid values are 1, 2, 4, 8, 16 - and depend also on the - color_type. See also significant - bits (sBIT) below). - color_type - describes which color/alpha - channels are present. - PNG_COLOR_TYPE_GRAY - (bit depths 1, 2, 4, 8, 16) - PNG_COLOR_TYPE_GRAY_ALPHA - (bit depths 8, 16) - PNG_COLOR_TYPE_PALETTE - (bit depths 1, 2, 4, 8) - PNG_COLOR_TYPE_RGB - (bit_depths 8, 16) - PNG_COLOR_TYPE_RGB_ALPHA - (bit_depths 8, 16) - - PNG_COLOR_MASK_PALETTE - PNG_COLOR_MASK_COLOR - PNG_COLOR_MASK_ALPHA - - interlace_type - PNG_INTERLACE_NONE or - PNG_INTERLACE_ADAM7 - compression_type - (must be - PNG_COMPRESSION_TYPE_DEFAULT) - filter_method - (must be PNG_FILTER_TYPE_DEFAULT - or, if you are writing a PNG to - be embedded in a MNG datastream, - can also be - PNG_INTRAPIXEL_DIFFERENCING) - -If you call png_set_IHDR(), the call must appear before any of the -other png_set_*() functions, because they might require access to some of -the IHDR settings. The remaining png_set_*() functions can be called -in any order. - -If you wish, you can reset the compression_type, interlace_type, or -filter_method later by calling png_set_IHDR() again; if you do this, the -width, height, bit_depth, and color_type must be the same in each call. - - png_set_PLTE(png_ptr, info_ptr, palette, - num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_set_gAMA(png_ptr, info_ptr, gamma); - gamma - the gamma the image was created - at (PNG_INFO_gAMA) - - png_set_sRGB(png_ptr, info_ptr, srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of - the sRGB chunk means that the pixel - data is in the sRGB color space. - This chunk also implies specific - values of gAMA and cHRM. Rendering - intent is the CSS-1 property that - has been defined by the International - Color Consortium - (http://www.color.org). - It can be one of - PNG_sRGB_INTENT_SATURATION, - PNG_sRGB_INTENT_PERCEPTUAL, - PNG_sRGB_INTENT_ABSOLUTE, or - PNG_sRGB_INTENT_RELATIVE. - - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, - srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of the - sRGB chunk means that the pixel - data is in the sRGB color space. - This function also causes gAMA and - cHRM chunks with the specific values - that are consistent with sRGB to be - written. - - png_set_iCCP(png_ptr, info_ptr, name, compression_type, - profile, proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_set_sBIT(png_ptr, info_ptr, sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, red, - green, and blue channels, whichever are - appropriate for the given color type - (png_color_16) - - png_set_tRNS(png_ptr, info_ptr, trans, num_trans, - trans_values); - trans - array of transparent entries for - palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values - (in order red, green, blue) of the - single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_set_hIST(png_ptr, info_ptr, hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_set_tIME(png_ptr, info_ptr, mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_set_bKGD(png_ptr, info_ptr, background); - background - background color (PNG_VALID_bKGD) - - png_set_text(png_ptr, info_ptr, text_ptr, num_text); - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be NULL or empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (NULL or - empty for unknown). - text_ptr[i].translated_keyword - keyword in UTF-8 (NULL - or empty for unknown). - num_text - number of comments - - png_set_sPLT(png_ptr, info_ptr, &palette_ptr, - num_spalettes); - palette_ptr - array of png_sPLT_struct structures - to be added to the list of palettes - in the info structure. - num_spalettes - number of palette structures to be - added. - - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, - unit_type); - offset_x - positive offset from the left - edge of the screen - offset_y - positive offset from the top - edge of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, - unit_type); - res_x - pixels/unit physical resolution - in x direction - res_y - pixels/unit physical resolution - in y direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_set_sCAL(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, - num_unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position to write chunk in file - 0: do not write chunk - PNG_HAVE_IHDR: before PLTE - PNG_HAVE_PLTE: before IDAT - PNG_AFTER_IDAT: after IDAT - -The "location" member is set automatically according to -what part of the output file has already been written. -You can change its value after calling png_set_unknown_chunks() -as demonstrated in pngtest.c. Within each of the "locations", -the chunks are sequenced according to their position in the -structure (that is, the value of "i", which is the order in which -the chunk was either read from the input file or defined with -png_set_unknown_chunks). - -A quick word about text and num_text. text is an array of png_text -structures. num_text is the number of valid structures in the array. -Each png_text structure holds a language code, a keyword, a text value, -and a compression type. - -The compression types have the same valid numbers as the compression -types of the image data. Currently, the only valid number is zero. -However, you can store text either compressed or uncompressed, unlike -images, which always have to be compressed. So if you don't want the -text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. -Because tEXt and zTXt chunks don't have a language field, if you -specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt -any language code or translated keyword will not be written out. - -Until text gets around 1000 bytes, it is not worth compressing it. -After the text has been written out to the file, the compression type -is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, -so that it isn't written out again at the end (in case you are calling -png_write_end() with the same struct. - -The keywords that are given in the PNG Specification are: - - Title Short (one line) title or - caption for image - Author Name of image's creator - Description Description of image (possibly long) - Copyright Copyright notice - Creation Time Time of original image creation - (usually RFC 1123 format, see below) - Software Software used to create the image - Disclaimer Legal disclaimer - Warning Warning of nature of content - Source Device used to create the image - Comment Miscellaneous comment; conversion - from other image format - -The keyword-text pairs work like this. Keywords should be short -simple descriptions of what the comment is about. Some typical -keywords are found in the PNG specification, as is some recommendations -on keywords. You can repeat keywords in a file. You can even write -some text before the image and some after. For example, you may want -to put a description of the image before the image, but leave the -disclaimer until after, so viewers working over modem connections -don't have to wait for the disclaimer to go over the modem before -they start seeing the image. Finally, keywords should be full -words, not abbreviations. Keywords and text are in the ISO 8859-1 -(Latin-1) character set (a superset of regular ASCII) and can not -contain NUL characters, and should not contain control or other -unprintable characters. To make the comments widely readable, stick -with basic ASCII, and avoid machine specific character set extensions -like the IBM-PC character set. The keyword must be present, but -you can leave off the text string on non-compressed pairs. -Compressed pairs must have a text string, as only the text string -is compressed anyway, so the compression would be meaningless. - -PNG supports modification time via the png_time structure. Two -conversion routines are provided, png_convert_from_time_t() for -time_t and png_convert_from_struct_tm() for struct tm. The -time_t routine uses gmtime(). You don't have to use either of -these, but if you wish to fill in the png_time structure directly, -you should provide the time in universal time (GMT) if possible -instead of your local time. Note that the year number is the full -year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and -that months start with 1. - -If you want to store the time of the original image creation, you should -use a plain tEXt chunk with the "Creation Time" keyword. This is -necessary because the "creation time" of a PNG image is somewhat vague, -depending on whether you mean the PNG file, the time the image was -created in a non-PNG format, a still photo from which the image was -scanned, or possibly the subject matter itself. In order to facilitate -machine-readable dates, it is recommended that the "Creation Time" -tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), -although this isn't a requirement. Unlike the tIME chunk, the -"Creation Time" tEXt chunk is not expected to be automatically changed -by the software. To facilitate the use of RFC 1123 dates, a function -png_convert_to_rfc1123(png_timep) is provided to convert from PNG -time to an RFC 1123 format string. - -Writing unknown chunks - -You can use the png_set_unknown_chunks function to queue up chunks -for writing. You give it a chunk name, raw data, and a size; that's -all there is to it. The chunks will be written by the next following -png_write_info_before_PLTE, png_write_info, or png_write_end function. -Any chunks previously read into the info structure's unknown-chunk -list will also be written out in a sequence that satisfies the PNG -specification's ordering rules. - -The high-level write interface - -At this point there are two ways to proceed; through the high-level -write interface, or through a sequence of low-level write operations. -You can use the high-level interface if your image data is present -in the info structure. All defined output -transformations are permitted, enabled by the following masks. - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - PNG_TRANSFORM_STRIP_FILLER Strip out filler - bytes (deprecated). - PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading - filler bytes - PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing - filler bytes - -If you have valid image data in the info structure (you can use -png_set_rows() to put image data in the info structure), simply do this: - - png_write_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of some set of -transformation flags. This call is equivalent to png_write_info(), -followed the set of transformations indicated by the transform mask, -then png_write_image(), and finally png_write_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future output transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_write_png(). - -The low-level write interface - -If you are going the low-level route instead, you are now ready to -write all the file information up to the actual image data. You do -this with a call to png_write_info(). - - png_write_info(png_ptr, info_ptr); - -Note that there is one transformation you may need to do before -png_write_info(). In PNG files, the alpha channel in an image is the -level of opacity. If your data is supplied as a level of -transparency, you can invert the alpha channel before you write it, so -that 0 is fully transparent and 255 (in 8-bit or paletted images) or -65535 (in 16-bit images) is fully opaque, with - - png_set_invert_alpha(png_ptr); - -This must appear before png_write_info() instead of later with the -other transformations because in the case of paletted images the tRNS -chunk data has to be inverted before the tRNS chunk is written. If -your image is not a paletted image, the tRNS data (which in such cases -represents a single color to be rendered as transparent) won't need to -be changed, and you can safely do this transformation after your -png_write_info() call. - -If you need to write a private chunk that you want to appear before -the PLTE chunk when PLTE is present, you can write the PNG info in -two steps, and insert code to write your own chunk between them: - - png_write_info_before_PLTE(png_ptr, info_ptr); - png_set_unknown_chunks(png_ptr, info_ptr, ...); - png_write_info(png_ptr, info_ptr); - -After you've written the file information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -PNG files store RGB pixels packed into 3 or 6 bytes. This code tells -the library to strip input data that has 4 or 8 bytes per pixel down -to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 -bytes per pixel). - - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - -where the 0 is unused, and the location is either PNG_FILLER_BEFORE or -PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel -is stored XRGB or RGBX. - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit files. -If the data is supplied at 1 pixel per byte, use this code, which will -correctly pack the pixels into a single byte: - - png_set_packing(png_ptr); - -PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your -data is of another bit depth, you can write an sBIT chunk into the -file so that decoders can recover the original data if desired. - - /* Set the true bit depth of the image data */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit.red = true_bit_depth; - sig_bit.green = true_bit_depth; - sig_bit.blue = true_bit_depth; - } - else - { - sig_bit.gray = true_bit_depth; - } - if (color_type & PNG_COLOR_MASK_ALPHA) - { - sig_bit.alpha = true_bit_depth; - } - - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - -If the data is stored in the row buffer in a bit depth other than -one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), -this will scale the values to appear to be the correct bit depth as -is required by PNG. - - png_set_shift(png_ptr, &sig_bit); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code would be used if they are -supplied the other way (little-endian, i.e. least significant bits -first, the way PCs store them): - - if (bit_depth > 8) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -PNG files store 3 color pixels in red, green, blue order. This code -would be used if they are supplied as blue, green, red: - - png_set_bgr(png_ptr); - -PNG files describe monochrome as black being zero and white being -one. This code would be used if the pixels are supplied with this reversed -(black being one and white being zero): - - png_set_invert_mono(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_write_user_transform_fn(png_ptr, - write_transform_fn); - -You must supply the function - - void write_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -before any of the other transformations are processed. - -You can also set up a pointer to a user structure for use by your -callback function. - - png_set_user_transform_info(png_ptr, user_ptr, 0, 0); - -The user_channels and user_depth parameters of this function are ignored -when writing; you can set them to zero as shown. - -You can retrieve the pointer via the function png_get_user_transform_ptr(). -For example: - - voidp write_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -It is possible to have libpng flush any pending output, either manually, -or automatically after a certain number of lines have been written. To -flush the output stream a single time call: - - png_write_flush(png_ptr); - -and to have libpng flush the output stream periodically after a certain -number of scanlines have been written, call: - - png_set_flush(png_ptr, nrows); - -Note that the distance between rows is from the last time png_write_flush() -was called, or the first row of the image if it has never been called. -So if you write 50 lines, and then png_set_flush 25, it will flush the -output on the next scanline, and every 25 lines thereafter, unless -png_write_flush() is called before 25 more lines have been written. -If nrows is too small (less than about 10 lines for a 640 pixel wide -RGB image) the image compression may decrease noticeably (although this -may be acceptable for real-time applications). Infrequent flushing will -only degrade the compression performance by a few percent over images -that do not use flushing. - -Writing the image data - -That's it for the transformations. Now you can write the image data. -The simplest way to do this is in one function call. If you have the -whole image in memory, you can just call png_write_image() and libpng -will write the image. You will need to pass in an array of pointers to -each row. This function automatically handles interlacing, so you don't -need to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_write_rows(). - - png_write_image(png_ptr, row_pointers); - -where row_pointers is: - - png_byte *row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to write the whole image at once, you can -use png_write_rows() instead. If the file is not interlaced, -this is simple: - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -row_pointers is the same as in the png_write_image() call. - -If you are just writing one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - - png_write_row(png_ptr, row_pointer); - -When the file is interlaced, things can get a good deal more -complicated. The only currently (as of the PNG Specification -version 1.2, dated July 1999) defined interlacing scheme for PNG files -is the "Adam7" interlace scheme, that breaks down an -image into seven smaller images of varying size. libpng will build -these images for you, or you can do them yourself. If you want to -build them yourself, see the PNG specification for details of which -pixels to write when. - -If you don't want libpng to handle the interlacing details, just -use png_set_interlace_handling() and call png_write_rows() the -correct number of times to write all seven sub-images. - -If you want libpng to build the sub-images, call this before you start -writing any rows: - - number_of_passes = - png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this -is seven, but may change if another interlace type is added. - -Then write the complete image number_of_passes times. - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -As some of these rows are not used, and thus return immediately, -you may want to read about interlacing in the PNG specification, -and only update the rows that are actually used. - -Finishing a sequential write - -After you are finished writing the image, you should finish writing -the file. If you are interested in writing comments or time, you should -pass an appropriately filled png_info pointer. If you are not interested, -you can pass NULL. - - png_write_end(png_ptr, info_ptr); - -When you are done, you can free all memory used by libpng like this: - - png_destroy_write_struct(&png_ptr, &info_ptr); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those -cases do nothing. The "seq" parameter is ignored if only one item -of the selected data type, such as PLTE, is allowed. If "seq" is not --1, and multiple items are allowed for the data type identified in -the mask, such as text or sPLT, only the n'th item in the structure -is freed, where n is "seq". - -If you allocated data such as a palette that you passed -in to libpng with png_set_*, you must not free it until just before the call to -png_destroy_write_struct(). - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -For example, to transfer responsibility for some data from a read structure -to a write structure, you could use - - png_data_freer(read_ptr, read_info_ptr, - PNG_USER_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - png_data_freer(write_ptr, write_info_ptr, - PNG_DESTROY_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - -thereby briefly reassigning responsibility for freeing to the user but -immediately afterwards reassigning it once more to the write_destroy -function. Having done this, it would then be safe to destroy the read -structure and continue to use the PLTE, tRNS, and hIST data in the write -structure. - -This function only affects data that has already been allocated. -You can call this function before calling after the png_set_*() functions -to control whether the user or png_destroy_*() is supposed to free the data. -When the user assumes responsibility for libpng-allocated data, the -application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. -For a more compact example of writing a PNG image, see the file example.c. - -V. Modifying/Customizing libpng: - -There are two issues here. The first is changing how libpng does -standard things like memory allocation, input/output, and error handling. -The second deals with more complicated things like adding new chunks, -adding new transformations, and generally changing how libpng works. -Both of those are compile-time issues; that is, they are generally -determined at the time the code is written, and there is rarely a need -to provide the user with a means of changing them. - -Memory allocation, input/output, and error handling - -All of the memory allocation, input/output, and error handling in libpng -goes through callbacks that are user-settable. The default routines are -in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change -these functions, call the appropriate png_set_*_fn() function. - -Memory allocation is done through the functions png_malloc() -and png_free(). These currently just call the standard C functions. If -your pointers can't access more then 64K at a time, you will want to set -MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling -memory allocation on a platform will change between applications, these -functions must be modified in the library at compile time. If you prefer -to use a different method of allocating and freeing data, you can use -png_create_read_struct_2() or png_create_write_struct_2() to register -your own functions as described above. -These functions also provide a void pointer that can be retrieved via - - mem_ptr=png_get_mem_ptr(png_ptr); - -Your replacement memory functions must have prototypes as follows: - - png_voidp malloc_fn(png_structp png_ptr, - png_size_t size); - void free_fn(png_structp png_ptr, png_voidp ptr); - -Your malloc_fn() must return NULL in case of failure. The png_malloc() -function will normally call png_error() if it receives a NULL from the -system memory allocator or from your replacement malloc_fn(). - -Your free_fn() will never be called with a NULL ptr, since libpng's -png_free() checks for NULL before calling free_fn(). - -Input/Output in libpng is done through png_read() and png_write(), -which currently just call fread() and fwrite(). The FILE * is stored in -png_struct and is initialized via png_init_io(). If you wish to change -the method of I/O, the library supplies callbacks that you can set -through the function png_set_read_fn() and png_set_write_fn() at run -time, instead of calling the png_init_io() function. These functions -also provide a void pointer that can be retrieved via the function -png_get_io_ptr(). For example: - - png_set_read_fn(png_structp read_ptr, - voidp read_io_ptr, png_rw_ptr read_data_fn) - - png_set_write_fn(png_structp write_ptr, - voidp write_io_ptr, png_rw_ptr write_data_fn, - png_flush_ptr output_flush_fn); - - voidp read_io_ptr = png_get_io_ptr(read_ptr); - voidp write_io_ptr = png_get_io_ptr(write_ptr); - -The replacement I/O functions must have prototypes as follows: - - void user_read_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_write_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_flush_data(png_structp png_ptr); - -The user_read_data() function is responsible for detecting and -handling end-of-data errors. - -Supplying NULL for the read, write, or flush functions sets them back -to using the default C stream functions, which expect the io_ptr to -point to a standard *FILE structure. It is probably a mistake -to use NULL for one of write_data_fn and output_flush_fn but not both -of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. -It is an error to read from a write stream, and vice versa. - -Error handling in libpng is done through png_error() and png_warning(). -Errors handled through png_error() are fatal, meaning that png_error() -should never return to its caller. Currently, this is handled via -setjmp() and longjmp() (unless you have compiled libpng with -PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), -but you could change this to do things like exit() if you should wish. - -On non-fatal errors, png_warning() is called -to print a warning message, and then control returns to the calling code. -By default png_error() and png_warning() print a message on stderr via -fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined -(because you don't want the messages) or PNG_NO_STDIO defined (because -fprintf() isn't available). If you wish to change the behavior of the error -functions, you will need to set up your own message callbacks. These -functions are normally supplied at the time that the png_struct is created. -It is also possible to redirect errors and warnings to your own replacement -functions after png_create_*_struct() has been called by calling: - - png_set_error_fn(png_structp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warning_fn); - - png_voidp error_ptr = png_get_error_ptr(png_ptr); - -If NULL is supplied for either error_fn or warning_fn, then the libpng -default function will be used, calling fprintf() and/or longjmp() if a -problem is encountered. The replacement error functions should have -parameters as follows: - - void user_error_fn(png_structp png_ptr, - png_const_charp error_msg); - void user_warning_fn(png_structp png_ptr, - png_const_charp warning_msg); - -The motivation behind using setjmp() and longjmp() is the C++ throw and -catch exception handling methods. This makes the code much easier to write, -as there is no need to check every return code of every function call. -However, there are some uncertainties about the status of local variables -after a longjmp, so the user may want to be careful about doing anything after -setjmp returns non-zero besides returning itself. Consult your compiler -documentation for more details. For an alternative approach, you may wish -to use the "cexcept" facility (see http://cexcept.sourceforge.net). - -Custom chunks - -If you need to read or write custom chunks, you may need to get deeper -into the libpng code. The library now has mechanisms for storing -and writing chunks of unknown type; you can even declare callbacks -for custom chunks. However, this may not be good enough if the -library code itself needs to know about interactions between your -chunk and existing `intrinsic' chunks. - -If you need to write a new intrinsic chunk, first read the PNG -specification. Acquire a first level of -understanding of how it works. Pay particular attention to the -sections that describe chunk names, and look at how other chunks were -designed, so you can do things similarly. Second, check out the -sections of libpng that read and write chunks. Try to find a chunk -that is similar to yours and use it as a template. More details can -be found in the comments inside the code. It is best to handle unknown -chunks in a generic method, via callback functions, instead of by -modifying libpng functions. - -If you wish to write your own transformation for the data, look through -the part of the code that does the transformations, and check out some of -the simpler ones to get an idea of how they work. Try to find a similar -transformation to the one you want to add and copy off of it. More details -can be found in the comments inside the code itself. - -Configuring for 16 bit platforms - -You will want to look into zconf.h to tell zlib (and thus libpng) that -it cannot allocate more then 64K at a time. Even if you can, the memory -won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. - -Configuring for DOS - -For DOS users who only have access to the lower 640K, you will -have to limit zlib's memory usage via a png_set_compression_mem_level() -call. See zlib.h or zconf.h in the zlib library for more information. - -Configuring for Medium Model - -Libpng's support for medium model has been tested on most of the popular -compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets -defined, and FAR gets defined to far in pngconf.h, and you should be -all set. Everything in the library (except for zlib's structure) is -expecting far data. You must use the typedefs with the p or pp on -the end for pointers (or at least look at them and be careful). Make -note that the rows of data are defined as png_bytepp, which is an -unsigned char far * far *. - -Configuring for gui/windowing platforms: - -You will need to write new error and warning functions that use the GUI -interface, as described previously, and set them to be the error and -warning functions at the time that png_create_*_struct() is called, -in order to have them available during the structure initialization. -They can be changed later via png_set_error_fn(). On some compilers, -you may also have to change the memory allocators (png_malloc, etc.). - -Configuring for compiler xxx: - -All includes for libpng are in pngconf.h. If you need to add, change -or delete an include, this is the place to do it. -The includes that are not needed outside libpng are protected by the -PNG_INTERNAL definition, which is only defined for those routines inside -libpng itself. The files in libpng proper only include png.h, which -includes pngconf.h. - -Configuring zlib: - -There are special functions to configure the compression. Perhaps the -most useful one changes the compression level, which currently uses -input compression values in the range 0 - 9. The library normally -uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests -have shown that for a large majority of images, compression values in -the range 3-6 compress nearly as well as higher levels, and do so much -faster. For online applications it may be desirable to have maximum speed -(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also -specify no compression (Z_NO_COMPRESSION = 0), but this would create -files larger than just storing the raw bitmap. You can specify the -compression level by calling: - - png_set_compression_level(png_ptr, level); - -Another useful one is to reduce the memory level used by the library. -The memory level defaults to 8, but it can be lowered if you are -short on memory (running DOS, for example, where you only have 640K). -Note that the memory level does have an effect on compression; among -other things, lower levels will result in sections of incompressible -data being emitted in smaller stored blocks, with a correspondingly -larger relative overhead of up to 15% in the worst case. - - png_set_compression_mem_level(png_ptr, level); - -The other functions are for configuring zlib. They are not recommended -for normal use and may result in writing an invalid PNG file. See -zlib.h for more information on what these mean. - - png_set_compression_strategy(png_ptr, - strategy); - png_set_compression_window_bits(png_ptr, - window_bits); - png_set_compression_method(png_ptr, method); - png_set_compression_buffer_size(png_ptr, size); - -Controlling row filtering - -If you want to control whether libpng uses filtering or not, which -filters are used, and how it goes about picking row filters, you -can call one of these functions. The selection and configuration -of row filters can have a significant impact on the size and -encoding speed and a somewhat lesser impact on the decoding speed -of an image. Filtering is enabled by default for RGB and grayscale -images (with and without alpha), but not for paletted images nor -for any images with bit depths less than 8 bits/pixel. - -The 'method' parameter sets the main filtering method, which is -currently only '0' in the PNG 1.2 specification. The 'filters' -parameter sets which filter(s), if any, should be used for each -scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS -to turn filtering on and off, respectively. - -Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, -PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise -ORed together with '|' to specify one or more filters to use. -These filters are described in more detail in the PNG specification. -If you intend to change the filter type during the course of writing -the image, you should start with flags set for all of the filters -you intend to use so that libpng can initialize its internal -structures appropriately for all of the filter types. (Note that this -means the first row must always be adaptively filtered, because libpng -currently does not allocate the filter buffers until png_write_row() -is called for the first time.) - - filters = PNG_FILTER_NONE | PNG_FILTER_SUB - PNG_FILTER_UP | PNG_FILTER_AVG | - PNG_FILTER_PAETH | PNG_ALL_FILTERS; - - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, - filters); - The second parameter can also be - PNG_INTRAPIXEL_DIFFERENCING if you are - writing a PNG to be embedded in a MNG - datastream. This parameter must be the - same as the value of filter_method used - in png_set_IHDR(). - -It is also possible to influence how libpng chooses from among the -available filters. This is done in one or both of two ways - by -telling it how important it is to keep the same filter for successive -rows, and by telling it the relative computational costs of the filters. - - double weights[3] = {1.5, 1.3, 1.1}, - costs[PNG_FILTER_VALUE_LAST] = - {1.0, 1.3, 1.3, 1.5, 1.7}; - - png_set_filter_heuristics(png_ptr, - PNG_FILTER_HEURISTIC_WEIGHTED, 3, - weights, costs); - -The weights are multiplying factors that indicate to libpng that the -row filter should be the same for successive rows unless another row filter -is that many times better than the previous filter. In the above example, -if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a -"sum of absolute differences" 1.5 x 1.3 times higher than other filters -and still be chosen, while the NONE filter could have a sum 1.1 times -higher than other filters and still be chosen. Unspecified weights are -taken to be 1.0, and the specified weights should probably be declining -like those above in order to emphasize recent filters over older filters. - -The filter costs specify for each filter type a relative decoding cost -to be considered when selecting row filters. This means that filters -with higher costs are less likely to be chosen over filters with lower -costs, unless their "sum of absolute differences" is that much smaller. -The costs do not necessarily reflect the exact computational speeds of -the various filters, since this would unduly influence the final image -size. - -Note that the numbers above were invented purely for this example and -are given only to help explain the function usage. Little testing has -been done to find optimum values for either the costs or the weights. - -Removing unwanted object code - -There are a bunch of #define's in pngconf.h that control what parts of -libpng are compiled. All the defines end in _SUPPORTED. If you are -never going to use a capability, you can change the #define to #undef -before recompiling libpng and save yourself code and data space, or -you can turn off individual capabilities with defines that begin with -PNG_NO_. - -You can also turn all of the transforms and ancillary chunk capabilities -off en masse with compiler directives that define -PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, -or all four, -along with directives to turn on any of the capabilities that you do -want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable -the extra transformations but still leave the library fully capable of reading -and writing PNG files with all known public chunks -Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive -produces a library that is incapable of reading or writing ancillary chunks. -If you are not using the progressive reading capability, you can -turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse -this with the INTERLACING capability, which you'll still have). - -All the reading and writing specific code are in separate files, so the -linker should only grab the files it needs. However, if you want to -make sure, or if you are building a stand alone library, all the -reading files start with pngr and all the writing files start with -pngw. The files that don't match either (like png.c, pngtrans.c, etc.) -are used for both reading and writing, and always need to be included. -The progressive reader is in pngpread.c - -If you are creating or distributing a dynamically linked library (a .so -or DLL file), you should not remove or disable any parts of the library, -as this will cause applications linked with different versions of the -library to fail if they call functions not available in your library. -The size of the library itself should not be an issue, because only -those sections that are actually used will be loaded into memory. - -Requesting debug printout - -The macro definition PNG_DEBUG can be used to request debugging -printout. Set it to an integer value in the range 0 to 3. Higher -numbers result in increasing amounts of debugging information. The -information is printed to the "stderr" file, unless another file -name is specified in the PNG_DEBUG_FILE macro definition. - -When PNG_DEBUG > 0, the following functions (macros) become available: - - png_debug(level, message) - png_debug1(level, message, p1) - png_debug2(level, message, p1, p2) - -in which "level" is compared to PNG_DEBUG to decide whether to print -the message, "message" is the formatted string to be printed, -and p1 and p2 are parameters that are to be embedded in the string -according to printf-style formatting directives. For example, - - png_debug1(2, "foo=%d\n", foo); - -is expanded to - - if(PNG_DEBUG > 2) - fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); - -When PNG_DEBUG is defined but is zero, the macros aren't defined, but you -can still use PNG_DEBUG to control your own debugging: - - #ifdef PNG_DEBUG - fprintf(stderr, ... - #endif - -When PNG_DEBUG = 1, the macros are defined, but only png_debug statements -having level = 0 will be printed. There aren't any such statements in -this version of libpng, but if you insert some they will be printed. - -VI. MNG support - -The MNG specification (available at http://www.libpng.org/pub/mng) allows -certain extensions to PNG for PNG images that are embedded in MNG datastreams. -Libpng can support some of these extensions. To enable them, use the -png_permit_mng_features() function: - - feature_set = png_permit_mng_features(png_ptr, mask) - mask is a png_uint_32 containing the bitwise OR of the - features you want to enable. These include - PNG_FLAG_MNG_EMPTY_PLTE - PNG_FLAG_MNG_FILTER_64 - PNG_ALL_MNG_FEATURES - feature_set is a png_uint_32 that is the bitwise AND of - your mask with the set of MNG features that is - supported by the version of libpng that you are using. - -It is an error to use this function when reading or writing a standalone -PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped -in a MNG datastream. As a minimum, it must have the MNG 8-byte signature -and the MHDR and MEND chunks. Libpng does not provide support for these -or any other MNG chunks; your application must provide its own support for -them. You may wish to consider using libmng (available at -http://www.libmng.com) instead. - -VII. Changes to Libpng from version 0.88 - -It should be noted that versions of libpng later than 0.96 are not -distributed by the original libpng author, Guy Schalnat, nor by -Andreas Dilger, who had taken over from Guy during 1996 and 1997, and -distributed versions 0.89 through 0.96, but rather by another member -of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are -still alive and well, but they have moved on to other things. - -The old libpng functions png_read_init(), png_write_init(), -png_info_init(), png_read_destroy(), and png_write_destroy() have been -moved to PNG_INTERNAL in version 0.95 to discourage their use. These -functions will be removed from libpng version 2.0.0. - -The preferred method of creating and initializing the libpng structures is -via the png_create_read_struct(), png_create_write_struct(), and -png_create_info_struct() because they isolate the size of the structures -from the application, allow version error checking, and also allow the -use of custom error handling routines during the initialization, which -the old functions do not. The functions png_read_destroy() and -png_write_destroy() do not actually free the memory that libpng -allocated for these structs, but just reset the data structures, so they -can be used instead of png_destroy_read_struct() and -png_destroy_write_struct() if you feel there is too much system overhead -allocating and freeing the png_struct for each image read. - -Setting the error callbacks via png_set_message_fn() before -png_read_init() as was suggested in libpng-0.88 is no longer supported -because this caused applications that do not use custom error functions -to fail if the png_ptr was not initialized to zero. It is still possible -to set the error callbacks AFTER png_read_init(), or to change them with -png_set_error_fn(), which is essentially the same function, but with a new -name to force compilation errors with applications that try to use the old -method. - -Starting with version 1.0.7, you can find out which version of the library -you are using at run-time: - - png_uint_32 libpng_vn = png_access_version_number(); - -The number libpng_vn is constructed from the major version, minor -version with leading zero, and release number with leading zero, -(e.g., libpng_vn for version 1.0.7 is 10007). - -You can also check which version of png.h you used when compiling your -application: - - png_uint_32 application_vn = PNG_LIBPNG_VER; - -VIII. Changes to Libpng from version 1.0.x to 1.2.x - -Support for user memory management was enabled by default. To -accomplish this, the functions png_create_read_struct_2(), -png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), -png_malloc_default(), and png_free_default() were added. - -Support for certain MNG features was enabled. - -Support for numbered error messages was added. However, we never got -around to actually numbering the error messages. The function -png_set_strip_error_numbers() was added (Note: the prototype for this -function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE -builds of libpng-1.2.15. It was restored in libpng-1.2.36). - -The png_malloc_warn() function was added at libpng-1.2.3. This issues -a png_warning and returns NULL instead of aborting when it fails to -acquire the requested memory allocation. - -Support for setting user limits on image width and height was enabled -by default. The functions png_set_user_limits(), png_get_user_width_max(), -and png_get_user_height_max() were added at libpng-1.2.6. - -The png_set_add_alpha() function was added at libpng-1.2.7. - -The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. -Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the -tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is -deprecated. - -A number of macro definitions in support of runtime selection of -assembler code features (especially Intel MMX code support) were -added at libpng-1.2.0: - - PNG_ASM_FLAG_MMX_SUPPORT_COMPILED - PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU - PNG_ASM_FLAG_MMX_READ_COMBINE_ROW - PNG_ASM_FLAG_MMX_READ_INTERLACE - PNG_ASM_FLAG_MMX_READ_FILTER_SUB - PNG_ASM_FLAG_MMX_READ_FILTER_UP - PNG_ASM_FLAG_MMX_READ_FILTER_AVG - PNG_ASM_FLAG_MMX_READ_FILTER_PAETH - PNG_ASM_FLAGS_INITIALIZED - PNG_MMX_READ_FLAGS - PNG_MMX_FLAGS - PNG_MMX_WRITE_FLAGS - PNG_MMX_FLAGS - -We added the following functions in support of runtime -selection of assembler code features: - - png_get_mmx_flagmask() - png_set_mmx_thresholds() - png_get_asm_flags() - png_get_mmx_bitdepth_threshold() - png_get_mmx_rowbytes_threshold() - png_set_asm_flags() - -We replaced all of these functions with simple stubs in libpng-1.2.20, -when the Intel assembler code was removed due to a licensing issue. - -IX. (Omitted) - -X. Detecting libpng - -The png_get_io_ptr() function has been present since libpng-0.88, has never -changed, and is unaffected by conditional compilation macros. It is the -best choice for use in configure scripts for detecting the presence of any -libpng version since 0.88. In an autoconf "configure.in" you could use - - AC_CHECK_LIB(png, png_get_io_ptr, ... - -XI. Source code repository - -Since about February 2009, version 1.2.34, libpng has been under "git" source -control. The git repository was built from old libpng-x.y.z.tar.gz files -going back to version 0.70. You can access the git repository (read only) -at - - git://libpng.git.sourceforge.net/gitroot/libpng - -or you can browse it via "gitweb" at - - http://libpng.git.sourceforge.net/git/gitweb.cgi?p=libpng - -Patches can be sent to glennrp at users.sourceforge.net or to -png-mng-implement at lists.sourceforge.net or you can upload them to -the libpng bug tracker at - - http://libpng.sourceforge.net - -XII. Coding style - -Our coding style is similar to the "Allman" style, with curly -braces on separate lines: - - if (condition) - { - action; - } - - else if (another condition) - { - another action; - } - -The braces can be omitted from simple one-line actions: - - if (condition) - return (0); - -We use 3-space indentation, except for continued statements which -are usually indented the same as the first line of the statement -plus four more spaces. - -Comments appear with the leading "/*" at the same indentation as -the statement that follows the comment: - - /* Single-line comment */ - statement; - - /* Multiple-line - * comment - */ - statement; - -Very short comments can be placed at the end of the statement -to which they pertain: - - statement; /* comment */ - -We don't use C++ style ("//") comments. We have, however, -used them in the past in some now-abandoned MMX assembler -code. - -Functions and their curly braces are not indented, and -exported functions are marked with PNGAPI: - - /* This is a public function that is visible to - * application programers. It does thus-and-so. - */ - void PNGAPI - png_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for all exported functions appear in png.h, -above the comment that says - - /* Maintainer: Put new public prototypes here ... */ - -We mark all non-exported functions with "/* PRIVATE */"": - - void /* PRIVATE */ - png_non_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for non-exported functions (except for those in -pngtest) appear in -the PNG_INTERNAL section of png.h -above the comment that says - - /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -The names of all exported functions and variables begin -with "png_", and all publicly visible C preprocessor -macros begin with "PNG_". - -We put a space after each comma and after each semicolon -in "for" statments, and we put spaces before and after each -C binary operator and after "for" or "while". We don't -put a space between a typecast and the expression being -cast, nor do we put one between a function name and the -left parenthesis that follows it: - - for (i = 2; i > 0; --i) - x[i] = a(x) + (int)b; - -We prefer #ifdef and #ifndef to #if defined() and if !defined() -when there is only one macro being tested. - -Other rules can be inferred by inspecting the libpng -source. - -XIII. Y2K Compliance in libpng - -September 10, 2009 - -Since the PNG Development group is an ad-hoc body, we can't make -an official declaration. - -This is your unofficial assurance that libpng from version 0.71 and -upward through 1.2.40 are Y2K compliant. It is my belief that earlier -versions were also Y2K compliant. - -Libpng only has three year fields. One is a 2-byte unsigned integer that -will hold years up to 65535. The other two hold the date in text -format, and will hold years up to 9999. - -The integer is - "png_uint_16 year" in png_time_struct. - -The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. - -There are seven time-related functions: - - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) - png_convert_from_struct_tm() in pngwrite.c, called - in pngwrite.c - png_convert_from_time_t() in pngwrite.c - png_get_tIME() in pngget.c - png_handle_tIME() in pngrutil.c, called in pngread.c - png_set_tIME() in pngset.c - png_write_tIME() in pngwutil.c, called in pngwrite.c - -All appear to handle dates properly in a Y2K environment. The -png_convert_from_time_t() function calls gmtime() to convert from system -clock time, which returns (year - 1900), which we properly convert to -the full 4-digit year. There is a possibility that applications using -libpng are not passing 4-digit years into the png_convert_to_rfc_1123() -function, or that they are incorrectly passing only a 2-digit year -instead of "year - 1900" into the png_convert_from_struct_tm() function, -but this is not under our control. The libpng documentation has always -stated that it works with 4-digit years, and the APIs have been -documented as such. - -The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned -integer to hold the year, and can hold years as large as 65535. - -zlib, upon which libpng depends, is also Y2K compliant. It contains -no date-related code. - - - Glenn Randers-Pehrson - libpng maintainer - PNG Development Group diff --git a/src/3rdparty/libpng/libpng.3 b/src/3rdparty/libpng/libpng.3 deleted file mode 100644 index 65b3686..0000000 --- a/src/3rdparty/libpng/libpng.3 +++ /dev/null @@ -1,4349 +0,0 @@ -.TH LIBPNG 3 "September 10, 2009" -.SH NAME -libpng \- Portable Network Graphics (PNG) Reference Library 1.2.40 -.SH SYNOPSIS -\fI\fB - -\fB#include \fP - -\fI\fB - -\fBpng_uint_32 png_access_version_number \fI(void\fP\fB);\fP - -\fI\fB - -\fBint png_check_sig (png_bytep \fP\fIsig\fP\fB, int \fInum\fP\fB);\fP - -\fI\fB - -\fBvoid png_chunk_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP - -\fI\fB - -\fBvoid png_chunk_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP - -\fI\fB - -\fBvoid png_convert_from_struct_tm (png_timep \fP\fIptime\fP\fB, struct tm FAR * \fIttime\fP\fB);\fP - -\fI\fB - -\fBvoid png_convert_from_time_t (png_timep \fP\fIptime\fP\fB, time_t \fIttime\fP\fB);\fP - -\fI\fB - -\fBpng_charp png_convert_to_rfc1123 (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fIptime\fP\fB);\fP - -\fI\fB - -\fBpng_infop png_create_info_struct (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_structp png_create_read_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP - -\fI\fB - -\fBpng_structp png_create_read_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP - -\fI\fB - -\fBpng_structp png_create_write_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP - -\fI\fB - -\fBpng_structp png_create_write_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP - -\fI\fB - -\fBint png_debug(int \fP\fIlevel\fP\fB, png_const_charp \fImessage\fP\fB);\fP - -\fI\fB - -\fBint png_debug1(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fIp1\fP\fB);\fP - -\fI\fB - -\fBint png_debug2(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fP\fIp1\fP\fB, \fIp2\fP\fB);\fP - -\fI\fB - -\fBvoid png_destroy_info_struct (png_structp \fP\fIpng_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_destroy_read_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fP\fIinfo_ptr_ptr\fP\fB, png_infopp \fIend_info_ptr_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_destroy_write_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP - -\fI\fB - -\fBvoid png_free (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_free_chunk_list (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_free_default(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_free_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fInum\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_bit_depth (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fI*background\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_channels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*white_x\fP\fB, double \fP\fI*white_y\fP\fB, double \fP\fI*red_x\fP\fB, double \fP\fI*red_y\fP\fB, double \fP\fI*green_x\fP\fB, double \fP\fI*green_y\fP\fB, double \fP\fI*blue_x\fP\fB, double \fI*blue_y\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*white_x\fP\fB, png_uint_32 \fP\fI*white_y\fP\fB, png_uint_32 \fP\fI*red_x\fP\fB, png_uint_32 \fP\fI*red_y\fP\fB, png_uint_32 \fP\fI*green_x\fP\fB, png_uint_32 \fP\fI*green_y\fP\fB, png_uint_32 \fP\fI*blue_x\fP\fB, png_uint_32 \fI*blue_y\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_color_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_compression_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_copyright (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_get_error_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_filter_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fI*file_gamma\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fI*int_file_gamma\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_header_ver (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_header_version (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fI*hist\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charpp \fP\fIname\fP\fB, int \fP\fI*compression_type\fP\fB, png_charpp \fP\fIprofile\fP\fB, png_uint_32 \fI*proflen\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*width\fP\fB, png_uint_32 \fP\fI*height\fP\fB, int \fP\fI*bit_depth\fP\fB, int \fP\fI*color_type\fP\fB, int \fP\fI*interlace_type\fP\fB, int \fP\fI*compression_type\fP\fB, int \fI*filter_type\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_image_height (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_image_width (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fB#if \fI!defined(PNG_1_0_X) - -\fBpng_int_32 png_get_int_32 (png_bytep \fIbuf\fP\fB);\fP - -\fI\fB#endif - -\fI\fB - -\fBpng_byte png_get_interlace_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_get_io_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_libpng_ver (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_get_mem_ptr(png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*offset_x\fP\fB, png_uint_32 \fP\fI*offset_y\fP\fB, int \fI*unit_type\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fI*purpose\fP\fB, png_int_32 \fP\fI*X0\fP\fB, png_int_32 \fP\fI*X1\fP\fB, int \fP\fI*type\fP\fB, int \fP\fI*nparams\fP\fB, png_charp \fP\fI*units\fP\fB, png_charpp \fI*params\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP - -\fI\fB - -\fBfloat png_get_pixel_aspect_ratio (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_get_progressive_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fI*palette\fP\fB, int \fI*num_palette\fP\fB);\fP - -\fI\fB - -\fBpng_byte png_get_rgb_to_gray_status (png_structp \fIpng_ptr) - -\fBpng_uint_32 png_get_rowbytes (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_bytepp png_get_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fI*sig_bit\fP\fB);\fP - -\fI\fB - -\fBpng_bytep png_get_signature (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fI*splt_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fI*intent\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fI*text_ptr\fP\fB, int \fI*num_text\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fI*mod_time\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fI*trans\fP\fB, int \fP\fI*num_trans\fP\fB, png_color_16p \fI*trans_values\fP\fB);\fP - -\fI\fB - -\fB#if \fI!defined(PNG_1_0_X) - -\fBpng_uint_16 png_get_uint_16 (png_bytep \fIbuf\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_uint_31 (png_bytep \fIbuf\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_uint_32 (png_bytep \fIbuf\fP\fB);\fP - -\fI\fB#endif - -\fI\fB - -\fBpng_uint_32 png_get_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkpp \fIunknowns\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_get_user_chunk_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_user_height_max( png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_get_user_transform_ptr (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_user_width_max (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_valid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIflag\fP\fB);\fP - -\fI\fB - -\fBpng_int_32 png_get_x_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_int_32 png_get_x_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_x_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_int_32 png_get_y_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_int_32 png_get_y_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_y_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_get_compression_buffer_size (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBint png_handle_as_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP - -\fI\fB - -\fBvoid png_init_io (png_structp \fP\fIpng_ptr\fP\fB, FILE \fI*fp\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_info_init (png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_info_init_2 (png_infopp \fP\fIptr_ptr\fP\fB, png_size_t \fIpng_info_struct_size\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_malloc (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_malloc_default(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fI\fB - -\fBvoidp png_memcpy (png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_size_t \fIsize\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_memcpy_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fI\fB - -\fBvoidp png_memset (png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_size_t \fIsize\fP\fB);\fP - -\fI\fB - -\fBpng_voidp png_memset_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_permit_empty_plte (png_structp \fP\fIpng_ptr\fP\fB, int \fIempty_plte_permitted\fP\fB);\fP - -\fI\fB - -\fBvoid png_process_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_size\fP\fB);\fP - -\fI\fB - -\fBvoid png_progressive_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIold_row\fP\fB, png_bytep \fInew_row\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_infop \fIend_info_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_read_init (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_read_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fIdisplay_row\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_bytepp \fP\fIdisplay_row\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP - -\fI\fB - -\fBvoid png_read_update_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fB#if \fI!defined(PNG_1_0_X) - -\fBpng_save_int_32 (png_bytep \fP\fIbuf\fP\fB, png_int_32 \fIi\fP\fB);\fP - -\fI\fB - -\fBvoid png_save_uint_16 (png_bytep \fP\fIbuf\fP\fB, unsigned int \fIi\fP\fB);\fP - -\fI\fB - -\fBvoid png_save_uint_32 (png_bytep \fP\fIbuf\fP\fB, png_uint_32 \fIi\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_add_alpha (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP - -\fI\fB#endif - -\fI\fB - -\fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_bgr (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fIbackground\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_compression_method (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_crc_action (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcrit_action\fP\fB, int \fIancil_action\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_dither (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fP\fInum_palette\fP\fB, int \fP\fImaximum_colors\fP\fB, png_uint_16p \fP\fIhistogram\fP\fB, int \fIfull_dither\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_error_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarning_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_expand (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_expand_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_filler (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_filter (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImethod\fP\fB, int \fIfilters\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_filter_heuristics (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_doublep \fP\fIfilter_weights\fP\fB, png_doublep \fIfilter_costs\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_flush (png_structp \fP\fIpng_ptr\fP\fB, int \fInrows\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_gamma (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIscreen_gamma\fP\fB, double \fIdefault_file_gamma\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIfile_gamma\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_gray_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fIhist\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, png_uint_32 \fIproflen\fP\fB);\fP - -\fI\fB - -\fBint png_set_interlace_handling (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_invalid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fImask\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_invert_alpha (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_invert_mono (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_keep_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIkeep\fP\fB, png_bytep \fP\fIchunk_list\fP\fB, int \fInum_chunks\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_mem_fn(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIoffset_x\fP\fB, png_uint_32 \fP\fIoffset_y\fP\fB, int \fIunit_type\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_packing (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_packswap (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_palette_to_rgb(png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIres_x\fP\fB, png_uint_32 \fP\fIres_y\fP\fB, int \fIunit_type\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_progressive_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIprogressive_ptr\fP\fB, png_progressive_info_ptr \fP\fIinfo_fn\fP\fB, png_progressive_row_ptr \fP\fIrow_fn\fP\fB, png_progressive_end_ptr \fIend_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fIread_data_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_read_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_read_status_ptr \fIread_row_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_read_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIread_user_transform_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_rgb_to_gray (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIerror_action\fP\fB, double \fP\fIred\fP\fB, double \fIgreen\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_rgb_to_gray_fixed (png_structp \fP\fIpng_ptr\fP\fB, int error_action png_fixed_point \fP\fIred\fP\fB, png_fixed_point \fIgreen\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytepp \fIrow_pointers\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fIsig_bit\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_sig_bytes (png_structp \fP\fIpng_ptr\fP\fB, int \fInum_bytes\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fP\fIsplt_ptr\fP\fB, int \fInum_spalettes\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_sRGB_gAMA_and_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_strip_16 (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_strip_alpha (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_swap (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_swap_alpha (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fP\fInum_trans\fP\fB, png_color_16p \fItrans_values\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_tRNS_to_alpha(png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBpng_uint_32 png_set_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkp \fP\fIunknowns\fP\fB, int \fP\fInum\fP\fB, int \fIlocation\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_unknown_chunk_location(png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIchunk\fP\fB, int \fIlocation\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_read_user_chunk_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_chunk_ptr\fP\fB, png_user_chunk_ptr \fIread_user_chunk_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_user_limits (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIuser_width_max\fP\fB, png_uint_32 \fIuser_height_max\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_user_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_transform_ptr\fP\fB, int \fP\fIuser_transform_depth\fP\fB, int \fIuser_transform_channels\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_write_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fP\fIwrite_data_fn\fP\fB, png_flush_ptr \fIoutput_flush_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_write_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_write_status_ptr \fIwrite_row_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_write_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIwrite_user_transform_fn\fP\fB);\fP - -\fI\fB - -\fBvoid png_set_compression_buffer_size(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP - -\fI\fB - -\fBint png_sig_cmp (png_bytep \fP\fIsig\fP\fB, png_size_t \fP\fIstart\fP\fB, png_size_t \fInum_to_check\fP\fB);\fP - -\fI\fB - -\fBvoid png_start_read_image (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_chunk_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_chunk_end (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_chunk_start (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_destroy (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_flush (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_write_init (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fBDEPRECATED: void png_write_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_info_before_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fBvoid png_write_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP - -\fI\fB - -\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP - -\fI\fB - -\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP - -\fI\fB - -.SH DESCRIPTION -The -.I libpng -library supports encoding, decoding, and various manipulations of -the Portable Network Graphics (PNG) format image files. It uses the -.IR zlib(3) -compression library. -Following is a copy of the libpng.txt file that accompanies libpng. -.SH LIBPNG.TXT -libpng.txt - A description on how to use and modify libpng - - libpng version 1.2.40 - September 10, 2009 - Updated and distributed by Glenn Randers-Pehrson - - Copyright (c) 1998-2009 Glenn Randers-Pehrson - - This document is released under the libpng license. - For conditions of distribution and use, see the disclaimer - and license in png.h - - Based on: - - libpng versions 0.97, January 1998, through 1.2.40 - September 10, 2009 - Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2009 Glenn Randers-Pehrson - - libpng 1.0 beta 6 version 0.96 May 28, 1997 - Updated and distributed by Andreas Dilger - Copyright (c) 1996, 1997 Andreas Dilger - - libpng 1.0 beta 2 - version 0.88 January 26, 1996 - For conditions of distribution and use, see copyright - notice in png.h. Copyright (c) 1995, 1996 Guy Eric - Schalnat, Group 42, Inc. - - Updated/rewritten per request in the libpng FAQ - Copyright (c) 1995, 1996 Frank J. T. Wojcik - December 18, 1995 & January 20, 1996 - -.SH I. Introduction - -This file describes how to use and modify the PNG reference library -(known as libpng) for your own use. There are five sections to this -file: introduction, structures, reading, writing, and modification and -configuration notes for various special platforms. In addition to this -file, example.c is a good starting point for using the library, as -it is heavily commented and should include everything most people -will need. We assume that libpng is already installed; see the -INSTALL file for instructions on how to install libpng. - -For examples of libpng usage, see the files "example.c", "pngtest.c", -and the files in the "contrib" directory, all of which are included in the -libpng distribution. - -Libpng was written as a companion to the PNG specification, as a way -of reducing the amount of time and effort it takes to support the PNG -file format in application programs. - -The PNG specification (second edition), November 2003, is available as -a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at -. It is technically equivalent -to the PNG specification (second edition) but has some additional material. - -The PNG-1.0 specification is available -as RFC 2083 and as a -W3C Recommendation . - -Some additional chunks are described in the special-purpose public chunks -documents at . - -Other information -about PNG, and the latest version of libpng, can be found at the PNG home -page, . - -Most users will not have to modify the library significantly; advanced -users may want to modify it more. All attempts were made to make it as -complete as possible, while keeping the code easy to understand. -Currently, this library only supports C. Support for other languages -is being considered. - -Libpng has been designed to handle multiple sessions at one time, -to be easily modifiable, to be portable to the vast majority of -machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy -to use. The ultimate goal of libpng is to promote the acceptance of -the PNG file format in whatever way possible. While there is still -work to be done (see the TODO file), libpng should cover the -majority of the needs of its users. - -Libpng uses zlib for its compression and decompression of PNG files. -Further information about zlib, and the latest version of zlib, can -be found at the zlib home page, . -The zlib compression utility is a general purpose utility that is -useful for more than PNG files, and can be used without libpng. -See the documentation delivered with zlib for more details. -You can usually find the source files for the zlib utility wherever you -find the libpng source files. - -Libpng is thread safe, provided the threads are using different -instances of the structures. Each thread should have its own -png_struct and png_info instances, and thus its own image. -Libpng does not protect itself against two threads using the -same instance of a structure. - -.SH II. Structures - -There are two main structures that are important to libpng, png_struct -and png_info. The first, png_struct, is an internal structure that -will not, for the most part, be used by a user except as the first -variable passed to every libpng function call. - -The png_info structure is designed to provide information about the -PNG file. At one time, the fields of png_info were intended to be -directly accessible to the user. However, this tended to cause problems -with applications using dynamically loaded libraries, and as a result -a set of interface functions for png_info (the png_get_*() and png_set_*() -functions) was developed. The fields of png_info are still available for -older applications, but it is suggested that applications use the new -interfaces if at all possible. - -Applications that do make direct access to the members of png_struct (except -for png_ptr->jmpbuf) must be recompiled whenever the library is updated, -and applications that make direct access to the members of png_info must -be recompiled if they were compiled or loaded with libpng version 1.0.6, -in which the members were in a different order. In version 1.0.7, the -members of the png_info structure reverted to the old order, as they were -in versions 0.97c through 1.0.5. Starting with version 2.0.0, both -structures are going to be hidden, and the contents of the structures will -only be accessible through the png_get/png_set functions. - -The png.h header file is an invaluable reference for programming with libpng. -And while I'm on the topic, make sure you include the libpng header file: - -#include - -.SH III. Reading - -We'll now walk you through the possible functions to call when reading -in a PNG file sequentially, briefly explaining the syntax and purpose -of each one. See example.c and png.h for more detail. While -progressive reading is covered in the next section, you will still -need some of the functions discussed in this section to read a PNG -file. - -.SS Setup - -You will want to do the I/O initialization(*) before you get into libpng, -so if it doesn't work, you don't have much to undo. Of course, you -will also want to insure that you are, in fact, dealing with a PNG -file. Libpng provides a simple check to see if a file is a PNG file. -To use it, pass in the first 1 to 8 bytes of the file to the function -png_sig_cmp(), and it will return 0 (false) if the bytes match the -corresponding bytes of the PNG signature, or nonzero (true) otherwise. -Of course, the more bytes you pass in, the greater the accuracy of the -prediction. - -If you are intending to keep the file pointer open for use in libpng, -you must ensure you don't read more than 8 bytes from the beginning -of the file, and you also have to make a call to png_set_sig_bytes_read() -with the number of bytes you read from the beginning. Libpng will -then only check the bytes (if any) that your program didn't read. - -(*): If you are not using the standard I/O functions, you will need -to replace them with custom functions. See the discussion under -Customizing libpng. - - - FILE *fp = fopen(file_name, "rb"); - if (!fp) - { - return (ERROR); - } - fread(header, 1, number, fp); - is_png = !png_sig_cmp(header, 0, number); - if (!is_png) - { - return (NOT_PNG); - } - - -Next, png_struct and png_info need to be allocated and initialized. In -order to ensure that the size of these structures is correct even with a -dynamically linked libpng, there are functions to initialize and -allocate the structures. We also pass the library version, optional -pointers to error handling functions, and a pointer to a data struct for -use by the error functions, if necessary (the pointer and functions can -be NULL if the default error handlers are to be used). See the section -on Changes to Libpng below regarding the old initialization functions. -The structure allocation functions quietly return NULL if they fail to -create the structure, so your application should check for that. - - png_structp png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, - (png_infopp)NULL, (png_infopp)NULL); - return (ERROR); - } - - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_read_struct_2() instead of png_create_read_struct(): - - png_structp png_ptr = png_create_read_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -The error handling routines passed to png_create_read_struct() -and the memory alloc/free routines passed to png_create_struct_2() -are only necessary if you are not using the libpng supplied error -handling and memory alloc/free functions. - -When libpng encounters an error, it expects to longjmp back -to your routine. Therefore, you will need to call setjmp and pass -your png_jmpbuf(png_ptr). If you read the file from different -routines, you will need to update the jmpbuf field every time you enter -a new routine that will call a png_*() function. - -See your documentation of setjmp/longjmp for your compiler for more -information on setjmp/longjmp. See the discussion on libpng error -handling in the Customizing Libpng section below for more information -on the libpng error handling. If an error occurs, and libpng longjmp's -back to your setjmp, you will want to call png_destroy_read_struct() to -free any memory. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - fclose(fp); - return (ERROR); - } - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the input code. The default for libpng is to -use the C function fread(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. If you wish to handle reading data in another -way, you need not call the png_init_io() function, but you must then -implement the libpng I/O methods discussed in the Customizing Libpng -section below. - - png_init_io(png_ptr, fp); - -If you had previously opened the file and read any of the signature from -the beginning in order to see if this was a PNG file, you need to let -libpng know that there are some bytes missing from the start of the file. - - png_set_sig_bytes(png_ptr, number); - -.SS Setting up callback code - -You can set up a callback function to handle any unknown chunks in the -input stream. You must supply the function - - read_chunk_callback(png_ptr ptr, - png_unknown_chunkp chunk); - { - /* The unknown chunk structure contains your - chunk data, along with similar data for any other - unknown chunks: */ - - png_byte name[5]; - png_byte *data; - png_size_t size; - - /* Note that libpng has already taken care of - the CRC handling */ - - /* put your code here. Search for your chunk in the - unknown chunk structure, process it, and return one - of the following: */ - - return (-n); /* chunk had an error */ - return (0); /* did not recognize */ - return (n); /* success */ - } - -(You can give your function another name that you like instead of -"read_chunk_callback") - -To inform libpng about your function, use - - png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, - read_chunk_callback); - -This names not only the callback function, but also a user pointer that -you can retrieve with - - png_get_user_chunk_ptr(png_ptr); - -If you call the png_set_read_user_chunk_fn() function, then all unknown -chunks will be saved when read, in case your callback function will need -one or more of them. This behavior can be changed with the -png_set_keep_unknown_chunks() function, described below. - -At this point, you can set up a callback function that will be -called after each row has been read, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void read_row_callback(png_ptr ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "read_row_callback") - -To inform libpng about your function, use - - png_set_read_status_fn(png_ptr, read_row_callback); - -.SS Unknown-chunk handling - -Now you get to set the way the library processes unknown chunks in the -input PNG stream. Both known and unknown chunks will be read. Normal -behavior is that known chunks will be parsed into information in -various info_ptr members while unknown chunks will be discarded. This -behavior can be wasteful if your application will never use some known -chunk types. To change this, you can call: - - png_set_keep_unknown_chunks(png_ptr, keep, - chunk_list, num_chunks); - keep - 0: default unknown chunk handling - 1: ignore; do not keep - 2: keep only if safe-to-copy - 3: keep even if unsafe-to-copy - You can use these definitions: - PNG_HANDLE_CHUNK_AS_DEFAULT 0 - PNG_HANDLE_CHUNK_NEVER 1 - PNG_HANDLE_CHUNK_IF_SAFE 2 - PNG_HANDLE_CHUNK_ALWAYS 3 - chunk_list - list of chunks affected (a byte string, - five bytes per chunk, NULL or '\0' if - num_chunks is 0) - num_chunks - number of chunks affected; if 0, all - unknown chunks are affected. If nonzero, - only the chunks in the list are affected - -Unknown chunks declared in this way will be saved as raw data onto a -list of png_unknown_chunk structures. If a chunk that is normally -known to libpng is named in the list, it will be handled as unknown, -according to the "keep" directive. If a chunk is named in successive -instances of png_set_keep_unknown_chunks(), the final instance will -take precedence. The IHDR and IEND chunks should not be named in -chunk_list; if they are, libpng will process them normally anyway. - -Here is an example of the usage of png_set_keep_unknown_chunks(), -where the private "vpAg" chunk will later be processed by a user chunk -callback function: - - png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - png_byte unused_chunks[]= - { - 104, 73, 83, 84, (png_byte) '\0', /* hIST */ - 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ - 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ - 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ - 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ - 116, 73, 77, 69, (png_byte) '\0', /* tIME */ - }; - #endif - - ... - - #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - /* ignore all unknown chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, NULL, 0); - /* except for vpAg: */ - png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); - /* also ignore unused known chunks: */ - png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - #endif - -.SS User limits - -The PNG specification allows the width and height of an image to be as -large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. -Since very few applications really need to process such large images, -we have imposed an arbitrary 1-million limit on rows and columns. -Larger images will be rejected immediately with a png_error() call. If -you wish to override this limit, you can use - - png_set_user_limits(png_ptr, width_max, height_max); - -to set your own limits, or use width_max = height_max = 0x7fffffffL -to allow all valid dimensions (libpng may reject some very large images -anyway because of potential buffer overflow conditions). - -You should put this statement after you create the PNG structure and -before calling png_read_info(), png_read_png(), or png_process_data(). -If you need to retrieve the limits that are being applied, use - - width_max = png_get_user_width_max(png_ptr); - height_max = png_get_user_height_max(png_ptr); - -.SS The high-level read interface - -At this point there are two ways to proceed; through the high-level -read interface, or through a sequence of low-level read operations. -You can use the high-level interface if (a) you are willing to read -the entire image into memory, and (b) the input transformations -you want to do are limited to the following set: - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to - 8 bits - PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel - PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit - samples to bytes - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_EXPAND Perform set_expand() - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - -(This excludes setting a background color, doing gamma transformation, -dithering, and setting filler.) If this is the case, simply do this: - - png_read_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of -some set of transformation flags. This call is equivalent to png_read_info(), -followed the set of transformations indicated by the transform mask, -then png_read_image(), and finally png_read_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future input transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_read_png(). - -After you have called png_read_png(), you can retrieve the image data -with - - row_pointers = png_get_rows(png_ptr, info_ptr); - -where row_pointers is an array of pointers to the pixel data for each row: - - png_bytep row_pointers[height]; - -If you know your image size and pixel size ahead of time, you can allocate -row_pointers prior to calling png_read_png() with - - if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) - png_error (png_ptr, - "Image is too tall to process in memory"); - if (width > PNG_UINT_32_MAX/pixel_size) - png_error (png_ptr, - "Image is too wide to process in memory"); - row_pointers = png_malloc(png_ptr, - height*png_sizeof(png_bytep)); - for (int i=0; i) and -png_get_(png_ptr, info_ptr, ...) functions return non-zero if the -data has been read, or zero if it is missing. The parameters to the -png_get_ are set directly if they are simple data types, or a pointer -into the info_ptr is returned for any complex types. - - png_get_PLTE(png_ptr, info_ptr, &palette, - &num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_get_gAMA(png_ptr, info_ptr, &gamma); - gamma - the gamma the file is written - at (PNG_INFO_gAMA) - - png_get_sRGB(png_ptr, info_ptr, &srgb_intent); - srgb_intent - the rendering intent (PNG_INFO_sRGB) - The presence of the sRGB chunk - means that the pixel data is in the - sRGB color space. This chunk also - implies specific values of gAMA and - cHRM. - - png_get_iCCP(png_ptr, info_ptr, &name, - &compression_type, &profile, &proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, - red, green, and blue channels, - whichever are appropriate for the - given color type (png_color_16) - - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, - &trans_values); - trans - array of transparent entries for - palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values of - the single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_get_hIST(png_ptr, info_ptr, &hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_get_tIME(png_ptr, info_ptr, &mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_get_bKGD(png_ptr, info_ptr, &background); - background - background color (PNG_VALID_bKGD) - valid 16-bit red, green and blue - values, regardless of color_type - - num_comments = png_get_text(png_ptr, info_ptr, - &text_ptr, &num_text); - num_comments - number of comments - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (empty - string for unknown). - text_ptr[i].lang_key - keyword in UTF-8 - (empty string for unknown). - num_text - number of comments (same as - num_comments; you can put NULL here - to avoid the duplication) - Note while png_set_text() will accept text, language, - and translated keywords that can be NULL pointers, the - structure returned by png_get_text will always contain - regular zero-terminated C strings. They might be - empty strings but they will never be NULL pointers. - - num_spalettes = png_get_sPLT(png_ptr, info_ptr, - &palette_ptr); - palette_ptr - array of palette structures holding - contents of one or more sPLT chunks - read. - num_spalettes - number of sPLT chunks read. - - png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, - &unit_type); - offset_x - positive offset from the left edge - of the screen - offset_y - positive offset from the top edge - of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, - &unit_type); - res_x - pixels/unit physical resolution in - x direction - res_y - pixels/unit physical resolution in - x direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_get_sCAL(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, - &height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - num_unknown_chunks = png_get_unknown_chunks(png_ptr, - info_ptr, &unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position of chunk in file - - The value of "i" corresponds to the order in which the - chunks were read from the PNG file or inserted with the - png_set_unknown_chunks() function. - -The data from the pHYs chunk can be retrieved in several convenient -forms: - - res_x = png_get_x_pixels_per_meter(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_meter(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_meter(png_ptr, - info_ptr) - res_x = png_get_x_pixels_per_inch(png_ptr, - info_ptr) - res_y = png_get_y_pixels_per_inch(png_ptr, - info_ptr) - res_x_and_y = png_get_pixels_per_inch(png_ptr, - info_ptr) - aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, - info_ptr) - - (Each of these returns 0 [signifying "unknown"] if - the data is not present or if res_x is 0; - res_x_and_y is 0 if res_x != res_y) - -The data from the oFFs chunk can be retrieved in several convenient -forms: - - x_offset = png_get_x_offset_microns(png_ptr, info_ptr); - y_offset = png_get_y_offset_microns(png_ptr, info_ptr); - x_offset = png_get_x_offset_inches(png_ptr, info_ptr); - y_offset = png_get_y_offset_inches(png_ptr, info_ptr); - - (Each of these returns 0 [signifying "unknown" if both - x and y are 0] if the data is not present or if the - chunk is present but the unit is the pixel) - -For more information, see the png_info definition in png.h and the -PNG specification for chunk contents. Be careful with trusting -rowbytes, as some of the transformations could increase the space -needed to hold a row (expand, filler, gray_to_rgb, etc.). -See png_read_update_info(), below. - -A quick word about text_ptr and num_text. PNG stores comments in -keyword/text pairs, one pair per chunk, with no limit on the number -of text chunks, and a 2^31 byte limit on their size. While there are -suggested keywords, there is no requirement to restrict the use to these -strings. It is strongly suggested that keywords and text be sensible -to humans (that's the point), so don't use abbreviations. Non-printing -symbols are not allowed. See the PNG specification for more details. -There is also no requirement to have text after the keyword. - -Keywords should be limited to 79 Latin-1 characters without leading or -trailing spaces, but non-consecutive spaces are allowed within the -keyword. It is possible to have the same keyword any number of times. -The text_ptr is an array of png_text structures, each holding a -pointer to a language string, a pointer to a keyword and a pointer to -a text string. The text string, language code, and translated -keyword may be empty or NULL pointers. The keyword/text -pairs are put into the array in the order that they are received. -However, some or all of the text chunks may be after the image, so, to -make sure you have read all the text chunks, don't mess with these -until after you read the stuff after the image. This will be -mentioned again below in the discussion that goes with png_read_end(). - -.SS Input transformations - -After you've read the header information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -The colors used for the background and transparency values should be -supplied in the same format/depth as the current image data. They -are stored in the same format/depth as the image data in a bKGD or tRNS -chunk, so this is what libpng expects for this data. The colors are -transformed to keep in sync with the image data when an application -calls the png_read_update_info() routine (see below). - -Data will be decoded into the supplied row buffers packed into bytes -unless the library has been told to transform it into another format. -For example, 4 bit/pixel paletted or grayscale data will be returned -2 pixels/byte with the leftmost pixel in the high-order bits of the -byte, unless png_set_packing() is called. 8-bit RGB data will be stored -in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() -is called to insert filler bytes, either before or after each RGB triplet. -16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant -byte of the color value first, unless png_set_strip_16() is called to -transform it to regular RGB RGB triplets, or png_set_filler() or -png_set_add alpha() is called to insert filler bytes, either before or -after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can -be modified with -png_set_filler(), png_set_add_alpha(), or png_set_strip_16(). - -The following code transforms grayscale images of less than 8 to 8 bits, -changes paletted images to RGB, and adds a full alpha channel if there is -transparency information in a tRNS chunk. This is most useful on -grayscale images with bit depths of 2 or 4 or if there is a multiple-image -viewing application that wishes to treat all images in the same way. - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && - bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); - - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); - -These three functions are actually aliases for png_set_expand(), added -in libpng version 1.0.4, with the function names expanded to improve code -readability. In some future version they may actually do different -things. - -As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was -added. It expands the sample depth without changing tRNS to alpha. - -PNG can have files with 16 bits per channel. If you only can handle -8 bits per channel, this will strip the pixels down to 8 bit. - - if (bit_depth == 16) - png_set_strip_16(png_ptr); - -If, for some reason, you don't need the alpha channel on an image, -and you want to remove it rather than combining it with the background -(but the image author certainly had in mind that you *would* combine -it with the background, so that's what you should probably do): - - if (color_type & PNG_COLOR_MASK_ALPHA) - png_set_strip_alpha(png_ptr); - -In PNG files, the alpha channel in an image -is the level of opacity. If you need the alpha channel in an image to -be the level of transparency instead of opacity, you can invert the -alpha channel (or the tRNS chunk data) after it's read, so that 0 is -fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit -images) is fully transparent, with - - png_set_invert_alpha(png_ptr); - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit -files. This code expands to 1 pixel per byte without changing the -values of the pixels: - - if (bit_depth < 8) - png_set_packing(png_ptr); - -PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels -stored in a PNG image have been "scaled" or "shifted" up to the next -higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to -8 bits/sample in the range [0, 255]). However, it is also possible to -convert the PNG pixel data back to the original bit depth of the image. -This call reduces the pixels back down to the original bit depth: - - png_color_8p sig_bit; - - if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) - png_set_shift(png_ptr, sig_bit); - -PNG files store 3-color pixels in red, green, blue order. This code -changes the storage of the pixels to blue, green, red: - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_bgr(png_ptr); - -PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them -into 4 or 8 bytes for windowing systems that need them in this format: - - if (color_type == PNG_COLOR_TYPE_RGB) - png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); - -where "filler" is the 8 or 16-bit number to fill with, and the location is -either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether -you want the filler before the RGB or after. This transformation -does not affect images that already have full alpha channels. To add an -opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which -will generate RGBA pixels. - -Note that png_set_filler() does not change the color type. If you want -to do that, you can add a true alpha channel with - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY) - png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); - -where "filler" contains the alpha value to assign to each pixel. -This function was added in libpng-1.2.7. - -If you are reading an image with an alpha channel, and you need the -data as ARGB instead of the normal PNG format RGBA: - - if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_swap_alpha(png_ptr); - -For some uses, you may want a grayscale image to be represented as -RGB. This code will do that conversion: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - -Conversely, you can convert an RGB or RGBA image to grayscale or grayscale -with alpha. - - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray_fixed(png_ptr, error_action, - int red_weight, int green_weight); - - error_action = 1: silently do the conversion - error_action = 2: issue a warning if the original - image has any pixel where - red != green or red != blue - error_action = 3: issue an error and abort the - conversion if the original - image has any pixel where - red != green or red != blue - - red_weight: weight of red component times 100000 - green_weight: weight of green component times 100000 - If either weight is negative, default - weights (21268, 71514) are used. - -If you have set error_action = 1 or 2, you can -later check whether the image really was gray, after processing -the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. -It will return a png_byte that is zero if the image was gray or -1 if there were any non-gray pixels. bKGD and sBIT data -will be silently converted to grayscale, using the green channel -data, regardless of the error_action setting. - -With red_weight+green_weight<=100000, -the normalized graylevel is computed: - - int rw = red_weight * 65536; - int gw = green_weight * 65536; - int bw = 65536 - (rw + gw); - gray = (rw*red + gw*green + bw*blue)/65536; - -The default values approximate those recommended in the Charles -Poynton's Color FAQ, -Copyright (c) 1998-01-04 Charles Poynton - - Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - -Libpng approximates this with - - Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - -which can be expressed with integers as - - Y = (6969 * R + 23434 * G + 2365 * B)/32768 - -The calculation is done in a linear colorspace, if the image gamma -is known. - -If you have a grayscale and you are using png_set_expand_depth(), -png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to -a higher bit-depth, you must either supply the background color as a gray -value at the original file bit-depth (need_expand = 1) or else supply the -background color as an RGB triplet at the final, expanded bit depth -(need_expand = 0). Similarly, if you are reading a paletted image, you -must either supply the background color as a palette index (need_expand = 1) -or as an RGB triplet that may or may not be in the palette (need_expand = 0). - - png_color_16 my_background; - png_color_16p image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - -The png_set_background() function tells libpng to composite images -with alpha or simple transparency against the supplied background -color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), -you may use this color, or supply another color more suitable for -the current display (e.g., the background color from a web page). You -need to tell libpng whether the color is in the gamma space of the -display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file -(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one -that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't -know why anyone would use this, but it's here). - -To properly display PNG images on any kind of system, the application needs -to know what the display gamma is. Ideally, the user will know this, and -the application will allow them to set it. One method of allowing the user -to set the display gamma separately for each system is to check for a -SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be -correctly set. - -Note that display_gamma is the overall gamma correction required to produce -pleasing results, which depends on the lighting conditions in the surrounding -environment. In a dim or brightly lit room, no compensation other than -the physical gamma exponent of the monitor is needed, while in a dark room -a slightly smaller exponent is better. - - double gamma, screen_gamma; - - if (/* We have a user-defined screen - gamma value */) - { - screen_gamma = user_defined_screen_gamma; - } - /* One way that applications can share the same - screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) - != NULL) - { - screen_gamma = (double)atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a - PC monitor in a bright office or a dim room */ - screen_gamma = 2.0; /* A good guess for a - PC monitor in a dark room */ - screen_gamma = 1.7 or 1.0; /* A good - guess for Mac systems */ - } - -The png_set_gamma() function handles gamma transformations of the data. -Pass both the file gamma and the current screen_gamma. If the file does -not have a gamma value, you can pass one anyway if you have an idea what -it is (usually 0.45455 is a good guess for GIF images on PCs). Note -that file gammas are inverted from screen gammas. See the discussions -on gamma in the PNG specification for an excellent description of what -gamma is, and why all applications should support it. It is strongly -recommended that PNG viewers support gamma correction. - - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma(png_ptr, screen_gamma, gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - -If you need to reduce an RGB file to a paletted file, or if a paletted -file has more entries then will fit on your screen, png_set_dither() -will do that. Note that this is a simple match dither that merely -finds the closest color available. This should work fairly well with -optimized palettes, and fairly badly with linear color cubes. If you -pass a palette that is larger then maximum_colors, the file will -reduce the number of colors in the palette so it will fit into -maximum_colors. If there is a histogram, it will use it to make -more intelligent choices when reducing the palette. If there is no -histogram, it may not do as good a job. - - if (color_type & PNG_COLOR_MASK_COLOR) - { - if (png_get_valid(png_ptr, info_ptr, - PNG_INFO_PLTE)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, - &histogram); - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 1); - } - else - { - png_color std_color_cube[MAX_SCREEN_COLORS] = - { ... colors ... }; - - png_set_dither(png_ptr, std_color_cube, - MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, - NULL,0); - } - } - -PNG files describe monochrome as black being zero and white being one. -The following code will reverse this (make black be one and white be -zero): - - if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) - png_set_invert_mono(png_ptr); - -This function can also be used to invert grayscale and gray-alpha images: - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_invert_mono(png_ptr); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code changes the storage to the -other way (little-endian, i.e. least significant bits first, the -way PCs store them): - - if (bit_depth == 16) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_read_user_transform_fn(png_ptr, - read_transform_fn); - -You must supply the function - - void read_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -after all of the other transformations have been processed. - -You can also set up a pointer to a user structure for use by your -callback function, and you can inform libpng that your transform -function will change the number of channels or bit depth with the -function - - png_set_user_transform_info(png_ptr, user_ptr, - user_depth, user_channels); - -The user's application, not libpng, is responsible for allocating and -freeing any memory required for the user structure. - -You can retrieve the pointer via the function -png_get_user_transform_ptr(). For example: - - voidp read_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -The last thing to handle is interlacing; this is covered in detail below, -but you must call the function here if you want libpng to handle expansion -of the interlaced image. - - number_of_passes = png_set_interlace_handling(png_ptr); - -After setting the transformations, libpng can update your png_info -structure to reflect any transformations you've requested with this -call. This is most useful to update the info structure's rowbytes -field so you can use it to allocate your image memory. This function -will also update your palette with the correct screen_gamma and -background if these have been given with the calls above. - - png_read_update_info(png_ptr, info_ptr); - -After you call png_read_update_info(), you can allocate any -memory you need to hold the image. The row data is simply -raw byte data for all forms of images. As the actual allocation -varies among applications, no example will be given. If you -are allocating one large chunk, you will need to build an -array of pointers to each row, as it will be needed for some -of the functions below. - -.SS Reading image data - -After you've allocated memory, you can read the image data. -The simplest way to do this is in one function call. If you are -allocating enough memory to hold the whole image, you can just -call png_read_image() and libpng will read in all the image data -and put it in the memory area supplied. You will need to pass in -an array of pointers to each row. - -This function automatically handles interlacing, so you don't need -to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_read_rows(). - - png_read_image(png_ptr, row_pointers); - -where row_pointers is: - - png_bytep row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to read in the whole image at once, you can -use png_read_rows() instead. If there is no interlacing (check -interlace_type == PNG_INTERLACE_NONE), this is simple: - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -where row_pointers is the same as in the png_read_image() call. - -If you are doing this just one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - png_read_row(png_ptr, row_pointer, NULL); - -If the file is interlaced (interlace_type != 0 in the IHDR chunk), things -get somewhat harder. The only current (PNG Specification version 1.2) -interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) -is a somewhat complicated 2D interlace scheme, known as Adam7, that -breaks down an image into seven smaller images of varying size, based -on an 8x8 grid. - -libpng can fill out those images or it can give them to you "as is". -If you want them filled out, there are two ways to do that. The one -mentioned in the PNG specification is to expand each pixel to cover -those pixels that have not been read yet (the "rectangle" method). -This results in a blocky image for the first pass, which gradually -smooths out as more pixels are read. The other method is the "sparkle" -method, where pixels are drawn only in their final locations, with the -rest of the image remaining whatever colors they were initialized to -before the start of the read. The first method usually looks better, -but tends to be slower, as there are more pixels to put in the rows. - -If you don't want libpng to handle the interlacing details, just call -png_read_rows() seven times to read in all seven images. Each of the -images is a valid image by itself, or they can all be combined on an -8x8 grid to form a single image (although if you intend to combine them -you would be far better off using the libpng interlace handling). - -The first pass will return an image 1/8 as wide as the entire image -(every 8th column starting in column 0) and 1/8 as high as the original -(every 8th row starting in row 0), the second will be 1/8 as wide -(starting in column 4) and 1/8 as high (also starting in row 0). The -third pass will be 1/4 as wide (every 4th pixel starting in column 0) and -1/8 as high (every 8th row starting in row 4), and the fourth pass will -be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, -and every 4th row starting in row 0). The fifth pass will return an -image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), -while the sixth pass will be 1/2 as wide and 1/2 as high as the original -(starting in column 1 and row 0). The seventh and final pass will be as -wide as the original, and 1/2 as high, containing all of the odd -numbered scanlines. Phew! - -If you want libpng to expand the images, call this before calling -png_start_read_image() or png_read_update_info(): - - if (interlace_type == PNG_INTERLACE_ADAM7) - number_of_passes - = png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this -is seven, but may change if another interlace type is added. -This function can be called even if the file is not interlaced, -where it will return one pass. - -If you are not going to display the image after each pass, but are -going to wait until the entire image is read in, use the sparkle -effect. This effect is faster and the end result of either method -is exactly the same. If you are planning on displaying the image -after each pass, the "rectangle" effect is generally considered the -better looking one. - -If you only want the "sparkle" effect, just call png_read_rows() as -normal, with the third parameter NULL. Make sure you make pass over -the image number_of_passes times, and you don't change the data in the -rows between calls. You can change the locations of the data, just -not the data. Each pass only writes the pixels appropriate for that -pass, and assumes the data from previous passes is still valid. - - png_read_rows(png_ptr, row_pointers, NULL, - number_of_rows); - -If you only want the first effect (the rectangles), do the same as -before except pass the row buffer in the third parameter, and leave -the second parameter NULL. - - png_read_rows(png_ptr, NULL, row_pointers, - number_of_rows); - -.SS Finishing a sequential read - -After you are finished reading the image through the -low-level interface, you can finish reading the file. If you are -interested in comments or time, which may be stored either before or -after the image data, you should pass the separate png_info struct if -you want to keep the comments from before and after the image -separate. If you are not interested, you can pass NULL. - - png_read_end(png_ptr, end_info); - -When you are done, you can free all memory allocated by libpng like this: - - png_destroy_read_struct(&png_ptr, &info_ptr, - &end_info); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those -cases do nothing. The "seq" parameter is ignored if only one item -of the selected data type, such as PLTE, is allowed. If "seq" is not --1, and multiple items are allowed for the data type identified in -the mask, such as text or sPLT, only the n'th item in the structure -is freed, where n is "seq". - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -This function only affects data that has already been allocated. -You can call this function after reading the PNG data but before calling -any png_set_*() functions, to control whether the user or the png_set_*() -function is responsible for freeing any existing data that might be present, -and again after the png_set_*() functions to control whether the user -or png_destroy_*() is supposed to free the data. When the user assumes -responsibility for libpng-allocated data, the application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated your row_pointers in a single block, as suggested above in -the description of the high level read interface, you must not transfer -responsibility for freeing it to the png_set_rows or png_read_destroy function, -because they would also try to free the individual row_pointers[i]. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. - -The png_free_data() function will turn off the "valid" flag for anything -it frees. If you need to turn the flag off for a chunk that was freed by your -application instead of by libpng, you can use - - png_set_invalid(png_ptr, info_ptr, mask); - mask - identifies the chunks to be made invalid, - containing the bitwise OR of one or - more of - PNG_INFO_gAMA, PNG_INFO_sBIT, - PNG_INFO_cHRM, PNG_INFO_PLTE, - PNG_INFO_tRNS, PNG_INFO_bKGD, - PNG_INFO_hIST, PNG_INFO_pHYs, - PNG_INFO_oFFs, PNG_INFO_tIME, - PNG_INFO_pCAL, PNG_INFO_sRGB, - PNG_INFO_iCCP, PNG_INFO_sPLT, - PNG_INFO_sCAL, PNG_INFO_IDAT - -For a more compact example of reading a PNG image, see the file example.c. - -.SS Reading PNG files progressively - -The progressive reader is slightly different then the non-progressive -reader. Instead of calling png_read_info(), png_read_rows(), and -png_read_end(), you make one call to png_process_data(), which calls -callbacks when it has the info, a row, or the end of the image. You -set up these callbacks with png_set_progressive_read_fn(). You don't -have to worry about the input/output functions of libpng, as you are -giving the library the data directly in png_process_data(). I will -assume that you have read the section on reading PNG files above, -so I will only highlight the differences (although I will show -all of the code). - -png_structp png_ptr; -png_infop info_ptr; - - /* An example code fragment of how you would - initialize the progressive reader in your - application. */ - int - initialize_png_reader() - { - png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, - (png_infopp)NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new. You can provide functions - to be called when the header info is valid, - when each row is completed, and when the image - is finished. If you aren't using all functions, - you can specify NULL parameters. Even when all - three functions are NULL, you need to call - png_set_progressive_read_fn(). You can use - any struct as the user_ptr (cast to a void pointer - for the function call), and retrieve the pointer - from inside the callbacks using the function - - png_get_progressive_ptr(png_ptr); - - which will return a void pointer, which you have - to cast appropriately. - */ - png_set_progressive_read_fn(png_ptr, (void *)user_ptr, - info_callback, row_callback, end_callback); - - return 0; - } - - /* A code fragment that you call as you receive blocks - of data */ - int - process_data(png_bytep buffer, png_uint_32 length) - { - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_read_struct(&png_ptr, &info_ptr, - (png_infopp)NULL); - return (ERROR); - } - - /* This one's new also. Simply give it a chunk - of data from the file stream (in order, of - course). On machines with segmented memory - models machines, don't give it any more than - 64K. The library seems to run fine with sizes - of 4K. Although you can give it much less if - necessary (I assume you can give it chunks of - 1 byte, I haven't tried less then 256 bytes - yet). When this function returns, you may - want to display any rows that were generated - in the row callback if you don't already do - so there. - */ - png_process_data(png_ptr, info_ptr, buffer, length); - return 0; - } - - /* This function is called (as set by - png_set_progressive_read_fn() above) when enough data - has been supplied so all of the header has been - read. - */ - void - info_callback(png_structp png_ptr, png_infop info) - { - /* Do any setup here, including setting any of - the transformations mentioned in the Reading - PNG files section. For now, you _must_ call - either png_start_read_image() or - png_read_update_info() after all the - transformations are set (even if you don't set - any). You may start getting rows before - png_process_data() returns, so this is your - last chance to prepare for that. - */ - } - - /* This function is called when each row of image - data is complete */ - void - row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) - { - /* If the image is interlaced, and you turned - on the interlace handler, this function will - be called for every row in every pass. Some - of these rows will not be changed from the - previous pass. When the row is not changed, - the new_row variable will be NULL. The rows - and passes are called in order, so you don't - really need the row_num and pass, but I'm - supplying them because it may make your life - easier. - - For the non-NULL rows of interlaced images, - you must call png_progressive_combine_row() - passing in the row and the old row. You can - call this function for NULL rows (it will just - return) and for non-interlaced images (it just - does the memcpy for you) if it will make the - code easier. Thus, you can just do this for - all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, - new_row); - - /* where old_row is what was displayed for - previously for the row. Note that the first - pass (pass == 0, really) will completely cover - the old row, so the rows do not have to be - initialized. After the first pass (and only - for interlaced images), you will have to pass - the current row, and the function will combine - the old row and the new row. - */ - } - - void - end_callback(png_structp png_ptr, png_infop info) - { - /* This function is called after the whole image - has been read, including any chunks after the - image (up to and including the IEND). You - will usually have the same info chunk as you - had in the header, although some data may have - been added to the comments and time fields. - - Most people won't do much here, perhaps setting - a flag that marks the image as finished. - */ - } - - - -.SH IV. Writing - -Much of this is very similar to reading. However, everything of -importance is repeated here, so you won't have to constantly look -back up in the reading section to understand writing. - -.SS Setup - -You will want to do the I/O initialization before you get into libpng, -so if it doesn't work, you don't have anything to undo. If you are not -using the standard I/O functions, you will need to replace them with -custom writing functions. See the discussion under Customizing libpng. - - FILE *fp = fopen(file_name, "wb"); - if (!fp) - { - return (ERROR); - } - -Next, png_struct and png_info need to be allocated and initialized. -As these can be both relatively large, you may not want to store these -on the stack, unless you have stack space to spare. Of course, you -will want to check if they return NULL. If you are also reading, -you won't want to name your read structure and your write structure -both "png_ptr"; you can call them anything you like, such as -"read_ptr" and "write_ptr". Look at pngtest.c, for example. - - png_structp png_ptr = png_create_write_struct - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn); - if (!png_ptr) - return (ERROR); - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - { - png_destroy_write_struct(&png_ptr, - (png_infopp)NULL); - return (ERROR); - } - -If you want to use your own memory allocation routines, -define PNG_USER_MEM_SUPPORTED and use -png_create_write_struct_2() instead of png_create_write_struct(): - - png_structp png_ptr = png_create_write_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); - -After you have these structures, you will need to set up the -error handling. When libpng encounters an error, it expects to -longjmp() back to your routine. Therefore, you will need to call -setjmp() and pass the png_jmpbuf(png_ptr). If you -write the file from different routines, you will need to update -the png_jmpbuf(png_ptr) every time you enter a new routine that will -call a png_*() function. See your documentation of setjmp/longjmp -for your compiler for more information on setjmp/longjmp. See -the discussion on libpng error handling in the Customizing Libpng -section below for more information on the libpng error handling. - - if (setjmp(png_jmpbuf(png_ptr))) - { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return (ERROR); - } - ... - return; - -If you would rather avoid the complexity of setjmp/longjmp issues, -you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case -errors will result in a call to PNG_ABORT() which defaults to abort(). - -Now you need to set up the output code. The default for libpng is to -use the C function fwrite(). If you use this, you will need to pass a -valid FILE * in the function png_init_io(). Be sure that the file is -opened in binary mode. Again, if you wish to handle writing data in -another way, see the discussion on libpng I/O handling in the Customizing -Libpng section below. - - png_init_io(png_ptr, fp); - -If you are embedding your PNG into a datastream such as MNG, and don't -want libpng to write the 8-byte signature, or if you have already -written the signature in your application, use - - png_set_sig_bytes(png_ptr, 8); - -to inform libpng that it should not write a signature. - -.SS Write callbacks - -At this point, you can set up a callback function that will be -called after each row has been written, which you can use to control -a progress meter or the like. It's demonstrated in pngtest.c. -You must supply a function - - void write_row_callback(png_ptr, png_uint_32 row, - int pass); - { - /* put your code here */ - } - -(You can give it another name that you like instead of "write_row_callback") - -To inform libpng about your function, use - - png_set_write_status_fn(png_ptr, write_row_callback); - -You now have the option of modifying how the compression library will -run. The following functions are mainly for testing, but may be useful -in some cases, like if you need to write PNG files extremely fast and -are willing to give up some compression, or if you want to get the -maximum possible compression at the expense of slower writing. If you -have no special needs in this area, let the library do what it wants by -not calling this function at all, as it has been tuned to deliver a good -speed/compression ratio. The second parameter to png_set_filter() is -the filter method, for which the only valid values are 0 (as of the -July 1999 PNG specification, version 1.2) or 64 (if you are writing -a PNG datastream that is to be embedded in a MNG datastream). The third -parameter is a flag that indicates which filter type(s) are to be tested -for each scanline. See the PNG specification for details on the specific filter -types. - - - /* turn on or off filtering, and/or choose - specific filters. You can use either a single - PNG_FILTER_VALUE_NAME or the bitwise OR of one - or more PNG_FILTER_NAME masks. */ - png_set_filter(png_ptr, 0, - PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | - PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | - PNG_FILTER_UP | PNG_FILTER_VALUE_UP | - PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | - PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| - PNG_ALL_FILTERS); - -If an application -wants to start and stop using particular filters during compression, -it should start out with all of the filters (to ensure that the previous -row of pixels will be stored in case it's needed later), and then add -and remove them after the start of compression. - -If you are writing a PNG datastream that is to be embedded in a MNG -datastream, the second parameter can be either 0 or 64. - -The png_set_compression_*() functions interface to the zlib compression -library, and should mostly be ignored unless you really know what you are -doing. The only generally useful call is png_set_compression_level() -which changes how much time zlib spends on trying to compress the image -data. See the Compression Library (zlib.h and algorithm.txt, distributed -with zlib) for details on the compression levels. - - /* set the zlib compression level */ - png_set_compression_level(png_ptr, - Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr, - Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192) - -extern PNG_EXPORT(void,png_set_zbuf_size) - -.SS Setting the contents of info for output - -You now need to fill in the png_info structure with all the data you -wish to write before the actual image. Note that the only thing you -are allowed to write after the image is the text chunks and the time -chunk (as of PNG Specification 1.2, anyway). See png_write_end() and -the latest PNG specification for more information on that. If you -wish to write them before the image, fill them in now, and flag that -data as being valid. If you want to wait until after the data, don't -fill them until png_write_end(). For all the fields in png_info and -their data types, see png.h. For explanations of what the fields -contain, see the PNG specification. - -Some of the more important parts of the png_info are: - - png_set_IHDR(png_ptr, info_ptr, width, height, - bit_depth, color_type, interlace_type, - compression_type, filter_method) - width - holds the width of the image - in pixels (up to 2^31). - height - holds the height of the image - in pixels (up to 2^31). - bit_depth - holds the bit depth of one of the - image channels. - (valid values are 1, 2, 4, 8, 16 - and depend also on the - color_type. See also significant - bits (sBIT) below). - color_type - describes which color/alpha - channels are present. - PNG_COLOR_TYPE_GRAY - (bit depths 1, 2, 4, 8, 16) - PNG_COLOR_TYPE_GRAY_ALPHA - (bit depths 8, 16) - PNG_COLOR_TYPE_PALETTE - (bit depths 1, 2, 4, 8) - PNG_COLOR_TYPE_RGB - (bit_depths 8, 16) - PNG_COLOR_TYPE_RGB_ALPHA - (bit_depths 8, 16) - - PNG_COLOR_MASK_PALETTE - PNG_COLOR_MASK_COLOR - PNG_COLOR_MASK_ALPHA - - interlace_type - PNG_INTERLACE_NONE or - PNG_INTERLACE_ADAM7 - compression_type - (must be - PNG_COMPRESSION_TYPE_DEFAULT) - filter_method - (must be PNG_FILTER_TYPE_DEFAULT - or, if you are writing a PNG to - be embedded in a MNG datastream, - can also be - PNG_INTRAPIXEL_DIFFERENCING) - -If you call png_set_IHDR(), the call must appear before any of the -other png_set_*() functions, because they might require access to some of -the IHDR settings. The remaining png_set_*() functions can be called -in any order. - -If you wish, you can reset the compression_type, interlace_type, or -filter_method later by calling png_set_IHDR() again; if you do this, the -width, height, bit_depth, and color_type must be the same in each call. - - png_set_PLTE(png_ptr, info_ptr, palette, - num_palette); - palette - the palette for the file - (array of png_color) - num_palette - number of entries in the palette - - png_set_gAMA(png_ptr, info_ptr, gamma); - gamma - the gamma the image was created - at (PNG_INFO_gAMA) - - png_set_sRGB(png_ptr, info_ptr, srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of - the sRGB chunk means that the pixel - data is in the sRGB color space. - This chunk also implies specific - values of gAMA and cHRM. Rendering - intent is the CSS-1 property that - has been defined by the International - Color Consortium - (http://www.color.org). - It can be one of - PNG_sRGB_INTENT_SATURATION, - PNG_sRGB_INTENT_PERCEPTUAL, - PNG_sRGB_INTENT_ABSOLUTE, or - PNG_sRGB_INTENT_RELATIVE. - - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, - srgb_intent); - srgb_intent - the rendering intent - (PNG_INFO_sRGB) The presence of the - sRGB chunk means that the pixel - data is in the sRGB color space. - This function also causes gAMA and - cHRM chunks with the specific values - that are consistent with sRGB to be - written. - - png_set_iCCP(png_ptr, info_ptr, name, compression_type, - profile, proflen); - name - The profile name. - compression - The compression type; always - PNG_COMPRESSION_TYPE_BASE for PNG 1.0. - You may give NULL to this argument to - ignore it. - profile - International Color Consortium color - profile data. May contain NULs. - proflen - length of profile data in bytes. - - png_set_sBIT(png_ptr, info_ptr, sig_bit); - sig_bit - the number of significant bits for - (PNG_INFO_sBIT) each of the gray, red, - green, and blue channels, whichever are - appropriate for the given color type - (png_color_16) - - png_set_tRNS(png_ptr, info_ptr, trans, num_trans, - trans_values); - trans - array of transparent entries for - palette (PNG_INFO_tRNS) - trans_values - graylevel or color sample values - (in order red, green, blue) of the - single transparent color for - non-paletted images (PNG_INFO_tRNS) - num_trans - number of transparent entries - (PNG_INFO_tRNS) - - png_set_hIST(png_ptr, info_ptr, hist); - (PNG_INFO_hIST) - hist - histogram of palette (array of - png_uint_16) - - png_set_tIME(png_ptr, info_ptr, mod_time); - mod_time - time image was last modified - (PNG_VALID_tIME) - - png_set_bKGD(png_ptr, info_ptr, background); - background - background color (PNG_VALID_bKGD) - - png_set_text(png_ptr, info_ptr, text_ptr, num_text); - text_ptr - array of png_text holding image - comments - text_ptr[i].compression - type of compression used - on "text" PNG_TEXT_COMPRESSION_NONE - PNG_TEXT_COMPRESSION_zTXt - PNG_ITXT_COMPRESSION_NONE - PNG_ITXT_COMPRESSION_zTXt - text_ptr[i].key - keyword for comment. Must contain - 1-79 characters. - text_ptr[i].text - text comments for current - keyword. Can be NULL or empty. - text_ptr[i].text_length - length of text string, - after decompression, 0 for iTXt - text_ptr[i].itxt_length - length of itxt string, - after decompression, 0 for tEXt/zTXt - text_ptr[i].lang - language of comment (NULL or - empty for unknown). - text_ptr[i].translated_keyword - keyword in UTF-8 (NULL - or empty for unknown). - num_text - number of comments - - png_set_sPLT(png_ptr, info_ptr, &palette_ptr, - num_spalettes); - palette_ptr - array of png_sPLT_struct structures - to be added to the list of palettes - in the info structure. - num_spalettes - number of palette structures to be - added. - - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, - unit_type); - offset_x - positive offset from the left - edge of the screen - offset_y - positive offset from the top - edge of the screen - unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER - - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, - unit_type); - res_x - pixels/unit physical resolution - in x direction - res_y - pixels/unit physical resolution - in y direction - unit_type - PNG_RESOLUTION_UNKNOWN, - PNG_RESOLUTION_METER - - png_set_sCAL(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are doubles) - - png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) - unit - physical scale units (an integer) - width - width of a pixel in physical scale units - height - height of a pixel in physical scale units - (width and height are strings like "2.54") - - png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, - num_unknowns) - unknowns - array of png_unknown_chunk - structures holding unknown chunks - unknowns[i].name - name of unknown chunk - unknowns[i].data - data of unknown chunk - unknowns[i].size - size of unknown chunk's data - unknowns[i].location - position to write chunk in file - 0: do not write chunk - PNG_HAVE_IHDR: before PLTE - PNG_HAVE_PLTE: before IDAT - PNG_AFTER_IDAT: after IDAT - -The "location" member is set automatically according to -what part of the output file has already been written. -You can change its value after calling png_set_unknown_chunks() -as demonstrated in pngtest.c. Within each of the "locations", -the chunks are sequenced according to their position in the -structure (that is, the value of "i", which is the order in which -the chunk was either read from the input file or defined with -png_set_unknown_chunks). - -A quick word about text and num_text. text is an array of png_text -structures. num_text is the number of valid structures in the array. -Each png_text structure holds a language code, a keyword, a text value, -and a compression type. - -The compression types have the same valid numbers as the compression -types of the image data. Currently, the only valid number is zero. -However, you can store text either compressed or uncompressed, unlike -images, which always have to be compressed. So if you don't want the -text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. -Because tEXt and zTXt chunks don't have a language field, if you -specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt -any language code or translated keyword will not be written out. - -Until text gets around 1000 bytes, it is not worth compressing it. -After the text has been written out to the file, the compression type -is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, -so that it isn't written out again at the end (in case you are calling -png_write_end() with the same struct. - -The keywords that are given in the PNG Specification are: - - Title Short (one line) title or - caption for image - Author Name of image's creator - Description Description of image (possibly long) - Copyright Copyright notice - Creation Time Time of original image creation - (usually RFC 1123 format, see below) - Software Software used to create the image - Disclaimer Legal disclaimer - Warning Warning of nature of content - Source Device used to create the image - Comment Miscellaneous comment; conversion - from other image format - -The keyword-text pairs work like this. Keywords should be short -simple descriptions of what the comment is about. Some typical -keywords are found in the PNG specification, as is some recommendations -on keywords. You can repeat keywords in a file. You can even write -some text before the image and some after. For example, you may want -to put a description of the image before the image, but leave the -disclaimer until after, so viewers working over modem connections -don't have to wait for the disclaimer to go over the modem before -they start seeing the image. Finally, keywords should be full -words, not abbreviations. Keywords and text are in the ISO 8859-1 -(Latin-1) character set (a superset of regular ASCII) and can not -contain NUL characters, and should not contain control or other -unprintable characters. To make the comments widely readable, stick -with basic ASCII, and avoid machine specific character set extensions -like the IBM-PC character set. The keyword must be present, but -you can leave off the text string on non-compressed pairs. -Compressed pairs must have a text string, as only the text string -is compressed anyway, so the compression would be meaningless. - -PNG supports modification time via the png_time structure. Two -conversion routines are provided, png_convert_from_time_t() for -time_t and png_convert_from_struct_tm() for struct tm. The -time_t routine uses gmtime(). You don't have to use either of -these, but if you wish to fill in the png_time structure directly, -you should provide the time in universal time (GMT) if possible -instead of your local time. Note that the year number is the full -year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and -that months start with 1. - -If you want to store the time of the original image creation, you should -use a plain tEXt chunk with the "Creation Time" keyword. This is -necessary because the "creation time" of a PNG image is somewhat vague, -depending on whether you mean the PNG file, the time the image was -created in a non-PNG format, a still photo from which the image was -scanned, or possibly the subject matter itself. In order to facilitate -machine-readable dates, it is recommended that the "Creation Time" -tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), -although this isn't a requirement. Unlike the tIME chunk, the -"Creation Time" tEXt chunk is not expected to be automatically changed -by the software. To facilitate the use of RFC 1123 dates, a function -png_convert_to_rfc1123(png_timep) is provided to convert from PNG -time to an RFC 1123 format string. - -.SS Writing unknown chunks - -You can use the png_set_unknown_chunks function to queue up chunks -for writing. You give it a chunk name, raw data, and a size; that's -all there is to it. The chunks will be written by the next following -png_write_info_before_PLTE, png_write_info, or png_write_end function. -Any chunks previously read into the info structure's unknown-chunk -list will also be written out in a sequence that satisfies the PNG -specification's ordering rules. - -.SS The high-level write interface - -At this point there are two ways to proceed; through the high-level -write interface, or through a sequence of low-level write operations. -You can use the high-level interface if your image data is present -in the info structure. All defined output -transformations are permitted, enabled by the following masks. - - PNG_TRANSFORM_IDENTITY No transformation - PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples - PNG_TRANSFORM_PACKSWAP Change order of packed - pixels to LSB first - PNG_TRANSFORM_INVERT_MONO Invert monochrome images - PNG_TRANSFORM_SHIFT Normalize pixels to the - sBIT depth - PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA - to BGRA - PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA - to AG - PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity - to transparency - PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples - PNG_TRANSFORM_STRIP_FILLER Strip out filler - bytes (deprecated). - PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading - filler bytes - PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing - filler bytes - -If you have valid image data in the info structure (you can use -png_set_rows() to put image data in the info structure), simply do this: - - png_write_png(png_ptr, info_ptr, png_transforms, NULL) - -where png_transforms is an integer containing the bitwise OR of some set of -transformation flags. This call is equivalent to png_write_info(), -followed the set of transformations indicated by the transform mask, -then png_write_image(), and finally png_write_end(). - -(The final parameter of this call is not yet used. Someday it might point -to transformation parameters required by some future output transform.) - -You must use png_transforms and not call any png_set_transform() functions -when you use png_write_png(). - -.SS The low-level write interface - -If you are going the low-level route instead, you are now ready to -write all the file information up to the actual image data. You do -this with a call to png_write_info(). - - png_write_info(png_ptr, info_ptr); - -Note that there is one transformation you may need to do before -png_write_info(). In PNG files, the alpha channel in an image is the -level of opacity. If your data is supplied as a level of -transparency, you can invert the alpha channel before you write it, so -that 0 is fully transparent and 255 (in 8-bit or paletted images) or -65535 (in 16-bit images) is fully opaque, with - - png_set_invert_alpha(png_ptr); - -This must appear before png_write_info() instead of later with the -other transformations because in the case of paletted images the tRNS -chunk data has to be inverted before the tRNS chunk is written. If -your image is not a paletted image, the tRNS data (which in such cases -represents a single color to be rendered as transparent) won't need to -be changed, and you can safely do this transformation after your -png_write_info() call. - -If you need to write a private chunk that you want to appear before -the PLTE chunk when PLTE is present, you can write the PNG info in -two steps, and insert code to write your own chunk between them: - - png_write_info_before_PLTE(png_ptr, info_ptr); - png_set_unknown_chunks(png_ptr, info_ptr, ...); - png_write_info(png_ptr, info_ptr); - -After you've written the file information, you can set up the library -to handle any special transformations of the image data. The various -ways to transform the data will be described in the order that they -should occur. This is important, as some of these change the color -type and/or bit depth of the data, and some others only work on -certain color types and bit depths. Even though each transformation -checks to see if it has data that it can do something with, you should -make sure to only enable a transformation if it will be valid for the -data. For example, don't swap red and blue on grayscale data. - -PNG files store RGB pixels packed into 3 or 6 bytes. This code tells -the library to strip input data that has 4 or 8 bytes per pixel down -to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 -bytes per pixel). - - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - -where the 0 is unused, and the location is either PNG_FILLER_BEFORE or -PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel -is stored XRGB or RGBX. - -PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as -they can, resulting in, for example, 8 pixels per byte for 1 bit files. -If the data is supplied at 1 pixel per byte, use this code, which will -correctly pack the pixels into a single byte: - - png_set_packing(png_ptr); - -PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your -data is of another bit depth, you can write an sBIT chunk into the -file so that decoders can recover the original data if desired. - - /* Set the true bit depth of the image data */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit.red = true_bit_depth; - sig_bit.green = true_bit_depth; - sig_bit.blue = true_bit_depth; - } - else - { - sig_bit.gray = true_bit_depth; - } - if (color_type & PNG_COLOR_MASK_ALPHA) - { - sig_bit.alpha = true_bit_depth; - } - - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - -If the data is stored in the row buffer in a bit depth other than -one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), -this will scale the values to appear to be the correct bit depth as -is required by PNG. - - png_set_shift(png_ptr, &sig_bit); - -PNG files store 16 bit pixels in network byte order (big-endian, -ie. most significant bits first). This code would be used if they are -supplied the other way (little-endian, i.e. least significant bits -first, the way PCs store them): - - if (bit_depth > 8) - png_set_swap(png_ptr); - -If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you -need to change the order the pixels are packed into bytes, you can use: - - if (bit_depth < 8) - png_set_packswap(png_ptr); - -PNG files store 3 color pixels in red, green, blue order. This code -would be used if they are supplied as blue, green, red: - - png_set_bgr(png_ptr); - -PNG files describe monochrome as black being zero and white being -one. This code would be used if the pixels are supplied with this reversed -(black being one and white being zero): - - png_set_invert_mono(png_ptr); - -Finally, you can write your own transformation function if none of -the existing ones meets your needs. This is done by setting a callback -with - - png_set_write_user_transform_fn(png_ptr, - write_transform_fn); - -You must supply the function - - void write_transform_fn(png_ptr ptr, row_info_ptr - row_info, png_bytep data) - -See pngtest.c for a working example. Your function will be called -before any of the other transformations are processed. - -You can also set up a pointer to a user structure for use by your -callback function. - - png_set_user_transform_info(png_ptr, user_ptr, 0, 0); - -The user_channels and user_depth parameters of this function are ignored -when writing; you can set them to zero as shown. - -You can retrieve the pointer via the function png_get_user_transform_ptr(). -For example: - - voidp write_user_transform_ptr = - png_get_user_transform_ptr(png_ptr); - -It is possible to have libpng flush any pending output, either manually, -or automatically after a certain number of lines have been written. To -flush the output stream a single time call: - - png_write_flush(png_ptr); - -and to have libpng flush the output stream periodically after a certain -number of scanlines have been written, call: - - png_set_flush(png_ptr, nrows); - -Note that the distance between rows is from the last time png_write_flush() -was called, or the first row of the image if it has never been called. -So if you write 50 lines, and then png_set_flush 25, it will flush the -output on the next scanline, and every 25 lines thereafter, unless -png_write_flush() is called before 25 more lines have been written. -If nrows is too small (less than about 10 lines for a 640 pixel wide -RGB image) the image compression may decrease noticeably (although this -may be acceptable for real-time applications). Infrequent flushing will -only degrade the compression performance by a few percent over images -that do not use flushing. - -.SS Writing the image data - -That's it for the transformations. Now you can write the image data. -The simplest way to do this is in one function call. If you have the -whole image in memory, you can just call png_write_image() and libpng -will write the image. You will need to pass in an array of pointers to -each row. This function automatically handles interlacing, so you don't -need to call png_set_interlace_handling() or call this function multiple -times, or any of that other stuff necessary with png_write_rows(). - - png_write_image(png_ptr, row_pointers); - -where row_pointers is: - - png_byte *row_pointers[height]; - -You can point to void or char or whatever you use for pixels. - -If you don't want to write the whole image at once, you can -use png_write_rows() instead. If the file is not interlaced, -this is simple: - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -row_pointers is the same as in the png_write_image() call. - -If you are just writing one row at a time, you can do this with -a single row_pointer instead of an array of row_pointers: - - png_bytep row_pointer = row; - - png_write_row(png_ptr, row_pointer); - -When the file is interlaced, things can get a good deal more -complicated. The only currently (as of the PNG Specification -version 1.2, dated July 1999) defined interlacing scheme for PNG files -is the "Adam7" interlace scheme, that breaks down an -image into seven smaller images of varying size. libpng will build -these images for you, or you can do them yourself. If you want to -build them yourself, see the PNG specification for details of which -pixels to write when. - -If you don't want libpng to handle the interlacing details, just -use png_set_interlace_handling() and call png_write_rows() the -correct number of times to write all seven sub-images. - -If you want libpng to build the sub-images, call this before you start -writing any rows: - - number_of_passes = - png_set_interlace_handling(png_ptr); - -This will return the number of passes needed. Currently, this -is seven, but may change if another interlace type is added. - -Then write the complete image number_of_passes times. - - png_write_rows(png_ptr, row_pointers, - number_of_rows); - -As some of these rows are not used, and thus return immediately, -you may want to read about interlacing in the PNG specification, -and only update the rows that are actually used. - -.SS Finishing a sequential write - -After you are finished writing the image, you should finish writing -the file. If you are interested in writing comments or time, you should -pass an appropriately filled png_info pointer. If you are not interested, -you can pass NULL. - - png_write_end(png_ptr, info_ptr); - -When you are done, you can free all memory used by libpng like this: - - png_destroy_write_struct(&png_ptr, &info_ptr); - -It is also possible to individually free the info_ptr members that -point to libpng-allocated storage with the following function: - - png_free_data(png_ptr, info_ptr, mask, seq) - mask - identifies data to be freed, a mask - containing the bitwise OR of one or - more of - PNG_FREE_PLTE, PNG_FREE_TRNS, - PNG_FREE_HIST, PNG_FREE_ICCP, - PNG_FREE_PCAL, PNG_FREE_ROWS, - PNG_FREE_SCAL, PNG_FREE_SPLT, - PNG_FREE_TEXT, PNG_FREE_UNKN, - or simply PNG_FREE_ALL - seq - sequence number of item to be freed - (-1 for all items) - -This function may be safely called when the relevant storage has -already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those -cases do nothing. The "seq" parameter is ignored if only one item -of the selected data type, such as PLTE, is allowed. If "seq" is not --1, and multiple items are allowed for the data type identified in -the mask, such as text or sPLT, only the n'th item in the structure -is freed, where n is "seq". - -If you allocated data such as a palette that you passed -in to libpng with png_set_*, you must not free it until just before the call to -png_destroy_write_struct(). - -The default behavior is only to free data that was allocated internally -by libpng. This can be changed, so that libpng will not free the data, -or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with - - png_data_freer(png_ptr, info_ptr, freer, mask) - mask - which data elements are affected - same choices as in png_free_data() - freer - one of - PNG_DESTROY_WILL_FREE_DATA - PNG_SET_WILL_FREE_DATA - PNG_USER_WILL_FREE_DATA - -For example, to transfer responsibility for some data from a read structure -to a write structure, you could use - - png_data_freer(read_ptr, read_info_ptr, - PNG_USER_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - png_data_freer(write_ptr, write_info_ptr, - PNG_DESTROY_WILL_FREE_DATA, - PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) - -thereby briefly reassigning responsibility for freeing to the user but -immediately afterwards reassigning it once more to the write_destroy -function. Having done this, it would then be safe to destroy the read -structure and continue to use the PLTE, tRNS, and hIST data in the write -structure. - -This function only affects data that has already been allocated. -You can call this function before calling after the png_set_*() functions -to control whether the user or png_destroy_*() is supposed to free the data. -When the user assumes responsibility for libpng-allocated data, the -application must use -png_free() to free it, and when the user transfers responsibility to libpng -for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. - -If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword -separately, do not transfer responsibility for freeing text_ptr to libpng, -because when libpng fills a png_text structure it combines these members with -the key member, and png_free_data() will free only text_ptr.key. Similarly, -if you transfer responsibility for free'ing text_ptr from libpng to your -application, your application must not separately free those members. -For a more compact example of writing a PNG image, see the file example.c. - -.SH V. Modifying/Customizing libpng: - -There are two issues here. The first is changing how libpng does -standard things like memory allocation, input/output, and error handling. -The second deals with more complicated things like adding new chunks, -adding new transformations, and generally changing how libpng works. -Both of those are compile-time issues; that is, they are generally -determined at the time the code is written, and there is rarely a need -to provide the user with a means of changing them. - -Memory allocation, input/output, and error handling - -All of the memory allocation, input/output, and error handling in libpng -goes through callbacks that are user-settable. The default routines are -in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change -these functions, call the appropriate png_set_*_fn() function. - -Memory allocation is done through the functions png_malloc() -and png_free(). These currently just call the standard C functions. If -your pointers can't access more then 64K at a time, you will want to set -MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling -memory allocation on a platform will change between applications, these -functions must be modified in the library at compile time. If you prefer -to use a different method of allocating and freeing data, you can use -png_create_read_struct_2() or png_create_write_struct_2() to register -your own functions as described above. -These functions also provide a void pointer that can be retrieved via - - mem_ptr=png_get_mem_ptr(png_ptr); - -Your replacement memory functions must have prototypes as follows: - - png_voidp malloc_fn(png_structp png_ptr, - png_size_t size); - void free_fn(png_structp png_ptr, png_voidp ptr); - -Your malloc_fn() must return NULL in case of failure. The png_malloc() -function will normally call png_error() if it receives a NULL from the -system memory allocator or from your replacement malloc_fn(). - -Your free_fn() will never be called with a NULL ptr, since libpng's -png_free() checks for NULL before calling free_fn(). - -Input/Output in libpng is done through png_read() and png_write(), -which currently just call fread() and fwrite(). The FILE * is stored in -png_struct and is initialized via png_init_io(). If you wish to change -the method of I/O, the library supplies callbacks that you can set -through the function png_set_read_fn() and png_set_write_fn() at run -time, instead of calling the png_init_io() function. These functions -also provide a void pointer that can be retrieved via the function -png_get_io_ptr(). For example: - - png_set_read_fn(png_structp read_ptr, - voidp read_io_ptr, png_rw_ptr read_data_fn) - - png_set_write_fn(png_structp write_ptr, - voidp write_io_ptr, png_rw_ptr write_data_fn, - png_flush_ptr output_flush_fn); - - voidp read_io_ptr = png_get_io_ptr(read_ptr); - voidp write_io_ptr = png_get_io_ptr(write_ptr); - -The replacement I/O functions must have prototypes as follows: - - void user_read_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_write_data(png_structp png_ptr, - png_bytep data, png_size_t length); - void user_flush_data(png_structp png_ptr); - -The user_read_data() function is responsible for detecting and -handling end-of-data errors. - -Supplying NULL for the read, write, or flush functions sets them back -to using the default C stream functions, which expect the io_ptr to -point to a standard *FILE structure. It is probably a mistake -to use NULL for one of write_data_fn and output_flush_fn but not both -of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. -It is an error to read from a write stream, and vice versa. - -Error handling in libpng is done through png_error() and png_warning(). -Errors handled through png_error() are fatal, meaning that png_error() -should never return to its caller. Currently, this is handled via -setjmp() and longjmp() (unless you have compiled libpng with -PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), -but you could change this to do things like exit() if you should wish. - -On non-fatal errors, png_warning() is called -to print a warning message, and then control returns to the calling code. -By default png_error() and png_warning() print a message on stderr via -fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined -(because you don't want the messages) or PNG_NO_STDIO defined (because -fprintf() isn't available). If you wish to change the behavior of the error -functions, you will need to set up your own message callbacks. These -functions are normally supplied at the time that the png_struct is created. -It is also possible to redirect errors and warnings to your own replacement -functions after png_create_*_struct() has been called by calling: - - png_set_error_fn(png_structp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, - png_error_ptr warning_fn); - - png_voidp error_ptr = png_get_error_ptr(png_ptr); - -If NULL is supplied for either error_fn or warning_fn, then the libpng -default function will be used, calling fprintf() and/or longjmp() if a -problem is encountered. The replacement error functions should have -parameters as follows: - - void user_error_fn(png_structp png_ptr, - png_const_charp error_msg); - void user_warning_fn(png_structp png_ptr, - png_const_charp warning_msg); - -The motivation behind using setjmp() and longjmp() is the C++ throw and -catch exception handling methods. This makes the code much easier to write, -as there is no need to check every return code of every function call. -However, there are some uncertainties about the status of local variables -after a longjmp, so the user may want to be careful about doing anything after -setjmp returns non-zero besides returning itself. Consult your compiler -documentation for more details. For an alternative approach, you may wish -to use the "cexcept" facility (see http://cexcept.sourceforge.net). - -.SS Custom chunks - -If you need to read or write custom chunks, you may need to get deeper -into the libpng code. The library now has mechanisms for storing -and writing chunks of unknown type; you can even declare callbacks -for custom chunks. However, this may not be good enough if the -library code itself needs to know about interactions between your -chunk and existing `intrinsic' chunks. - -If you need to write a new intrinsic chunk, first read the PNG -specification. Acquire a first level of -understanding of how it works. Pay particular attention to the -sections that describe chunk names, and look at how other chunks were -designed, so you can do things similarly. Second, check out the -sections of libpng that read and write chunks. Try to find a chunk -that is similar to yours and use it as a template. More details can -be found in the comments inside the code. It is best to handle unknown -chunks in a generic method, via callback functions, instead of by -modifying libpng functions. - -If you wish to write your own transformation for the data, look through -the part of the code that does the transformations, and check out some of -the simpler ones to get an idea of how they work. Try to find a similar -transformation to the one you want to add and copy off of it. More details -can be found in the comments inside the code itself. - -.SS Configuring for 16 bit platforms - -You will want to look into zconf.h to tell zlib (and thus libpng) that -it cannot allocate more then 64K at a time. Even if you can, the memory -won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. - -.SS Configuring for DOS - -For DOS users who only have access to the lower 640K, you will -have to limit zlib's memory usage via a png_set_compression_mem_level() -call. See zlib.h or zconf.h in the zlib library for more information. - -.SS Configuring for Medium Model - -Libpng's support for medium model has been tested on most of the popular -compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets -defined, and FAR gets defined to far in pngconf.h, and you should be -all set. Everything in the library (except for zlib's structure) is -expecting far data. You must use the typedefs with the p or pp on -the end for pointers (or at least look at them and be careful). Make -note that the rows of data are defined as png_bytepp, which is an -unsigned char far * far *. - -.SS Configuring for gui/windowing platforms: - -You will need to write new error and warning functions that use the GUI -interface, as described previously, and set them to be the error and -warning functions at the time that png_create_*_struct() is called, -in order to have them available during the structure initialization. -They can be changed later via png_set_error_fn(). On some compilers, -you may also have to change the memory allocators (png_malloc, etc.). - -.SS Configuring for compiler xxx: - -All includes for libpng are in pngconf.h. If you need to add, change -or delete an include, this is the place to do it. -The includes that are not needed outside libpng are protected by the -PNG_INTERNAL definition, which is only defined for those routines inside -libpng itself. The files in libpng proper only include png.h, which -includes pngconf.h. - -.SS Configuring zlib: - -There are special functions to configure the compression. Perhaps the -most useful one changes the compression level, which currently uses -input compression values in the range 0 - 9. The library normally -uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests -have shown that for a large majority of images, compression values in -the range 3-6 compress nearly as well as higher levels, and do so much -faster. For online applications it may be desirable to have maximum speed -(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also -specify no compression (Z_NO_COMPRESSION = 0), but this would create -files larger than just storing the raw bitmap. You can specify the -compression level by calling: - - png_set_compression_level(png_ptr, level); - -Another useful one is to reduce the memory level used by the library. -The memory level defaults to 8, but it can be lowered if you are -short on memory (running DOS, for example, where you only have 640K). -Note that the memory level does have an effect on compression; among -other things, lower levels will result in sections of incompressible -data being emitted in smaller stored blocks, with a correspondingly -larger relative overhead of up to 15% in the worst case. - - png_set_compression_mem_level(png_ptr, level); - -The other functions are for configuring zlib. They are not recommended -for normal use and may result in writing an invalid PNG file. See -zlib.h for more information on what these mean. - - png_set_compression_strategy(png_ptr, - strategy); - png_set_compression_window_bits(png_ptr, - window_bits); - png_set_compression_method(png_ptr, method); - png_set_compression_buffer_size(png_ptr, size); - -.SS Controlling row filtering - -If you want to control whether libpng uses filtering or not, which -filters are used, and how it goes about picking row filters, you -can call one of these functions. The selection and configuration -of row filters can have a significant impact on the size and -encoding speed and a somewhat lesser impact on the decoding speed -of an image. Filtering is enabled by default for RGB and grayscale -images (with and without alpha), but not for paletted images nor -for any images with bit depths less than 8 bits/pixel. - -The 'method' parameter sets the main filtering method, which is -currently only '0' in the PNG 1.2 specification. The 'filters' -parameter sets which filter(s), if any, should be used for each -scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS -to turn filtering on and off, respectively. - -Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, -PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise -ORed together with '|' to specify one or more filters to use. -These filters are described in more detail in the PNG specification. -If you intend to change the filter type during the course of writing -the image, you should start with flags set for all of the filters -you intend to use so that libpng can initialize its internal -structures appropriately for all of the filter types. (Note that this -means the first row must always be adaptively filtered, because libpng -currently does not allocate the filter buffers until png_write_row() -is called for the first time.) - - filters = PNG_FILTER_NONE | PNG_FILTER_SUB - PNG_FILTER_UP | PNG_FILTER_AVG | - PNG_FILTER_PAETH | PNG_ALL_FILTERS; - - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, - filters); - The second parameter can also be - PNG_INTRAPIXEL_DIFFERENCING if you are - writing a PNG to be embedded in a MNG - datastream. This parameter must be the - same as the value of filter_method used - in png_set_IHDR(). - -It is also possible to influence how libpng chooses from among the -available filters. This is done in one or both of two ways - by -telling it how important it is to keep the same filter for successive -rows, and by telling it the relative computational costs of the filters. - - double weights[3] = {1.5, 1.3, 1.1}, - costs[PNG_FILTER_VALUE_LAST] = - {1.0, 1.3, 1.3, 1.5, 1.7}; - - png_set_filter_heuristics(png_ptr, - PNG_FILTER_HEURISTIC_WEIGHTED, 3, - weights, costs); - -The weights are multiplying factors that indicate to libpng that the -row filter should be the same for successive rows unless another row filter -is that many times better than the previous filter. In the above example, -if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a -"sum of absolute differences" 1.5 x 1.3 times higher than other filters -and still be chosen, while the NONE filter could have a sum 1.1 times -higher than other filters and still be chosen. Unspecified weights are -taken to be 1.0, and the specified weights should probably be declining -like those above in order to emphasize recent filters over older filters. - -The filter costs specify for each filter type a relative decoding cost -to be considered when selecting row filters. This means that filters -with higher costs are less likely to be chosen over filters with lower -costs, unless their "sum of absolute differences" is that much smaller. -The costs do not necessarily reflect the exact computational speeds of -the various filters, since this would unduly influence the final image -size. - -Note that the numbers above were invented purely for this example and -are given only to help explain the function usage. Little testing has -been done to find optimum values for either the costs or the weights. - -.SS Removing unwanted object code - -There are a bunch of #define's in pngconf.h that control what parts of -libpng are compiled. All the defines end in _SUPPORTED. If you are -never going to use a capability, you can change the #define to #undef -before recompiling libpng and save yourself code and data space, or -you can turn off individual capabilities with defines that begin with -PNG_NO_. - -You can also turn all of the transforms and ancillary chunk capabilities -off en masse with compiler directives that define -PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, -or all four, -along with directives to turn on any of the capabilities that you do -want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable -the extra transformations but still leave the library fully capable of reading -and writing PNG files with all known public chunks -Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive -produces a library that is incapable of reading or writing ancillary chunks. -If you are not using the progressive reading capability, you can -turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse -this with the INTERLACING capability, which you'll still have). - -All the reading and writing specific code are in separate files, so the -linker should only grab the files it needs. However, if you want to -make sure, or if you are building a stand alone library, all the -reading files start with pngr and all the writing files start with -pngw. The files that don't match either (like png.c, pngtrans.c, etc.) -are used for both reading and writing, and always need to be included. -The progressive reader is in pngpread.c - -If you are creating or distributing a dynamically linked library (a .so -or DLL file), you should not remove or disable any parts of the library, -as this will cause applications linked with different versions of the -library to fail if they call functions not available in your library. -The size of the library itself should not be an issue, because only -those sections that are actually used will be loaded into memory. - -.SS Requesting debug printout - -The macro definition PNG_DEBUG can be used to request debugging -printout. Set it to an integer value in the range 0 to 3. Higher -numbers result in increasing amounts of debugging information. The -information is printed to the "stderr" file, unless another file -name is specified in the PNG_DEBUG_FILE macro definition. - -When PNG_DEBUG > 0, the following functions (macros) become available: - - png_debug(level, message) - png_debug1(level, message, p1) - png_debug2(level, message, p1, p2) - -in which "level" is compared to PNG_DEBUG to decide whether to print -the message, "message" is the formatted string to be printed, -and p1 and p2 are parameters that are to be embedded in the string -according to printf-style formatting directives. For example, - - png_debug1(2, "foo=%d\n", foo); - -is expanded to - - if(PNG_DEBUG > 2) - fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); - -When PNG_DEBUG is defined but is zero, the macros aren't defined, but you -can still use PNG_DEBUG to control your own debugging: - - #ifdef PNG_DEBUG - fprintf(stderr, ... - #endif - -When PNG_DEBUG = 1, the macros are defined, but only png_debug statements -having level = 0 will be printed. There aren't any such statements in -this version of libpng, but if you insert some they will be printed. - -.SH VI. MNG support - -The MNG specification (available at http://www.libpng.org/pub/mng) allows -certain extensions to PNG for PNG images that are embedded in MNG datastreams. -Libpng can support some of these extensions. To enable them, use the -png_permit_mng_features() function: - - feature_set = png_permit_mng_features(png_ptr, mask) - mask is a png_uint_32 containing the bitwise OR of the - features you want to enable. These include - PNG_FLAG_MNG_EMPTY_PLTE - PNG_FLAG_MNG_FILTER_64 - PNG_ALL_MNG_FEATURES - feature_set is a png_uint_32 that is the bitwise AND of - your mask with the set of MNG features that is - supported by the version of libpng that you are using. - -It is an error to use this function when reading or writing a standalone -PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped -in a MNG datastream. As a minimum, it must have the MNG 8-byte signature -and the MHDR and MEND chunks. Libpng does not provide support for these -or any other MNG chunks; your application must provide its own support for -them. You may wish to consider using libmng (available at -http://www.libmng.com) instead. - -.SH VII. Changes to Libpng from version 0.88 - -It should be noted that versions of libpng later than 0.96 are not -distributed by the original libpng author, Guy Schalnat, nor by -Andreas Dilger, who had taken over from Guy during 1996 and 1997, and -distributed versions 0.89 through 0.96, but rather by another member -of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are -still alive and well, but they have moved on to other things. - -The old libpng functions png_read_init(), png_write_init(), -png_info_init(), png_read_destroy(), and png_write_destroy() have been -moved to PNG_INTERNAL in version 0.95 to discourage their use. These -functions will be removed from libpng version 2.0.0. - -The preferred method of creating and initializing the libpng structures is -via the png_create_read_struct(), png_create_write_struct(), and -png_create_info_struct() because they isolate the size of the structures -from the application, allow version error checking, and also allow the -use of custom error handling routines during the initialization, which -the old functions do not. The functions png_read_destroy() and -png_write_destroy() do not actually free the memory that libpng -allocated for these structs, but just reset the data structures, so they -can be used instead of png_destroy_read_struct() and -png_destroy_write_struct() if you feel there is too much system overhead -allocating and freeing the png_struct for each image read. - -Setting the error callbacks via png_set_message_fn() before -png_read_init() as was suggested in libpng-0.88 is no longer supported -because this caused applications that do not use custom error functions -to fail if the png_ptr was not initialized to zero. It is still possible -to set the error callbacks AFTER png_read_init(), or to change them with -png_set_error_fn(), which is essentially the same function, but with a new -name to force compilation errors with applications that try to use the old -method. - -Starting with version 1.0.7, you can find out which version of the library -you are using at run-time: - - png_uint_32 libpng_vn = png_access_version_number(); - -The number libpng_vn is constructed from the major version, minor -version with leading zero, and release number with leading zero, -(e.g., libpng_vn for version 1.0.7 is 10007). - -You can also check which version of png.h you used when compiling your -application: - - png_uint_32 application_vn = PNG_LIBPNG_VER; - -.SH VIII. Changes to Libpng from version 1.0.x to 1.2.x - -Support for user memory management was enabled by default. To -accomplish this, the functions png_create_read_struct_2(), -png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), -png_malloc_default(), and png_free_default() were added. - -Support for certain MNG features was enabled. - -Support for numbered error messages was added. However, we never got -around to actually numbering the error messages. The function -png_set_strip_error_numbers() was added (Note: the prototype for this -function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE -builds of libpng-1.2.15. It was restored in libpng-1.2.36). - -The png_malloc_warn() function was added at libpng-1.2.3. This issues -a png_warning and returns NULL instead of aborting when it fails to -acquire the requested memory allocation. - -Support for setting user limits on image width and height was enabled -by default. The functions png_set_user_limits(), png_get_user_width_max(), -and png_get_user_height_max() were added at libpng-1.2.6. - -The png_set_add_alpha() function was added at libpng-1.2.7. - -The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. -Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the -tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is -deprecated. - -A number of macro definitions in support of runtime selection of -assembler code features (especially Intel MMX code support) were -added at libpng-1.2.0: - - PNG_ASM_FLAG_MMX_SUPPORT_COMPILED - PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU - PNG_ASM_FLAG_MMX_READ_COMBINE_ROW - PNG_ASM_FLAG_MMX_READ_INTERLACE - PNG_ASM_FLAG_MMX_READ_FILTER_SUB - PNG_ASM_FLAG_MMX_READ_FILTER_UP - PNG_ASM_FLAG_MMX_READ_FILTER_AVG - PNG_ASM_FLAG_MMX_READ_FILTER_PAETH - PNG_ASM_FLAGS_INITIALIZED - PNG_MMX_READ_FLAGS - PNG_MMX_FLAGS - PNG_MMX_WRITE_FLAGS - PNG_MMX_FLAGS - -We added the following functions in support of runtime -selection of assembler code features: - - png_get_mmx_flagmask() - png_set_mmx_thresholds() - png_get_asm_flags() - png_get_mmx_bitdepth_threshold() - png_get_mmx_rowbytes_threshold() - png_set_asm_flags() - -We replaced all of these functions with simple stubs in libpng-1.2.20, -when the Intel assembler code was removed due to a licensing issue. - -.SH IX. (Omitted) - -.SH X. Detecting libpng - -The png_get_io_ptr() function has been present since libpng-0.88, has never -changed, and is unaffected by conditional compilation macros. It is the -best choice for use in configure scripts for detecting the presence of any -libpng version since 0.88. In an autoconf "configure.in" you could use - - AC_CHECK_LIB(png, png_get_io_ptr, ... - -.SH XI. Source code repository - -Since about February 2009, version 1.2.34, libpng has been under "git" source -control. The git repository was built from old libpng-x.y.z.tar.gz files -going back to version 0.70. You can access the git repository (read only) -at - - git://libpng.git.sourceforge.net/gitroot/libpng - -or you can browse it via "gitweb" at - - http://libpng.git.sourceforge.net/git/gitweb.cgi?p=libpng - -Patches can be sent to glennrp at users.sourceforge.net or to -png-mng-implement at lists.sourceforge.net or you can upload them to -the libpng bug tracker at - - http://libpng.sourceforge.net - -.SH XII. Coding style - -Our coding style is similar to the "Allman" style, with curly -braces on separate lines: - - if (condition) - { - action; - } - - else if (another condition) - { - another action; - } - -The braces can be omitted from simple one-line actions: - - if (condition) - return (0); - -We use 3-space indentation, except for continued statements which -are usually indented the same as the first line of the statement -plus four more spaces. - -Comments appear with the leading "/*" at the same indentation as -the statement that follows the comment: - - /* Single-line comment */ - statement; - - /* Multiple-line - * comment - */ - statement; - -Very short comments can be placed at the end of the statement -to which they pertain: - - statement; /* comment */ - -We don't use C++ style ("//") comments. We have, however, -used them in the past in some now-abandoned MMX assembler -code. - -Functions and their curly braces are not indented, and -exported functions are marked with PNGAPI: - - /* This is a public function that is visible to - * application programers. It does thus-and-so. - */ - void PNGAPI - png_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for all exported functions appear in png.h, -above the comment that says - - /* Maintainer: Put new public prototypes here ... */ - -We mark all non-exported functions with "/* PRIVATE */"": - - void /* PRIVATE */ - png_non_exported_function(png_ptr, png_info, foo) - { - body; - } - -The prototypes for non-exported functions (except for those in -pngtest) appear in -the PNG_INTERNAL section of png.h -above the comment that says - - /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -The names of all exported functions and variables begin -with "png_", and all publicly visible C preprocessor -macros begin with "PNG_". - -We put a space after each comma and after each semicolon -in "for" statments, and we put spaces before and after each -C binary operator and after "for" or "while". We don't -put a space between a typecast and the expression being -cast, nor do we put one between a function name and the -left parenthesis that follows it: - - for (i = 2; i > 0; --i) - x[i] = a(x) + (int)b; - -We prefer #ifdef and #ifndef to #if defined() and if !defined() -when there is only one macro being tested. - -Other rules can be inferred by inspecting the libpng -source. - -.SH XIII. Y2K Compliance in libpng - -September 10, 2009 - -Since the PNG Development group is an ad-hoc body, we can't make -an official declaration. - -This is your unofficial assurance that libpng from version 0.71 and -upward through 1.2.40 are Y2K compliant. It is my belief that earlier -versions were also Y2K compliant. - -Libpng only has three year fields. One is a 2-byte unsigned integer that -will hold years up to 65535. The other two hold the date in text -format, and will hold years up to 9999. - -The integer is - "png_uint_16 year" in png_time_struct. - -The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. - -There are seven time-related functions: - - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) - png_convert_from_struct_tm() in pngwrite.c, called - in pngwrite.c - png_convert_from_time_t() in pngwrite.c - png_get_tIME() in pngget.c - png_handle_tIME() in pngrutil.c, called in pngread.c - png_set_tIME() in pngset.c - png_write_tIME() in pngwutil.c, called in pngwrite.c - -All appear to handle dates properly in a Y2K environment. The -png_convert_from_time_t() function calls gmtime() to convert from system -clock time, which returns (year - 1900), which we properly convert to -the full 4-digit year. There is a possibility that applications using -libpng are not passing 4-digit years into the png_convert_to_rfc_1123() -function, or that they are incorrectly passing only a 2-digit year -instead of "year - 1900" into the png_convert_from_struct_tm() function, -but this is not under our control. The libpng documentation has always -stated that it works with 4-digit years, and the APIs have been -documented as such. - -The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned -integer to hold the year, and can hold years as large as 65535. - -zlib, upon which libpng depends, is also Y2K compliant. It contains -no date-related code. - - - Glenn Randers-Pehrson - libpng maintainer - PNG Development Group - -.SH NOTE - -Note about libpng version numbers: - -Due to various miscommunications, unforeseen code incompatibilities -and occasional factors outside the authors' control, version numbering -on the library has not always been consistent and straightforward. -The following table summarizes matters since version 0.89c, which was -the first widely used release: - - source png.h png.h shared-lib - version string int version - ------- ------ ----- ---------- - 0.89c ("beta 3") 0.89 89 1.0.89 - 0.90 ("beta 4") 0.90 90 0.90 - 0.95 ("beta 5") 0.95 95 0.95 - 0.96 ("beta 6") 0.96 96 0.96 - 0.97b ("beta 7") 1.00.97 97 1.0.1 - 0.97c 0.97 97 2.0.97 - 0.98 0.98 98 2.0.98 - 0.99 0.99 98 2.0.99 - 0.99a-m 0.99 99 2.0.99 - 1.00 1.00 100 2.1.0 - 1.0.0 1.0.0 100 2.1.0 - 1.0.0 (from here on, the 100 2.1.0 - 1.0.1 png.h string is 10001 2.1.0 - 1.0.1a-e identical to the 10002 from here on, the - 1.0.2 source version) 10002 shared library is 2.V - 1.0.2a-b 10003 where V is the source - 1.0.1 10001 code version except as - 1.0.1a-e 10002 2.1.0.1a-e noted. - 1.0.2 10002 2.1.0.2 - 1.0.2a-b 10003 2.1.0.2a-b - 1.0.3 10003 2.1.0.3 - 1.0.3a-d 10004 2.1.0.3a-d - 1.0.4 10004 2.1.0.4 - 1.0.4a-f 10005 2.1.0.4a-f - 1.0.5 (+ 2 patches) 10005 2.1.0.5 - 1.0.5a-d 10006 2.1.0.5a-d - 1.0.5e-r 10100 2.1.0.5e-r - 1.0.5s-v 10006 2.1.0.5s-v - 1.0.6 (+ 3 patches) 10006 2.1.0.6 - 1.0.6d-g 10007 2.1.0.6d-g - 1.0.6h 10007 10.6h - 1.0.6i 10007 10.6i - 1.0.6j 10007 2.1.0.6j - 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 - 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 - 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 - 1.0.7 1 10007 2.1.0.7 - 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 - 1.0.8rc1 1 10008 2.1.0.8rc1 - 1.0.8 1 10008 2.1.0.8 - 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 - 1.0.9rc1 1 10009 2.1.0.9rc1 - 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 - 1.0.9rc2 1 10009 2.1.0.9rc2 - 1.0.9 1 10009 2.1.0.9 - 1.0.10beta1 1 10010 2.1.0.10beta1 - 1.0.10rc1 1 10010 2.1.0.10rc1 - 1.0.10 1 10010 2.1.0.10 - 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 - 1.0.11rc1 1 10011 2.1.0.11rc1 - 1.0.11 1 10011 2.1.0.11 - 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 - 1.0.12rc1 2 10012 2.1.0.12rc1 - 1.0.12 2 10012 2.1.0.12 - 1.1.0a-f - 10100 2.1.1.0a-f abandoned - 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 - 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 - 1.2.0rc1 3 10200 3.1.2.0rc1 - 1.2.0 3 10200 3.1.2.0 - 1.2.1beta-4 3 10201 3.1.2.1beta1-4 - 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 - 1.2.1 3 10201 3.1.2.1 - 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 - 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 - 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 - 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 - 1.0.13 10 10013 10.so.0.1.0.13 - 1.2.2 12 10202 12.so.0.1.2.2 - 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 - 1.2.3 12 10203 12.so.0.1.2.3 - 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 - 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 - 1.0.14 10 10014 10.so.0.1.0.14 - 1.2.4 13 10204 12.so.0.1.2.4 - 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 - 1.0.15rc1 10 10015 10.so.0.1.0.15rc1 - 1.0.15 10 10015 10.so.0.1.0.15 - 1.2.5 13 10205 12.so.0.1.2.5 - 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 - 1.2.6rc1-5 13 10206 12.so.0.1.2.6rc1-5 - 1.0.16 10 10016 10.so.0.1.0.16 - 1.2.6 13 10206 12.so.0.1.2.6 - 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 - 1.0.17rc1 10 10017 10.so.0.1.0.17rc1 - 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 - 1.0.17 10 10017 10.so.0.1.0.17 - 1.2.7 13 10207 12.so.0.1.2.7 - 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 - 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5 - 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 - 1.0.18 10 10018 10.so.0.1.0.18 - 1.2.8 13 10208 12.so.0.1.2.8 - 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 - 1.2.9beta4-11 13 10209 12.so.0.9[.0] - 1.2.9rc1 13 10209 12.so.0.9[.0] - 1.2.9 13 10209 12.so.0.9[.0] - 1.2.10beta1-8 13 10210 12.so.0.10[.0] - 1.2.10rc1-3 13 10210 12.so.0.10[.0] - 1.2.10 13 10210 12.so.0.10[.0] - 1.2.11beta1-4 13 10211 12.so.0.11[.0] - 1.0.19rc1-5 10 10019 10.so.0.19[.0] - 1.2.11rc1-5 13 10211 12.so.0.11[.0] - 1.0.19 10 10019 10.so.0.19[.0] - 1.2.11 13 10211 12.so.0.11[.0] - 1.0.20 10 10020 10.so.0.20[.0] - 1.2.12 13 10212 12.so.0.12[.0] - 1.2.13beta1 13 10213 12.so.0.13[.0] - 1.0.21 10 10021 10.so.0.21[.0] - 1.2.13 13 10213 12.so.0.13[.0] - 1.2.14beta1-2 13 10214 12.so.0.14[.0] - 1.0.22rc1 10 10022 10.so.0.22[.0] - 1.2.14rc1 13 10214 12.so.0.14[.0] - 1.2.15beta1-6 13 10215 12.so.0.15[.0] - 1.0.23rc1-5 10 10023 10.so.0.23[.0] - 1.2.15rc1-5 13 10215 12.so.0.15[.0] - 1.0.23 10 10023 10.so.0.23[.0] - 1.2.15 13 10215 12.so.0.15[.0] - 1.2.16beta1-2 13 10216 12.so.0.16[.0] - 1.2.16rc1 13 10216 12.so.0.16[.0] - 1.0.24 10 10024 10.so.0.24[.0] - 1.2.16 13 10216 12.so.0.16[.0] - 1.2.17beta1-2 13 10217 12.so.0.17[.0] - 1.0.25rc1 10 10025 10.so.0.25[.0] - 1.2.17rc1-3 13 10217 12.so.0.17[.0] - 1.0.25 10 10025 10.so.0.25[.0] - 1.2.17 13 10217 12.so.0.17[.0] - 1.0.26 10 10026 10.so.0.26[.0] - 1.2.18 13 10218 12.so.0.18[.0] - 1.2.19beta1-31 13 10219 12.so.0.19[.0] - 1.0.27rc1-6 10 10027 10.so.0.27[.0] - 1.2.19rc1-6 13 10219 12.so.0.19[.0] - 1.0.27 10 10027 10.so.0.27[.0] - 1.2.19 13 10219 12.so.0.19[.0] - 1.2.20beta01-04 13 10220 12.so.0.20[.0] - 1.0.28rc1-6 10 10028 10.so.0.28[.0] - 1.2.20rc1-6 13 10220 12.so.0.20[.0] - 1.0.28 10 10028 10.so.0.28[.0] - 1.2.20 13 10220 12.so.0.20[.0] - 1.2.21beta1-2 13 10221 12.so.0.21[.0] - 1.2.21rc1-3 13 10221 12.so.0.21[.0] - 1.0.29 10 10029 10.so.0.29[.0] - 1.2.21 13 10221 12.so.0.21[.0] - 1.2.22beta1-4 13 10222 12.so.0.22[.0] - 1.0.30rc1 13 10030 10.so.0.30[.0] - 1.2.22rc1 13 10222 12.so.0.22[.0] - 1.0.30 10 10030 10.so.0.30[.0] - 1.2.22 13 10222 12.so.0.22[.0] - 1.2.23beta01-05 13 10223 12.so.0.23[.0] - 1.2.23rc01 13 10223 12.so.0.23[.0] - 1.2.23 13 10223 12.so.0.23[.0] - 1.2.24beta01-02 13 10224 12.so.0.24[.0] - 1.2.24rc01 13 10224 12.so.0.24[.0] - 1.2.24 13 10224 12.so.0.24[.0] - 1.2.25beta01-06 13 10225 12.so.0.25[.0] - 1.2.25rc01-02 13 10225 12.so.0.25[.0] - 1.0.31 10 10031 10.so.0.31[.0] - 1.2.25 13 10225 12.so.0.25[.0] - 1.2.26beta01-06 13 10226 12.so.0.26[.0] - 1.2.26rc01 13 10226 12.so.0.26[.0] - 1.2.26 13 10226 12.so.0.26[.0] - 1.0.32 10 10032 10.so.0.32[.0] - 1.2.27beta01-06 13 10227 12.so.0.27[.0] - 1.2.27rc01 13 10227 12.so.0.27[.0] - 1.0.33 10 10033 10.so.0.33[.0] - 1.2.27 13 10227 12.so.0.27[.0] - 1.0.34 10 10034 10.so.0.34[.0] - 1.2.28 13 10228 12.so.0.28[.0] - 1.2.29beta01-03 13 10229 12.so.0.29[.0] - 1.2.29rc01 13 10229 12.so.0.29[.0] - 1.0.35 10 10035 10.so.0.35[.0] - 1.2.29 13 10229 12.so.0.29[.0] - 1.0.37 10 10037 10.so.0.37[.0] - 1.2.30beta01-04 13 10230 12.so.0.30[.0] - 1.0.38rc01-08 10 10038 10.so.0.38[.0] - 1.2.30rc01-08 13 10230 12.so.0.30[.0] - 1.0.38 10 10038 10.so.0.38[.0] - 1.2.30 13 10230 12.so.0.30[.0] - 1.0.39rc01-03 10 10039 10.so.0.39[.0] - 1.2.31rc01-03 13 10231 12.so.0.31[.0] - 1.0.39 10 10039 10.so.0.39[.0] - 1.2.31 13 10231 12.so.0.31[.0] - 1.2.32beta01-02 13 10232 12.so.0.32[.0] - 1.0.40rc01 10 10040 10.so.0.40[.0] - 1.2.32rc01 13 10232 12.so.0.32[.0] - 1.0.40 10 10040 10.so.0.40[.0] - 1.2.32 13 10232 12.so.0.32[.0] - 1.2.33beta01-02 13 10233 12.so.0.33[.0] - 1.2.33rc01-02 13 10233 12.so.0.33[.0] - 1.0.41rc01 10 10041 10.so.0.41[.0] - 1.2.33 13 10233 12.so.0.33[.0] - 1.0.41 10 10041 10.so.0.41[.0] - 1.2.34beta01-07 13 10234 12.so.0.34[.0] - 1.0.42rc01 10 10042 10.so.0.42[.0] - 1.2.34rc01 13 10234 12.so.0.34[.0] - 1.0.42 10 10042 10.so.0.42[.0] - 1.2.34 13 10234 12.so.0.34[.0] - 1.2.35beta01-03 13 10235 12.so.0.35[.0] - 1.0.43rc01-02 10 10043 10.so.0.43[.0] - 1.2.35rc01-02 13 10235 12.so.0.35[.0] - 1.0.43 10 10043 10.so.0.43[.0] - 1.2.35 13 10235 12.so.0.35[.0] - 1.2.36beta01-05 13 10236 12.so.0.36[.0] - 1.2.36rc01 13 10236 12.so.0.36[.0] - 1.0.44 10 10044 10.so.0.44[.0] - 1.2.36 13 10236 12.so.0.36[.0] - 1.2.37beta01-03 13 10237 12.so.0.37[.0] - 1.2.37rc01 13 10237 12.so.0.37[.0] - 1.2.37 13 10237 12.so.0.37[.0] - 1.2.45 10 10045 12.so.0.45[.0] - 1.0.46 10 10046 10.so.0.46[.0] - 1.2.38beta01 13 10238 12.so.0.38[.0] - 1.2.38rc01-03 13 10238 12.so.0.38[.0] - 1.0.47 10 10047 10.so.0.47[.0] - 1.2.38 13 10238 12.so.0.38[.0] - 1.2.39beta01-05 13 10239 12.so.0.39[.0] - 1.2.39rc01 13 10239 12.so.0.39[.0] - 1.0.48 10 10048 10.so.0.48[.0] - 1.2.39 13 10239 12.so.0.39[.0] - 1.2.40rc01 13 10240 12.so.0.40[.0] - 1.0.49 10 10049 10.so.0.49[.0] - 1.2.40 13 10240 12.so.0.40[.0] - -Henceforth the source version will match the shared-library minor -and patch numbers; the shared-library major version number will be -used for changes in backward compatibility, as it is intended. The -PNG_PNGLIB_VER macro, which is not used within libpng but is available -for applications, is an unsigned integer of the form xyyzz corresponding -to the source version x.y.z (leading zeros in y and z). Beta versions -were given the previous public release number plus a letter, until -version 1.0.6j; from then on they were given the upcoming public -release number plus "betaNN" or "rcN". - -.SH "SEE ALSO" -.IR libpngpf(3) ", " png(5) -.LP -.IR libpng : -.IP -http://libpng.sourceforge.net (follow the [DOWNLOAD] link) -http://www.libpng.org/pub/png - -.LP -.IR zlib : -.IP -(generally) at the same location as -.I libpng -or at -.br -ftp://ftp.info-zip.org/pub/infozip/zlib - -.LP -.IR PNG specification: RFC 2083 -.IP -(generally) at the same location as -.I libpng -or at -.br -ftp://ftp.rfc-editor.org:/in-notes/rfc2083.txt -.br -or (as a W3C Recommendation) at -.br -http://www.w3.org/TR/REC-png.html - -.LP -In the case of any inconsistency between the PNG specification -and this library, the specification takes precedence. - -.SH AUTHORS -This man page: Glenn Randers-Pehrson - - -The contributing authors would like to thank all those who helped -with testing, bug fixes, and patience. This wouldn't have been -possible without all of you. - -Thanks to Frank J. T. Wojcik for helping with the documentation. - -Libpng version 1.2.40 - September 10, 2009: -Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc. -Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net). - -Supported by the PNG development group -.br -png-mng-implement at lists.sf.net -(subscription required; visit -png-mng-implement at lists.sourceforge.net (subscription required; visit -https://lists.sourceforge.net/lists/listinfo/png-mng-implement -to subscribe). - -.SH COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -(This copy of the libpng notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file png.h that is -included in the libpng distribution, the latter shall prevail.) - -If you modify libpng you may insert additional notices immediately following -this sentence. - -This code is released under the libpng license. - -libpng versions 1.2.6, August 15, 2004, through 1.2.40, September 10, 2009, are -Copyright (c) 2004,2006-2008 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.2.5 -with the following individual added to the list of Contributing Authors - - Cosmin Truta - -libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are -Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are -distributed according to the same disclaimer and license as libpng-1.0.6 -with the following individuals added to the list of Contributing Authors - - Simon-Pierre Cadieux - Eric S. Raymond - Gilles Vollant - -and with the following additions to the disclaimer: - - There is no warranty against interference with your - enjoyment of the library or against infringement. - There is no warranty that our efforts or the library - will fulfill any of your particular purposes or needs. - This library is provided with all faults, and the entire - risk of satisfactory quality, performance, accuracy, and - effort is with the user. - -libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are -Copyright (c) 1998, 1999 Glenn Randers-Pehrson -Distributed according to the same disclaimer and license as libpng-0.96, -with the following individuals added to the list of Contributing Authors: - - Tom Lane - Glenn Randers-Pehrson - Willem van Schaik - -libpng versions 0.89, June 1996, through 0.96, May 1997, are -Copyright (c) 1996, 1997 Andreas Dilger -Distributed according to the same disclaimer and license as libpng-0.88, -with the following individuals added to the list of Contributing Authors: - - John Bowler - Kevin Bracey - Sam Bushell - Magnus Holmgren - Greg Roelofs - Tom Tanner - -libpng versions 0.5, May 1995, through 0.88, January 1996, are -Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. - -For the purposes of this copyright and license, "Contributing Authors" -is defined as the following set of individuals: - - Andreas Dilger - Dave Martindale - Guy Eric Schalnat - Paul Schmidt - Tim Wegner - -The PNG Reference Library is supplied "AS IS". The Contributing Authors -and Group 42, Inc. disclaim all warranties, expressed or implied, -including, without limitation, the warranties of merchantability and of -fitness for any purpose. The Contributing Authors and Group 42, Inc. -assume no liability for direct, indirect, incidental, special, exemplary, -or consequential damages, which may result from the use of the PNG -Reference Library, even if advised of the possibility of such damage. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, without fee, subject -to the following restrictions: - -1. The origin of this source code must not be misrepresented. - -2. Altered versions must be plainly marked as such and - must not be misrepresented as being the original source. - -3. This Copyright notice may not be removed or altered from - any source or altered source distribution. - -The Contributing Authors and Group 42, Inc. specifically permit, without -fee, and encourage the use of this source code as a component to -supporting the PNG file format in commercial products. If you use this -source code in a product, acknowledgment is not required but would be -appreciated. - - -A "png_get_copyright" function is available, for convenient use in "about" -boxes and the like: - - printf("%s",png_get_copyright(NULL)); - -Also, the PNG logo (in PNG format, of course) is supplied in the -files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - -Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a -certification mark of the Open Source Initiative. - -Glenn Randers-Pehrson -glennrp at users.sourceforge.net -September 10, 2009 - -.\" end of man page - diff --git a/src/3rdparty/libpng/libpngpf.3 b/src/3rdparty/libpng/libpngpf.3 deleted file mode 100644 index a1e030d..0000000 --- a/src/3rdparty/libpng/libpngpf.3 +++ /dev/null @@ -1,790 +0,0 @@ -.TH LIBPNGPF 3 "September 10, 2009" -.SH NAME -libpng \- Portable Network Graphics (PNG) Reference Library 1.2.40 -(private functions) -.SH SYNOPSIS -\fB#include \fP - -\fI\fB - -\fI\fB - -\fBvoid png_build_gamma_table (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_build_grayscale_palette (int \fP\fIbit_depth\fP\fB, png_colorp \fIpalette\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_calculate_crc (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIptr\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_check_chunk_name (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBpng_size_t png_check_keyword (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charpp \fInew_key\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fImask\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_correct_palette (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBint png_crc_error (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBint png_crc_finish (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIskip\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_crc_read (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuf\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBpng_voidp png_create_struct (int \fItype\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBpng_voidp png_create_struct_2 (int \fP\fItype\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_decompress_chunk (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcomp_type\fP\fB, png_charp \fP\fIchunkdata\fP\fB, png_size_t \fP\fIchunklength\fP\fB, png_size_t \fP\fIprefix_length\fP\fB, png_size_t \fI*data_length\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_destroy_struct (png_voidp \fIstruct_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_destroy_struct_2 (png_voidp \fP\fIstruct_ptr\fP\fB, png_free_ptr \fP\fIfree_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_background (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fP\fItrans_values\fP\fB, png_color_16p \fP\fIbackground\fP\fB, png_color_16p \fP\fIbackground_1\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_bytep \fP\fIgamma_from_1\fP\fB, png_bytep \fP\fIgamma_to_1\fP\fB, png_uint_16pp \fP\fIgamma_16\fP\fB, png_uint_16pp \fP\fIgamma_16_from_1\fP\fB, png_uint_16pp \fP\fIgamma_16_to_1\fP\fB, int \fIgamma_shift\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_bgr (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_chop (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_dither (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIpalette_lookup\fP\fB, png_bytep \fIdither_lookup\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_expand (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fItrans_value\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_expand_palette (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fInum_trans\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_gamma (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_uint_16pp \fP\fIgamma_16_table\fP\fB, int \fIgamma_shift\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_gray_to_rgb (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_invert (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_pack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIbit_depth\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_packswap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_read_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, png_uint_32 \fIflags\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_read_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fP\fIpass\fP\fB, png_uint_32 \fItransformations\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_read_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_read_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBint png_do_rgb_to_gray (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_shift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIbit_depth\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_strip_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIflags\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_swap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_unpack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_unshift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIsig_bits\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_write_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fIpass\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_write_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_write_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_do_write_transformations (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid *png_far_to_near (png_structp png_ptr,png_voidp \fP\fIptr\fP\fB, int \fIcheck\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_flush (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_IEND (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_iTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_info_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_init_mmx_flags (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_init_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_process_IDAT_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_process_some_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_check_crc (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_crc_finish (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_crc_skip (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_fill_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_have_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_have_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_have_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_process_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_read_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_read_IDAT (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_read_sig (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_read_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_read_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_restore_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_push_save_buffer (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBpng_uint_32 png_read_chunk_header (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_read_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_read_filter_row (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIprev_row\fP\fB, int \fIfilter\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_read_finish_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_read_push_finish_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_read_start_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_read_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_reset_crc (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBint png_set_text_2 (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_cHRM (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_filtered_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIfiltered_row\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_find_filter (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fIrow_info\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_finish_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_gAMA (png_structp \fP\fIpng_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIint_file_gamma\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_uint_16p \fP\fIhist\fP\fB, int \fInum_hist\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, int \fIproflen\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_IDAT (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_IEND (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fP\fIfilter_type\fP\fB, int \fIinterlace_type\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_iTXt (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcompression\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fIlang\fP\fB, png_charp \fP\fItranslated_key\fP\fB, png_charp \fItext\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_offset\fP\fB, png_uint_32 \fP\fIy_offset\fP\fB, int \fIunit_type\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_pixels_per_unit\fP\fB, png_uint_32 \fP\fIy_pixels_per_unit\fP\fB, int \fIunit_type\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_uint_32 \fInum_pal\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fP\fIsbit\fP\fB, int \fIcolor_type\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_sCAL_s (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, png_charp \fP\fIwidth\fP\fB, png_charp \fIheight\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_sig (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_sRGB (png_structp \fP\fIpng_ptr\fP\fB, int \fIintent\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_spalette_p \fIpalette\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_start_row (png_structp \fIpng_ptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fItext_len\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, png_color_16p \fP\fIvalues\fP\fB, int \fP\fInumber\fP\fB, int \fIcolor_type\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_write_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fP\fItext_len\fP\fB, int \fIcompression\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP - -\fI\fB - -\fI\fB - -\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP - -\fI\fB - -\fI\fB - -.SH DESCRIPTION -The functions listed above are used privately by libpng -and are not recommended for use by applications. They are -not "exported" to applications using shared libraries. They -are listed alphabetically here as an aid to libpng maintainers. -See png.h for more information on these functions. - -.SH SEE ALSO -.IR libpng(3) ", " png(5) -.SH AUTHOR -Glenn Randers-Pehrson diff --git a/src/3rdparty/libpng/png.5 b/src/3rdparty/libpng/png.5 deleted file mode 100644 index 30923ba..0000000 --- a/src/3rdparty/libpng/png.5 +++ /dev/null @@ -1,74 +0,0 @@ -.TH PNG 5 "September 10, 2009" -.SH NAME -png \- Portable Network Graphics (PNG) format -.SH DESCRIPTION -PNG (Portable Network Graphics) is an extensible file format for the -lossless, portable, well-compressed storage of raster images. PNG provides -a patent-free replacement for GIF and can also replace many -common uses of TIFF. Indexed-color, grayscale, and truecolor images are -supported, plus an optional alpha channel. Sample depths range from -1 to 16 bits. -.br - -PNG is designed to work well in online viewing applications, such as the -World Wide Web, so it is fully streamable with a progressive display -option. PNG is robust, providing both full file integrity checking and -fast, simple detection of common transmission errors. Also, PNG can store -gamma and chromaticity data for improved color matching on heterogeneous -platforms. - -.SH "SEE ALSO" -.IR libpng(3) ", " zlib(3) ", " deflate(5) ", and " zlib(5) -.LP -PNG specification (second edition), November 2003: -.IP -.br - 8) - png_error(png_ptr, "Too many bytes for PNG signature."); - - png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); -} - -/* Checks whether the supplied bytes match the PNG signature. We allow - * checking less than the full 8-byte signature so that those apps that - * already read the first few bytes of a file to determine the file type - * can simply check the remaining bytes for extra assurance. Returns - * an integer less than, equal to, or greater than zero if sig is found, - * respectively, to be less than, to match, or be greater than the correct - * PNG signature (this is the same behaviour as strcmp, memcmp, etc). - */ -int PNGAPI -png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) -{ - png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - if (num_to_check > 8) - num_to_check = 8; - else if (num_to_check < 1) - return (-1); - - if (start > 7) - return (-1); - - if (start + num_to_check > 8) - num_to_check = 8 - start; - - return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); -} - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* (Obsolete) function to check signature bytes. It does not allow one - * to check a partial signature. This function might be removed in the - * future - use png_sig_cmp(). Returns true (nonzero) if the file is PNG. - */ -int PNGAPI -png_check_sig(png_bytep sig, int num) -{ - return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num)); -} -#endif -#endif /* PNG_READ_SUPPORTED */ - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -/* Function to allocate memory for zlib and clear it to 0. */ -#ifdef PNG_1_0_X -voidpf PNGAPI -#else -voidpf /* PRIVATE */ -#endif -png_zalloc(voidpf png_ptr, uInt items, uInt size) -{ - png_voidp ptr; - png_structp p=(png_structp)png_ptr; - png_uint_32 save_flags=p->flags; - png_uint_32 num_bytes; - - if (png_ptr == NULL) - return (NULL); - if (items > PNG_UINT_32_MAX/size) - { - png_warning (p, "Potential overflow in png_zalloc()"); - return (NULL); - } - num_bytes = (png_uint_32)items * size; - - p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); - p->flags=save_flags; - -#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO) - if (ptr == NULL) - return ((voidpf)ptr); - - if (num_bytes > (png_uint_32)0x8000L) - { - png_memset(ptr, 0, (png_size_t)0x8000L); - png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0, - (png_size_t)(num_bytes - (png_uint_32)0x8000L)); - } - else - { - png_memset(ptr, 0, (png_size_t)num_bytes); - } -#endif - return ((voidpf)ptr); -} - -/* Function to free memory for zlib */ -#ifdef PNG_1_0_X -void PNGAPI -#else -void /* PRIVATE */ -#endif -png_zfree(voidpf png_ptr, voidpf ptr) -{ - png_free((png_structp)png_ptr, (png_voidp)ptr); -} - -/* Reset the CRC variable to 32 bits of 1's. Care must be taken - * in case CRC is > 32 bits to leave the top bits 0. - */ -void /* PRIVATE */ -png_reset_crc(png_structp png_ptr) -{ - png_ptr->crc = crc32(0, Z_NULL, 0); -} - -/* Calculate the CRC over a section of data. We can only pass as - * much data to this routine as the largest single buffer size. We - * also check that this data will actually be used before going to the - * trouble of calculating it. - */ -void /* PRIVATE */ -png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) -{ - int need_crc = 1; - - if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - - if (need_crc) - png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); -} - -/* Allocate the memory for an info_struct for the application. We don't - * really need the png_ptr, but it could potentially be useful in the - * future. This should be used in favour of malloc(png_sizeof(png_info)) - * and png_info_init() so that applications that want to use a shared - * libpng don't have to be recompiled if png_info changes size. - */ -png_infop PNGAPI -png_create_info_struct(png_structp png_ptr) -{ - png_infop info_ptr; - - png_debug(1, "in png_create_info_struct"); - if (png_ptr == NULL) - return (NULL); -#ifdef PNG_USER_MEM_SUPPORTED - info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, - png_ptr->malloc_fn, png_ptr->mem_ptr); -#else - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); -#endif - if (info_ptr != NULL) - png_info_init_3(&info_ptr, png_sizeof(png_info)); - - return (info_ptr); -} - -/* This function frees the memory associated with a single info struct. - * Normally, one would use either png_destroy_read_struct() or - * png_destroy_write_struct() to free an info struct, but this may be - * useful for some applications. - */ -void PNGAPI -png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) -{ - png_infop info_ptr = NULL; - if (png_ptr == NULL) - return; - - png_debug(1, "in png_destroy_info_struct"); - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - png_info_destroy(png_ptr, info_ptr); - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, - png_ptr->mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } -} - -/* Initialize the info structure. This is now an internal function (0.89) - * and applications using it are urged to use png_create_info_struct() - * instead. - */ -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -#undef png_info_init -void PNGAPI -png_info_init(png_infop info_ptr) -{ - /* We only come here via pre-1.0.12-compiled applications */ - png_info_init_3(&info_ptr, 0); -} -#endif - -void PNGAPI -png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) -{ - png_infop info_ptr = *ptr_ptr; - - if (info_ptr == NULL) - return; - - png_debug(1, "in png_info_init_3"); - - if (png_sizeof(png_info) > png_info_struct_size) - { - png_destroy_struct(info_ptr); - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); - *ptr_ptr = info_ptr; - } - - /* Set everything to 0 */ - png_memset(info_ptr, 0, png_sizeof(png_info)); -} - -#ifdef PNG_FREE_ME_SUPPORTED -void PNGAPI -png_data_freer(png_structp png_ptr, png_infop info_ptr, - int freer, png_uint_32 mask) -{ - png_debug(1, "in png_data_freer"); - if (png_ptr == NULL || info_ptr == NULL) - return; - if (freer == PNG_DESTROY_WILL_FREE_DATA) - info_ptr->free_me |= mask; - else if (freer == PNG_USER_WILL_FREE_DATA) - info_ptr->free_me &= ~mask; - else - png_warning(png_ptr, - "Unknown freer parameter in png_data_freer."); -} -#endif - -void PNGAPI -png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, - int num) -{ - png_debug(1, "in png_free_data"); - if (png_ptr == NULL || info_ptr == NULL) - return; - -#if defined(PNG_TEXT_SUPPORTED) - /* Free text item num or (if num == -1) all text items */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) -#else - if (mask & PNG_FREE_TEXT) -#endif - { - if (num != -1) - { - if (info_ptr->text && info_ptr->text[num].key) - { - png_free(png_ptr, info_ptr->text[num].key); - info_ptr->text[num].key = NULL; - } - } - else - { - int i; - for (i = 0; i < info_ptr->num_text; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); - png_free(png_ptr, info_ptr->text); - info_ptr->text = NULL; - info_ptr->num_text=0; - } - } -#endif - -#if defined(PNG_tRNS_SUPPORTED) - /* Free any tRNS entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) -#else - if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS)) -#endif - { - png_free(png_ptr, info_ptr->trans); - info_ptr->trans = NULL; - info_ptr->valid &= ~PNG_INFO_tRNS; -#ifndef PNG_FREE_ME_SUPPORTED - png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; -#endif - } -#endif - -#if defined(PNG_sCAL_SUPPORTED) - /* Free any sCAL entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) -#else - if (mask & PNG_FREE_SCAL) -#endif - { -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, info_ptr->scal_s_width); - png_free(png_ptr, info_ptr->scal_s_height); - info_ptr->scal_s_width = NULL; - info_ptr->scal_s_height = NULL; -#endif - info_ptr->valid &= ~PNG_INFO_sCAL; - } -#endif - -#if defined(PNG_pCAL_SUPPORTED) - /* Free any pCAL entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) -#else - if (mask & PNG_FREE_PCAL) -#endif - { - png_free(png_ptr, info_ptr->pcal_purpose); - png_free(png_ptr, info_ptr->pcal_units); - info_ptr->pcal_purpose = NULL; - info_ptr->pcal_units = NULL; - if (info_ptr->pcal_params != NULL) - { - int i; - for (i = 0; i < (int)info_ptr->pcal_nparams; i++) - { - png_free(png_ptr, info_ptr->pcal_params[i]); - info_ptr->pcal_params[i]=NULL; - } - png_free(png_ptr, info_ptr->pcal_params); - info_ptr->pcal_params = NULL; - } - info_ptr->valid &= ~PNG_INFO_pCAL; - } -#endif - -#if defined(PNG_iCCP_SUPPORTED) - /* Free any iCCP entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) -#else - if (mask & PNG_FREE_ICCP) -#endif - { - png_free(png_ptr, info_ptr->iccp_name); - png_free(png_ptr, info_ptr->iccp_profile); - info_ptr->iccp_name = NULL; - info_ptr->iccp_profile = NULL; - info_ptr->valid &= ~PNG_INFO_iCCP; - } -#endif - -#if defined(PNG_sPLT_SUPPORTED) - /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) -#else - if (mask & PNG_FREE_SPLT) -#endif - { - if (num != -1) - { - if (info_ptr->splt_palettes) - { - png_free(png_ptr, info_ptr->splt_palettes[num].name); - png_free(png_ptr, info_ptr->splt_palettes[num].entries); - info_ptr->splt_palettes[num].name = NULL; - info_ptr->splt_palettes[num].entries = NULL; - } - } - else - { - if (info_ptr->splt_palettes_num) - { - int i; - for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); - - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; - } - info_ptr->valid &= ~PNG_INFO_sPLT; - } - } -#endif - -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - if (png_ptr->unknown_chunk.data) - { - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) -#else - if (mask & PNG_FREE_UNKN) -#endif - { - if (num != -1) - { - if (info_ptr->unknown_chunks) - { - png_free(png_ptr, info_ptr->unknown_chunks[num].data); - info_ptr->unknown_chunks[num].data = NULL; - } - } - else - { - int i; - - if (info_ptr->unknown_chunks_num) - { - for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); - - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; - } - } - } -#endif - -#if defined(PNG_hIST_SUPPORTED) - /* Free any hIST entry */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_HIST) & info_ptr->free_me) -#else - if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST)) -#endif - { - png_free(png_ptr, info_ptr->hist); - info_ptr->hist = NULL; - info_ptr->valid &= ~PNG_INFO_hIST; -#ifndef PNG_FREE_ME_SUPPORTED - png_ptr->flags &= ~PNG_FLAG_FREE_HIST; -#endif - } -#endif - - /* Free any PLTE entry that was internally allocated */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) -#else - if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE)) -#endif - { - png_zfree(png_ptr, info_ptr->palette); - info_ptr->palette = NULL; - info_ptr->valid &= ~PNG_INFO_PLTE; -#ifndef PNG_FREE_ME_SUPPORTED - png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; -#endif - info_ptr->num_palette = 0; - } - -#if defined(PNG_INFO_IMAGE_SUPPORTED) - /* Free any image bits attached to the info structure */ -#ifdef PNG_FREE_ME_SUPPORTED - if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) -#else - if (mask & PNG_FREE_ROWS) -#endif - { - if (info_ptr->row_pointers) - { - int row; - for (row = 0; row < (int)info_ptr->height; row++) - { - png_free(png_ptr, info_ptr->row_pointers[row]); - info_ptr->row_pointers[row]=NULL; - } - png_free(png_ptr, info_ptr->row_pointers); - info_ptr->row_pointers=NULL; - } - info_ptr->valid &= ~PNG_INFO_IDAT; - } -#endif - -#ifdef PNG_FREE_ME_SUPPORTED - if (num == -1) - info_ptr->free_me &= ~mask; - else - info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); -#endif -} - -/* This is an internal routine to free any memory that the info struct is - * pointing to before re-using it or freeing the struct itself. Recall - * that png_free() checks for NULL pointers for us. - */ -void /* PRIVATE */ -png_info_destroy(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_info_destroy"); - - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#if defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list=NULL; - png_ptr->num_chunk_list = 0; - } -#endif - - png_info_init_3(&info_ptr, png_sizeof(png_info)); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -/* This function returns a pointer to the io_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy() or png_read_destroy() are called. - */ -png_voidp PNGAPI -png_get_io_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - return (png_ptr->io_ptr); -} - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#if !defined(PNG_NO_STDIO) -/* Initialize the default input/output functions for the PNG file. If you - * use your own read or write routines, you can call either png_set_read_fn() - * or png_set_write_fn() instead of png_init_io(). If you have defined - * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't - * necessarily available. - */ -void PNGAPI -png_init_io(png_structp png_ptr, png_FILE_p fp) -{ - png_debug(1, "in png_init_io"); - if (png_ptr == NULL) - return; - png_ptr->io_ptr = (png_voidp)fp; -} -#endif - -#if defined(PNG_TIME_RFC1123_SUPPORTED) -/* Convert the supplied time into an RFC 1123 string suitable for use in - * a "Creation Time" or other text-based time string. - */ -png_charp PNGAPI -png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) -{ - static PNG_CONST char short_months[12][4] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - - if (png_ptr == NULL) - return (NULL); - if (png_ptr->time_buffer == NULL) - { - png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* - png_sizeof(char))); - } - -#if defined(_WIN32_WCE) - { - wchar_t time_buf[29]; - wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"), - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); - WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29, - NULL, NULL); - } -#else -#ifdef USE_FAR_KEYWORD - { - char near_time_buf[29]; - png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000", - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); - png_memcpy(png_ptr->time_buffer, near_time_buf, - 29*png_sizeof(char)); - } -#else - png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000", - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); -#endif -#endif /* _WIN32_WCE */ - return ((png_charp)png_ptr->time_buffer); -} -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -png_charp PNGAPI -png_get_copyright(png_structp png_ptr) -{ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) "\n libpng version 1.2.40 - September 10, 2009\n\ - Copyright (c) 1998-2009 Glenn Randers-Pehrson\n\ - Copyright (c) 1996-1997 Andreas Dilger\n\ - Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n"); -} - -/* The following return the library version as a short string in the - * format 1.0.0 through 99.99.99zz. To get the version of *.h files - * used with your application, print out PNG_LIBPNG_VER_STRING, which - * is defined in png.h. - * Note: now there is no difference between png_get_libpng_ver() and - * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, - * it is guaranteed that png.c uses the correct version of png.h. - */ -png_charp PNGAPI -png_get_libpng_ver(png_structp png_ptr) -{ - /* Version of *.c files used when building libpng */ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_LIBPNG_VER_STRING); -} - -png_charp PNGAPI -png_get_header_ver(png_structp png_ptr) -{ - /* Version of *.h files used when building libpng */ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_LIBPNG_VER_STRING); -} - -png_charp PNGAPI -png_get_header_version(png_structp png_ptr) -{ - /* Returns longer string containing both version and date */ - png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) PNG_HEADER_VERSION_STRING -#ifndef PNG_READ_SUPPORTED - " (NO READ SUPPORT)" -#endif - "\n"); -} - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -int PNGAPI -png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) -{ - /* Check chunk_name and return "keep" value if it's on the list, else 0 */ - int i; - png_bytep p; - if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0) - return 0; - p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5; - for (i = png_ptr->num_chunk_list; i; i--, p -= 5) - if (!png_memcmp(chunk_name, p, 4)) - return ((int)*(p + 4)); - return 0; -} -#endif - -/* This function, added to libpng-1.0.6g, is untested. */ -int PNGAPI -png_reset_zstream(png_structp png_ptr) -{ - if (png_ptr == NULL) - return Z_STREAM_ERROR; - return (inflateReset(&png_ptr->zstream)); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ - -/* This function was added to libpng-1.0.7 */ -png_uint_32 PNGAPI -png_access_version_number(void) -{ - /* Version of *.c files used when building libpng */ - return((png_uint_32) PNG_LIBPNG_VER); -} - - -#if defined(PNG_READ_SUPPORTED) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) -#if !defined(PNG_1_0_X) -/* This function was added to libpng 1.2.0 */ -int PNGAPI -png_mmx_support(void) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return -1; -} -#endif /* PNG_1_0_X */ -#endif /* PNG_READ_SUPPORTED && PNG_ASSEMBLER_CODE_SUPPORTED */ - -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -#ifdef PNG_SIZE_T -/* Added at libpng version 1.2.6 */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); -png_size_t PNGAPI -png_convert_size(size_t size) -{ - if (size > (png_size_t)-1) - PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */ - return ((png_size_t)size); -} -#endif /* PNG_SIZE_T */ - -/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ -#if defined(PNG_cHRM_SUPPORTED) -#if !defined(PNG_NO_CHECK_cHRM) - -/* - * Multiply two 32-bit numbers, V1 and V2, using 32-bit - * arithmetic, to produce a 64 bit result in the HI/LO words. - * - * A B - * x C D - * ------ - * AD || BD - * AC || CB || 0 - * - * where A and B are the high and low 16-bit words of V1, - * C and D are the 16-bit words of V2, AD is the product of - * A and D, and X || Y is (X << 16) + Y. -*/ - -void /* PRIVATE */ -png_64bit_product (long v1, long v2, unsigned long *hi_product, - unsigned long *lo_product) -{ - int a, b, c, d; - long lo, hi, x, y; - - a = (v1 >> 16) & 0xffff; - b = v1 & 0xffff; - c = (v2 >> 16) & 0xffff; - d = v2 & 0xffff; - - lo = b * d; /* BD */ - x = a * d + c * b; /* AD + CB */ - y = ((lo >> 16) & 0xffff) + x; - - lo = (lo & 0xffff) | ((y & 0xffff) << 16); - hi = (y >> 16) & 0xffff; - - hi += a * c; /* AC */ - - *hi_product = (unsigned long)hi; - *lo_product = (unsigned long)lo; -} - -int /* PRIVATE */ -png_check_cHRM_fixed(png_structp png_ptr, - png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, - png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, - png_fixed_point blue_x, png_fixed_point blue_y) -{ - int ret = 1; - unsigned long xy_hi,xy_lo,yx_hi,yx_lo; - - png_debug(1, "in function png_check_cHRM_fixed"); - if (png_ptr == NULL) - return 0; - - if (white_x < 0 || white_y <= 0 || - red_x < 0 || red_y < 0 || - green_x < 0 || green_y < 0 || - blue_x < 0 || blue_y < 0) - { - png_warning(png_ptr, - "Ignoring attempt to set negative chromaticity value"); - ret = 0; - } - if (white_x > (png_fixed_point) PNG_UINT_31_MAX || - white_y > (png_fixed_point) PNG_UINT_31_MAX || - red_x > (png_fixed_point) PNG_UINT_31_MAX || - red_y > (png_fixed_point) PNG_UINT_31_MAX || - green_x > (png_fixed_point) PNG_UINT_31_MAX || - green_y > (png_fixed_point) PNG_UINT_31_MAX || - blue_x > (png_fixed_point) PNG_UINT_31_MAX || - blue_y > (png_fixed_point) PNG_UINT_31_MAX ) - { - png_warning(png_ptr, - "Ignoring attempt to set chromaticity value exceeding 21474.83"); - ret = 0; - } - if (white_x > 100000L - white_y) - { - png_warning(png_ptr, "Invalid cHRM white point"); - ret = 0; - } - if (red_x > 100000L - red_y) - { - png_warning(png_ptr, "Invalid cHRM red point"); - ret = 0; - } - if (green_x > 100000L - green_y) - { - png_warning(png_ptr, "Invalid cHRM green point"); - ret = 0; - } - if (blue_x > 100000L - blue_y) - { - png_warning(png_ptr, "Invalid cHRM blue point"); - ret = 0; - } - - png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo); - png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo); - - if (xy_hi == yx_hi && xy_lo == yx_lo) - { - png_warning(png_ptr, - "Ignoring attempt to set cHRM RGB triangle with zero area"); - ret = 0; - } - - return ret; -} -#endif /* NO_PNG_CHECK_cHRM */ -#endif /* PNG_cHRM_SUPPORTED */ -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h deleted file mode 100644 index d95339d..0000000 --- a/src/3rdparty/libpng/png.h +++ /dev/null @@ -1,3726 +0,0 @@ -/* png.h - header file for PNG reference library - * - * libpng version 1.2.40 - September 10, 2009 - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license (See LICENSE, below) - * - * Authors and maintainers: - * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat - * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.2.40 - September 10, 2009: Glenn - * See also "Contributing Authors", below. - * - * Note about libpng version numbers: - * - * Due to various miscommunications, unforeseen code incompatibilities - * and occasional factors outside the authors' control, version numbering - * on the library has not always been consistent and straightforward. - * The following table summarizes matters since version 0.89c, which was - * the first widely used release: - * - * source png.h png.h shared-lib - * version string int version - * ------- ------ ----- ---------- - * 0.89c "1.0 beta 3" 0.89 89 1.0.89 - * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] - * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] - * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] - * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] - * 0.97c 0.97 97 2.0.97 - * 0.98 0.98 98 2.0.98 - * 0.99 0.99 98 2.0.99 - * 0.99a-m 0.99 99 2.0.99 - * 1.00 1.00 100 2.1.0 [100 should be 10000] - * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] - * 1.0.1 png.h string is 10001 2.1.0 - * 1.0.1a-e identical to the 10002 from here on, the shared library - * 1.0.2 source version) 10002 is 2.V where V is the source code - * 1.0.2a-b 10003 version, except as noted. - * 1.0.3 10003 - * 1.0.3a-d 10004 - * 1.0.4 10004 - * 1.0.4a-f 10005 - * 1.0.5 (+ 2 patches) 10005 - * 1.0.5a-d 10006 - * 1.0.5e-r 10100 (not source compatible) - * 1.0.5s-v 10006 (not binary compatible) - * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) - * 1.0.6d-f 10007 (still binary incompatible) - * 1.0.6g 10007 - * 1.0.6h 10007 10.6h (testing xy.z so-numbering) - * 1.0.6i 10007 10.6i - * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) - * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) - * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) - * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) - * 1.0.7 1 10007 (still compatible) - * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 - * 1.0.8rc1 1 10008 2.1.0.8rc1 - * 1.0.8 1 10008 2.1.0.8 - * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 - * 1.0.9rc1 1 10009 2.1.0.9rc1 - * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 - * 1.0.9rc2 1 10009 2.1.0.9rc2 - * 1.0.9 1 10009 2.1.0.9 - * 1.0.10beta1 1 10010 2.1.0.10beta1 - * 1.0.10rc1 1 10010 2.1.0.10rc1 - * 1.0.10 1 10010 2.1.0.10 - * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 - * 1.0.11rc1 1 10011 2.1.0.11rc1 - * 1.0.11 1 10011 2.1.0.11 - * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 - * 1.0.12rc1 2 10012 2.1.0.12rc1 - * 1.0.12 2 10012 2.1.0.12 - * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) - * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 - * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 - * 1.2.0rc1 3 10200 3.1.2.0rc1 - * 1.2.0 3 10200 3.1.2.0 - * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 - * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 - * 1.2.1 3 10201 3.1.2.1 - * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 - * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 - * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 - * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 - * 1.0.13 10 10013 10.so.0.1.0.13 - * 1.2.2 12 10202 12.so.0.1.2.2 - * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 - * 1.2.3 12 10203 12.so.0.1.2.3 - * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 - * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 - * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 - * 1.0.14 10 10014 10.so.0.1.0.14 - * 1.2.4 13 10204 12.so.0.1.2.4 - * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 - * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 - * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 - * 1.0.15 10 10015 10.so.0.1.0.15 - * 1.2.5 13 10205 12.so.0.1.2.5 - * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 - * 1.0.16 10 10016 10.so.0.1.0.16 - * 1.2.6 13 10206 12.so.0.1.2.6 - * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 - * 1.0.17rc1 10 10017 10.so.0.1.0.17rc1 - * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 - * 1.0.17 10 10017 10.so.0.1.0.17 - * 1.2.7 13 10207 12.so.0.1.2.7 - * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 - * 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5 - * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 - * 1.0.18 10 10018 10.so.0.1.0.18 - * 1.2.8 13 10208 12.so.0.1.2.8 - * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 - * 1.2.9beta4-11 13 10209 12.so.0.9[.0] - * 1.2.9rc1 13 10209 12.so.0.9[.0] - * 1.2.9 13 10209 12.so.0.9[.0] - * 1.2.10beta1-8 13 10210 12.so.0.10[.0] - * 1.2.10rc1-3 13 10210 12.so.0.10[.0] - * 1.2.10 13 10210 12.so.0.10[.0] - * 1.2.11beta1-4 13 10211 12.so.0.11[.0] - * 1.0.19rc1-5 10 10019 10.so.0.19[.0] - * 1.2.11rc1-5 13 10211 12.so.0.11[.0] - * 1.0.19 10 10019 10.so.0.19[.0] - * 1.2.11 13 10211 12.so.0.11[.0] - * 1.0.20 10 10020 10.so.0.20[.0] - * 1.2.12 13 10212 12.so.0.12[.0] - * 1.2.13beta1 13 10213 12.so.0.13[.0] - * 1.0.21 10 10021 10.so.0.21[.0] - * 1.2.13 13 10213 12.so.0.13[.0] - * 1.2.14beta1-2 13 10214 12.so.0.14[.0] - * 1.0.22rc1 10 10022 10.so.0.22[.0] - * 1.2.14rc1 13 10214 12.so.0.14[.0] - * 1.0.22 10 10022 10.so.0.22[.0] - * 1.2.14 13 10214 12.so.0.14[.0] - * 1.2.15beta1-6 13 10215 12.so.0.15[.0] - * 1.0.23rc1-5 10 10023 10.so.0.23[.0] - * 1.2.15rc1-5 13 10215 12.so.0.15[.0] - * 1.0.23 10 10023 10.so.0.23[.0] - * 1.2.15 13 10215 12.so.0.15[.0] - * 1.2.16beta1-2 13 10216 12.so.0.16[.0] - * 1.2.16rc1 13 10216 12.so.0.16[.0] - * 1.0.24 10 10024 10.so.0.24[.0] - * 1.2.16 13 10216 12.so.0.16[.0] - * 1.2.17beta1-2 13 10217 12.so.0.17[.0] - * 1.0.25rc1 10 10025 10.so.0.25[.0] - * 1.2.17rc1-3 13 10217 12.so.0.17[.0] - * 1.0.25 10 10025 10.so.0.25[.0] - * 1.2.17 13 10217 12.so.0.17[.0] - * 1.0.26 10 10026 10.so.0.26[.0] - * 1.2.18 13 10218 12.so.0.18[.0] - * 1.2.19beta1-31 13 10219 12.so.0.19[.0] - * 1.0.27rc1-6 10 10027 10.so.0.27[.0] - * 1.2.19rc1-6 13 10219 12.so.0.19[.0] - * 1.0.27 10 10027 10.so.0.27[.0] - * 1.2.19 13 10219 12.so.0.19[.0] - * 1.2.20beta01-04 13 10220 12.so.0.20[.0] - * 1.0.28rc1-6 10 10028 10.so.0.28[.0] - * 1.2.20rc1-6 13 10220 12.so.0.20[.0] - * 1.0.28 10 10028 10.so.0.28[.0] - * 1.2.20 13 10220 12.so.0.20[.0] - * 1.2.21beta1-2 13 10221 12.so.0.21[.0] - * 1.2.21rc1-3 13 10221 12.so.0.21[.0] - * 1.0.29 10 10029 10.so.0.29[.0] - * 1.2.21 13 10221 12.so.0.21[.0] - * 1.2.22beta1-4 13 10222 12.so.0.22[.0] - * 1.0.30rc1 10 10030 10.so.0.30[.0] - * 1.2.22rc1 13 10222 12.so.0.22[.0] - * 1.0.30 10 10030 10.so.0.30[.0] - * 1.2.22 13 10222 12.so.0.22[.0] - * 1.2.23beta01-05 13 10223 12.so.0.23[.0] - * 1.2.23rc01 13 10223 12.so.0.23[.0] - * 1.2.23 13 10223 12.so.0.23[.0] - * 1.2.24beta01-02 13 10224 12.so.0.24[.0] - * 1.2.24rc01 13 10224 12.so.0.24[.0] - * 1.2.24 13 10224 12.so.0.24[.0] - * 1.2.25beta01-06 13 10225 12.so.0.25[.0] - * 1.2.25rc01-02 13 10225 12.so.0.25[.0] - * 1.0.31 10 10031 10.so.0.31[.0] - * 1.2.25 13 10225 12.so.0.25[.0] - * 1.2.26beta01-06 13 10226 12.so.0.26[.0] - * 1.2.26rc01 13 10226 12.so.0.26[.0] - * 1.2.26 13 10226 12.so.0.26[.0] - * 1.0.32 10 10032 10.so.0.32[.0] - * 1.2.27beta01-06 13 10227 12.so.0.27[.0] - * 1.2.27rc01 13 10227 12.so.0.27[.0] - * 1.0.33 10 10033 10.so.0.33[.0] - * 1.2.27 13 10227 12.so.0.27[.0] - * 1.0.34 10 10034 10.so.0.34[.0] - * 1.2.28 13 10228 12.so.0.28[.0] - * 1.2.29beta01-03 13 10229 12.so.0.29[.0] - * 1.2.29rc01 13 10229 12.so.0.29[.0] - * 1.0.35 10 10035 10.so.0.35[.0] - * 1.2.29 13 10229 12.so.0.29[.0] - * 1.0.37 10 10037 10.so.0.37[.0] - * 1.2.30beta01-04 13 10230 12.so.0.30[.0] - * 1.0.38rc01-08 10 10038 10.so.0.38[.0] - * 1.2.30rc01-08 13 10230 12.so.0.30[.0] - * 1.0.38 10 10038 10.so.0.38[.0] - * 1.2.30 13 10230 12.so.0.30[.0] - * 1.0.39rc01-03 10 10039 10.so.0.39[.0] - * 1.2.31rc01-03 13 10231 12.so.0.31[.0] - * 1.0.39 10 10039 10.so.0.39[.0] - * 1.2.31 13 10231 12.so.0.31[.0] - * 1.2.32beta01-02 13 10232 12.so.0.32[.0] - * 1.0.40rc01 10 10040 10.so.0.40[.0] - * 1.2.32rc01 13 10232 12.so.0.32[.0] - * 1.0.40 10 10040 10.so.0.40[.0] - * 1.2.32 13 10232 12.so.0.32[.0] - * 1.2.33beta01-02 13 10233 12.so.0.33[.0] - * 1.2.33rc01-02 13 10233 12.so.0.33[.0] - * 1.0.41rc01 10 10041 10.so.0.41[.0] - * 1.2.33 13 10233 12.so.0.33[.0] - * 1.0.41 10 10041 10.so.0.41[.0] - * 1.2.34beta01-07 13 10234 12.so.0.34[.0] - * 1.0.42rc01 10 10042 10.so.0.42[.0] - * 1.2.34rc01 13 10234 12.so.0.34[.0] - * 1.0.42 10 10042 10.so.0.42[.0] - * 1.2.34 13 10234 12.so.0.34[.0] - * 1.2.35beta01-03 13 10235 12.so.0.35[.0] - * 1.0.43rc01-02 10 10043 10.so.0.43[.0] - * 1.2.35rc01-02 13 10235 12.so.0.35[.0] - * 1.0.43 10 10043 10.so.0.43[.0] - * 1.2.35 13 10235 12.so.0.35[.0] - * 1.2.36beta01-05 13 10236 12.so.0.36[.0] - * 1.2.36rc01 13 10236 12.so.0.36[.0] - * 1.0.44 10 10044 10.so.0.44[.0] - * 1.2.36 13 10236 12.so.0.36[.0] - * 1.2.37beta01-03 13 10237 12.so.0.37[.0] - * 1.2.37rc01 13 10237 12.so.0.37[.0] - * 1.2.37 13 10237 12.so.0.37[.0] - * 1.2.45 10 10045 12.so.0.45[.0] - * 1.0.46 10 10046 10.so.0.46[.0] - * 1.2.38beta01 13 10238 12.so.0.38[.0] - * 1.2.38rc01-03 13 10238 12.so.0.38[.0] - * 1.0.47 10 10047 10.so.0.47[.0] - * 1.2.38 13 10238 12.so.0.38[.0] - * 1.2.39beta01-05 13 10239 12.so.0.39[.0] - * 1.2.39rc01 13 10239 12.so.0.39[.0] - * 1.0.48 10 10048 10.so.0.48[.0] - * 1.2.39 13 10239 12.so.0.39[.0] - * 1.2.40beta01 13 10240 12.so.0.40[.0] - * 1.2.40rc01 13 10240 12.so.0.40[.0] - * 1.0.49 10 10049 10.so.0.49[.0] - * 1.2.40 13 10240 12.so.0.40[.0] - * - * Henceforth the source version will match the shared-library major - * and minor numbers; the shared-library major version number will be - * used for changes in backward compatibility, as it is intended. The - * PNG_LIBPNG_VER macro, which is not used within libpng but is available - * for applications, is an unsigned integer of the form xyyzz corresponding - * to the source version x.y.z (leading zeros in y and z). Beta versions - * were given the previous public release number plus a letter, until - * version 1.0.6j; from then on they were given the upcoming public - * release number plus "betaNN" or "rcNN". - * - * Binary incompatibility exists only when applications make direct access - * to the info_ptr or png_ptr members through png.h, and the compiled - * application is loaded with a different version of the library. - * - * DLLNUM will change each time there are forward or backward changes - * in binary compatibility (e.g., when a new feature is added). - * - * See libpng.txt or libpng.3 for more information. The PNG specification - * is available as a W3C Recommendation and as an ISO Specification, - * defines should NOT be changed. - */ -#define PNG_INFO_gAMA 0x0001 -#define PNG_INFO_sBIT 0x0002 -#define PNG_INFO_cHRM 0x0004 -#define PNG_INFO_PLTE 0x0008 -#define PNG_INFO_tRNS 0x0010 -#define PNG_INFO_bKGD 0x0020 -#define PNG_INFO_hIST 0x0040 -#define PNG_INFO_pHYs 0x0080 -#define PNG_INFO_oFFs 0x0100 -#define PNG_INFO_tIME 0x0200 -#define PNG_INFO_pCAL 0x0400 -#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ -#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ -#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ -#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ -#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ - -/* This is used for the transformation routines, as some of them - * change these values for the row. It also should enable using - * the routines for other purposes. - */ -typedef struct png_row_info_struct -{ - png_uint_32 width; /* width of row */ - png_uint_32 rowbytes; /* number of bytes in row */ - png_byte color_type; /* color type of row */ - png_byte bit_depth; /* bit depth of row */ - png_byte channels; /* number of channels (1, 2, 3, or 4) */ - png_byte pixel_depth; /* bits per pixel (depth * channels) */ -} png_row_info; - -typedef png_row_info FAR * png_row_infop; -typedef png_row_info FAR * FAR * png_row_infopp; - -/* These are the function types for the I/O functions and for the functions - * that allow the user to override the default I/O functions with his or her - * own. The png_error_ptr type should match that of user-supplied warning - * and error functions, while the png_rw_ptr type should match that of the - * user read/write data functions. - */ -typedef struct png_struct_def png_struct; -typedef png_struct FAR * png_structp; - -typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); -typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); -typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); -typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, - int)); -typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, - int)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); -typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); -typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, - png_uint_32, int)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, - png_row_infop, png_bytep)); -#endif - -#if defined(PNG_USER_CHUNKS_SUPPORTED) -typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); -#endif -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) -typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); -#endif - -/* Transform masks for the high-level interface */ -#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ -#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ -#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ -#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ -#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ -#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ -#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ -#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ -#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ -#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ -#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ -#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ -#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only, deprecated */ -/* Added to libpng-1.2.34 */ -#define PNG_TRANSFORM_STRIP_FILLER_BEFORE 0x0800 /* write only */ -#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ - -/* Flags for MNG supported features */ -#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 -#define PNG_FLAG_MNG_FILTER_64 0x04 -#define PNG_ALL_MNG_FEATURES 0x05 - -typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); -typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); - -/* The structure that holds the information to read and write PNG files. - * The only people who need to care about what is inside of this are the - * people who will be modifying the library for their own special needs. - * It should NOT be accessed directly by an application, except to store - * the jmp_buf. - */ - -struct png_struct_def -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf jmpbuf; /* used in png_error */ -#endif - png_error_ptr error_fn; /* function for printing errors and aborting */ - png_error_ptr warning_fn; /* function for printing warnings */ - png_voidp error_ptr; /* user supplied struct for error functions */ - png_rw_ptr write_data_fn; /* function for writing output data */ - png_rw_ptr read_data_fn; /* function for reading input data */ - png_voidp io_ptr; /* ptr to application struct for I/O functions */ - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - png_user_transform_ptr read_user_transform_fn; /* user read transform */ -#endif - -#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_user_transform_ptr write_user_transform_fn; /* user write transform */ -#endif - -/* These were added in libpng-1.0.2 */ -#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - png_voidp user_transform_ptr; /* user supplied struct for user transform */ - png_byte user_transform_depth; /* bit depth of user transformed pixels */ - png_byte user_transform_channels; /* channels in user transformed pixels */ -#endif -#endif - - png_uint_32 mode; /* tells us where we are in the PNG file */ - png_uint_32 flags; /* flags indicating various things to libpng */ - png_uint_32 transformations; /* which transformations to perform */ - - z_stream zstream; /* pointer to decompression structure (below) */ - png_bytep zbuf; /* buffer for zlib */ - png_size_t zbuf_size; /* size of zbuf */ - int zlib_level; /* holds zlib compression level */ - int zlib_method; /* holds zlib compression method */ - int zlib_window_bits; /* holds zlib compression window bits */ - int zlib_mem_level; /* holds zlib compression memory level */ - int zlib_strategy; /* holds zlib compression strategy */ - - png_uint_32 width; /* width of image in pixels */ - png_uint_32 height; /* height of image in pixels */ - png_uint_32 num_rows; /* number of rows in current pass */ - png_uint_32 usr_width; /* width of row at start of write */ - png_uint_32 rowbytes; /* size of row in bytes */ - png_uint_32 irowbytes; /* size of current interlaced row in bytes */ - png_uint_32 iwidth; /* width of current interlaced row in pixels */ - png_uint_32 row_number; /* current row in interlace pass */ - png_bytep prev_row; /* buffer to save previous (unfiltered) row */ - png_bytep row_buf; /* buffer to save current (unfiltered) row */ -#ifndef PNG_NO_WRITE_FILTER - png_bytep sub_row; /* buffer to save "sub" row when filtering */ - png_bytep up_row; /* buffer to save "up" row when filtering */ - png_bytep avg_row; /* buffer to save "avg" row when filtering */ - png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ -#endif - png_row_info row_info; /* used for transformation routines */ - - png_uint_32 idat_size; /* current IDAT size for read */ - png_uint_32 crc; /* current chunk CRC value */ - png_colorp palette; /* palette from the input file */ - png_uint_16 num_palette; /* number of color entries in palette */ - png_uint_16 num_trans; /* number of transparency values */ - png_byte chunk_name[5]; /* null-terminated name of current chunk */ - png_byte compression; /* file compression type (always 0) */ - png_byte filter; /* file filter type (always 0) */ - png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - png_byte pass; /* current interlace pass (0 - 6) */ - png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ - png_byte color_type; /* color type of file */ - png_byte bit_depth; /* bit depth of file */ - png_byte usr_bit_depth; /* bit depth of users row */ - png_byte pixel_depth; /* number of bits per pixel */ - png_byte channels; /* number of channels in file */ - png_byte usr_channels; /* channels at start of write */ - png_byte sig_bytes; /* magic bytes read/written from start of file */ - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -#ifdef PNG_LEGACY_SUPPORTED - png_byte filler; /* filler byte for pixel expansion */ -#else - png_uint_16 filler; /* filler bytes for pixel expansion */ -#endif -#endif - -#if defined(PNG_bKGD_SUPPORTED) - png_byte background_gamma_type; -# ifdef PNG_FLOATING_POINT_SUPPORTED - float background_gamma; -# endif - png_color_16 background; /* background color in screen gamma space */ -#if defined(PNG_READ_GAMMA_SUPPORTED) - png_color_16 background_1; /* background normalized to gamma 1.0 */ -#endif -#endif /* PNG_bKGD_SUPPORTED */ - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_flush_ptr output_flush_fn; /* Function for flushing output */ - png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ - png_uint_32 flush_rows; /* number of rows written since last flush */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ -#ifdef PNG_FLOATING_POINT_SUPPORTED - float gamma; /* file gamma value */ - float screen_gamma; /* screen gamma value (display_exponent) */ -#endif -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep gamma_table; /* gamma table for 8-bit depth files */ - png_bytep gamma_from_1; /* converts from 1.0 to screen */ - png_bytep gamma_to_1; /* converts from file to 1.0 */ - png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ - png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ - png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) - png_color_8 sig_bit; /* significant bits in each available channel */ -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift; /* shift for significant bit tranformation */ -#endif - -#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ - || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_bytep trans; /* transparency values for paletted files */ - png_color_16 trans_values; /* transparency values for non-paletted files */ -#endif - - png_read_status_ptr read_row_fn; /* called after each row is decoded */ - png_write_status_ptr write_row_fn; /* called after each row is encoded */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_progressive_info_ptr info_fn; /* called after header data fully read */ - png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ - png_progressive_end_ptr end_fn; /* called after image is complete */ - png_bytep save_buffer_ptr; /* current location in save_buffer */ - png_bytep save_buffer; /* buffer for previously read data */ - png_bytep current_buffer_ptr; /* current location in current_buffer */ - png_bytep current_buffer; /* buffer for recently used data */ - png_uint_32 push_length; /* size of current input chunk */ - png_uint_32 skip_length; /* bytes to skip in input data */ - png_size_t save_buffer_size; /* amount of data now in save_buffer */ - png_size_t save_buffer_max; /* total size of save_buffer */ - png_size_t buffer_size; /* total amount of available input data */ - png_size_t current_buffer_size; /* amount of data now in current_buffer */ - int process_mode; /* what push library is currently doing */ - int cur_palette; /* current push library palette index */ - -# if defined(PNG_TEXT_SUPPORTED) - png_size_t current_text_size; /* current size of text input data */ - png_size_t current_text_left; /* how much text left to read in input */ - png_charp current_text; /* current text chunk buffer */ - png_charp current_text_ptr; /* current location in current_text */ -# endif /* PNG_TEXT_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* for the Borland special 64K segment handler */ - png_bytepp offset_table_ptr; - png_bytep offset_table; - png_uint_16 offset_table_number; - png_uint_16 offset_table_count; - png_uint_16 offset_table_count_free; -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) - png_bytep palette_lookup; /* lookup table for dithering */ - png_bytep dither_index; /* index translation for palette files */ -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) - png_uint_16p hist; /* histogram */ -#endif - -#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) - png_byte heuristic_method; /* heuristic for row filter selection */ - png_byte num_prev_filters; /* number of weights for previous rows */ - png_bytep prev_filters; /* filter type(s) of previous row(s) */ - png_uint_16p filter_weights; /* weight(s) for previous line(s) */ - png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ - png_uint_16p filter_costs; /* relative filter calculation cost */ - png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ -#endif - -#if defined(PNG_TIME_RFC1123_SUPPORTED) - png_charp time_buffer; /* String to hold RFC 1123 time text */ -#endif - -/* New members added in libpng-1.0.6 */ - -#ifdef PNG_FREE_ME_SUPPORTED - png_uint_32 free_me; /* flags items libpng is responsible for freeing */ -#endif - -#if defined(PNG_USER_CHUNKS_SUPPORTED) - png_voidp user_chunk_ptr; - png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ -#endif - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int num_chunk_list; - png_bytep chunk_list; -#endif - -/* New members added in libpng-1.0.3 */ -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - png_byte rgb_to_gray_status; - /* These were changed from png_byte in libpng-1.0.6 */ - png_uint_16 rgb_to_gray_red_coeff; - png_uint_16 rgb_to_gray_green_coeff; - png_uint_16 rgb_to_gray_blue_coeff; -#endif - -/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ -#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ - defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ - defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) -/* Changed from png_byte to png_uint_32 at version 1.2.0 */ -#ifdef PNG_1_0_X - png_byte mng_features_permitted; -#else - png_uint_32 mng_features_permitted; -#endif /* PNG_1_0_X */ -#endif - -/* New member added in libpng-1.0.7 */ -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - png_fixed_point int_gamma; -#endif - -/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ -#if defined(PNG_MNG_FEATURES_SUPPORTED) - png_byte filter_type; -#endif - -#if defined(PNG_1_0_X) -/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ - png_uint_32 row_buf_size; -#endif - -/* New members added in libpng-1.2.0 */ -#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) -# if !defined(PNG_1_0_X) -# if defined(PNG_MMX_CODE_SUPPORTED) - png_byte mmx_bitdepth_threshold; - png_uint_32 mmx_rowbytes_threshold; -# endif - png_uint_32 asm_flags; -# endif -#endif - -/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ -#ifdef PNG_USER_MEM_SUPPORTED - png_voidp mem_ptr; /* user supplied struct for mem functions */ - png_malloc_ptr malloc_fn; /* function for allocating memory */ - png_free_ptr free_fn; /* function for freeing memory */ -#endif - -/* New member added in libpng-1.0.13 and 1.2.0 */ - png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ - -#if defined(PNG_READ_DITHER_SUPPORTED) -/* The following three members were added at version 1.0.14 and 1.2.4 */ - png_bytep dither_sort; /* working sort array */ - png_bytep index_to_palette; /* where the original index currently is */ - /* in the palette */ - png_bytep palette_to_index; /* which original index points to this */ - /* palette color */ -#endif - -/* New members added in libpng-1.0.16 and 1.2.6 */ - png_byte compression_type; - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_uint_32 user_width_max; - png_uint_32 user_height_max; -#endif - -/* New member added in libpng-1.0.25 and 1.2.17 */ -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - /* Storage for unknown chunk that the library doesn't recognize. */ - png_unknown_chunk unknown_chunk; -#endif - -/* New members added in libpng-1.2.26 */ - png_uint_32 old_big_row_buf_size, old_prev_row_size; - -/* New member added in libpng-1.2.30 */ - png_charp chunkdata; /* buffer for reading chunk data */ - -}; - - -/* This triggers a compiler error in png.c, if png.c and png.h - * do not agree upon the version number. - */ -typedef png_structp version_1_2_40; - -typedef png_struct FAR * FAR * png_structpp; - -/* Here are the function definitions most commonly used. This is not - * the place to find out how to use libpng. See libpng.txt for the - * full explanation, see example.c for the summary. This just provides - * a simple one line description of the use of each function. - */ - -/* Returns the version number of the library */ -extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); - -/* Tell lib we have already handled the first magic bytes. - * Handling more than 8 bytes from the beginning of the file is an error. - */ -extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, - int num_bytes)); - -/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a - * PNG file. Returns zero if the supplied bytes match the 8-byte PNG - * signature, and non-zero otherwise. Having num_to_check == 0 or - * start > 7 will always fail (ie return non-zero). - */ -extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, - png_size_t num_to_check)); - -/* Simple signature checking function. This is the same as calling - * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). - */ -extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)); - -/* Allocate and initialize png_ptr struct for reading, and any other memory. */ -extern PNG_EXPORT(png_structp,png_create_read_struct) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn)); - -/* Allocate and initialize png_ptr struct for writing, and any other memory */ -extern PNG_EXPORT(png_structp,png_create_write_struct) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn)); - -#ifdef PNG_WRITE_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) - PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_WRITE_SUPPORTED -extern PNG_EXPORT(void,png_set_compression_buffer_size) - PNGARG((png_structp png_ptr, png_uint_32 size)); -#endif - -/* Reset the compression stream */ -extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); - -/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ -#ifdef PNG_USER_MEM_SUPPORTED -extern PNG_EXPORT(png_structp,png_create_read_struct_2) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)); -extern PNG_EXPORT(png_structp,png_create_write_struct_2) - PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn)); -#endif - -/* Write a PNG chunk - size, type, (optional) data, CRC. */ -extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, - png_bytep chunk_name, png_bytep data, png_size_t length)); - -/* Write the start of a PNG chunk - length and chunk name. */ -extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, - png_bytep chunk_name, png_uint_32 length)); - -/* Write the data of a PNG chunk started with png_write_chunk_start(). */ -extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); - -/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ -extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); - -/* Allocate and initialize the info structure */ -extern PNG_EXPORT(png_infop,png_create_info_struct) - PNGARG((png_structp png_ptr)); - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Initialize the info structure (old interface - DEPRECATED) */ -extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)); -#undef png_info_init -#define png_info_init(info_ptr) png_info_init_3(&info_ptr,\ - png_sizeof(png_info)); -#endif - -extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, - png_size_t png_info_struct_size)); - -/* Writes all the PNG information before the image. */ -extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the information before the actual image data. */ -extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -#if defined(PNG_TIME_RFC1123_SUPPORTED) -extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) - PNGARG((png_structp png_ptr, png_timep ptime)); -#endif - -#if !defined(_WIN32_WCE) -/* "time.h" functions are not supported on WindowsCE */ -#if defined(PNG_WRITE_tIME_SUPPORTED) -/* Convert from a struct tm to png_time */ -extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, - struct tm FAR * ttime)); - -/* Convert from time_t to png_time. Uses gmtime() */ -extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, - time_t ttime)); -#endif /* PNG_WRITE_tIME_SUPPORTED */ -#endif /* _WIN32_WCE */ - -#if defined(PNG_READ_EXPAND_SUPPORTED) -/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ -extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); -#if !defined(PNG_1_0_X) -extern PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp - png_ptr)); -#endif -extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Deprecated */ -extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); -#endif -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -/* Use blue, green, red order for pixels. */ -extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) -/* Expand the grayscale to 24-bit RGB if necessary. */ -extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -/* Reduce RGB to grayscale. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, - int error_action, double red, double green )); -#endif -extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, - int error_action, png_fixed_point red, png_fixed_point green )); -extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp - png_ptr)); -#endif - -extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, - png_colorp palette)); - -#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ - defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ -extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, - png_uint_32 filler, int flags)); -/* The values of the PNG_FILLER_ defines should NOT be changed */ -#define PNG_FILLER_BEFORE 0 -#define PNG_FILLER_AFTER 1 -/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ -#if !defined(PNG_1_0_X) -extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr, - png_uint_32 filler, int flags)); -#endif -#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Swap bytes in 16-bit depth files. */ -extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) -/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ -extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) -/* Swap packing order of pixels in bytes. */ -extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) -/* Converts files to legal bit depths. */ -extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, - png_color_8p true_bits)); -#endif - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) -/* Have the code handle the interlacing. Returns the number of passes. */ -extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -/* Invert monochrome files */ -extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) -/* Handle alpha and tRNS by replacing with a background color. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, - png_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma)); -#endif -#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 -#define PNG_BACKGROUND_GAMMA_SCREEN 1 -#define PNG_BACKGROUND_GAMMA_FILE 2 -#define PNG_BACKGROUND_GAMMA_UNIQUE 3 -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) -/* Strip the second byte of information from a 16-bit depth file. */ -extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) -/* Turn on dithering, and reduce the palette to the number of colors available. */ -extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette, int maximum_colors, - png_uint_16p histogram, int full_dither)); -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) -/* Handle gamma correction. Screen_gamma=(display_exponent) */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, - double screen_gamma, double default_file_gamma)); -#endif -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ - defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) -/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ -/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ -extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, - int empty_plte_permitted)); -#endif -#endif - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -/* Set how many lines between output flushes - 0 for no flushing */ -extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); -/* Flush the current PNG output buffer */ -extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); -#endif - -/* Optional update palette with requested transformations */ -extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); - -/* Optional call to update the users info structure */ -extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read one or more rows of image data. */ -extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, - png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); -#endif - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read a row of data. */ -extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, - png_bytep row, - png_bytep display_row)); -#endif - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the whole image into memory at once. */ -extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, - png_bytepp image)); -#endif - -/* Write a row of image data */ -extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, - png_bytep row)); - -/* Write a few rows of image data */ -extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, - png_bytepp row, png_uint_32 num_rows)); - -/* Write the image data */ -extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, - png_bytepp image)); - -/* Writes the end of the PNG file. */ -extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the end of the PNG file. */ -extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -/* Free any memory associated with the png_info_struct */ -extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, - png_infopp info_ptr_ptr)); - -/* Free any memory associated with the png_struct and the png_info_structs */ -extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp - png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); - -/* Free all memory used by the read (old method - NOT DLL EXPORTED) */ -extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, - png_infop end_info_ptr)); - -/* Free any memory associated with the png_struct and the png_info_structs */ -extern PNG_EXPORT(void,png_destroy_write_struct) - PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); - -/* Free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ -extern void png_write_destroy PNGARG((png_structp png_ptr)); - -/* Set the libpng method of handling chunk CRC errors */ -extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, - int crit_action, int ancil_action)); - -/* Values for png_set_crc_action() to say how to handle CRC errors in - * ancillary and critical chunks, and whether to use the data contained - * therein. Note that it is impossible to "discard" data in a critical - * chunk. For versions prior to 0.90, the action was always error/quit, - * whereas in version 0.90 and later, the action for CRC errors in ancillary - * chunks is warn/discard. These values should NOT be changed. - * - * value action:critical action:ancillary - */ -#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ -#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ -#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ -#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ -#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ -#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ - -/* These functions give the user control over the scan-line filtering in - * libpng and the compression methods used by zlib. These functions are - * mainly useful for testing, as the defaults should work with most users. - * Those users who are tight on memory or want faster performance at the - * expense of compression can modify them. See the compression library - * header file (zlib.h) for an explination of the compression functions. - */ - -/* Set the filtering method(s) used by libpng. Currently, the only valid - * value for "method" is 0. - */ -extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, - int filters)); - -/* Flags for png_set_filter() to say which filters to use. The flags - * are chosen so that they don't conflict with real filter types - * below, in case they are supplied instead of the #defined constants. - * These values should NOT be changed. - */ -#define PNG_NO_FILTERS 0x00 -#define PNG_FILTER_NONE 0x08 -#define PNG_FILTER_SUB 0x10 -#define PNG_FILTER_UP 0x20 -#define PNG_FILTER_AVG 0x40 -#define PNG_FILTER_PAETH 0x80 -#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ - PNG_FILTER_AVG | PNG_FILTER_PAETH) - -/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. - * These defines should NOT be changed. - */ -#define PNG_FILTER_VALUE_NONE 0 -#define PNG_FILTER_VALUE_SUB 1 -#define PNG_FILTER_VALUE_UP 2 -#define PNG_FILTER_VALUE_AVG 3 -#define PNG_FILTER_VALUE_PAETH 4 -#define PNG_FILTER_VALUE_LAST 5 - -#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ -/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ - * defines, either the default (minimum-sum-of-absolute-differences), or - * the experimental method (weighted-minimum-sum-of-absolute-differences). - * - * Weights are factors >= 1.0, indicating how important it is to keep the - * filter type consistent between rows. Larger numbers mean the current - * filter is that many times as likely to be the same as the "num_weights" - * previous filters. This is cumulative for each previous row with a weight. - * There needs to be "num_weights" values in "filter_weights", or it can be - * NULL if the weights aren't being specified. Weights have no influence on - * the selection of the first row filter. Well chosen weights can (in theory) - * improve the compression for a given image. - * - * Costs are factors >= 1.0 indicating the relative decoding costs of a - * filter type. Higher costs indicate more decoding expense, and are - * therefore less likely to be selected over a filter with lower computational - * costs. There needs to be a value in "filter_costs" for each valid filter - * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't - * setting the costs. Costs try to improve the speed of decompression without - * unduly increasing the compressed image size. - * - * A negative weight or cost indicates the default value is to be used, and - * values in the range [0.0, 1.0) indicate the value is to remain unchanged. - * The default values for both weights and costs are currently 1.0, but may - * change if good general weighting/cost heuristics can be found. If both - * the weights and costs are set to 1.0, this degenerates the WEIGHTED method - * to the UNWEIGHTED method, but with added encoding time/computation. - */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, - int heuristic_method, int num_weights, png_doublep filter_weights, - png_doublep filter_costs)); -#endif -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ - -/* Heuristic used for row filter selection. These defines should NOT be - * changed. - */ -#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ -#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ -#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ -#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ - -/* Set the library compression level. Currently, valid values range from - * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 - * (0 - no compression, 9 - "maximal" compression). Note that tests have - * shown that zlib compression levels 3-6 usually perform as well as level 9 - * for PNG images, and do considerably fewer caclulations. In the future, - * these values may not correspond directly to the zlib compression levels. - */ -extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, - int level)); - -extern PNG_EXPORT(void,png_set_compression_mem_level) - PNGARG((png_structp png_ptr, int mem_level)); - -extern PNG_EXPORT(void,png_set_compression_strategy) - PNGARG((png_structp png_ptr, int strategy)); - -extern PNG_EXPORT(void,png_set_compression_window_bits) - PNGARG((png_structp png_ptr, int window_bits)); - -extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, - int method)); - -/* These next functions are called for input/output, memory, and error - * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, - * and call standard C I/O routines such as fread(), fwrite(), and - * fprintf(). These functions can be made to use other I/O routines - * at run time for those applications that need to handle I/O in a - * different manner by calling png_set_???_fn(). See libpng.txt for - * more information. - */ - -#if !defined(PNG_NO_STDIO) -/* Initialize the input/output for the PNG file to the default functions. */ -extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); -#endif - -/* Replace the (error and abort), and warning functions with user - * supplied functions. If no messages are to be printed you must still - * write and use replacement functions. The replacement error_fn should - * still do a longjmp to the last setjmp location if you are using this - * method of error handling. If error_fn or warning_fn is NULL, the - * default function will be used. - */ - -extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); - -/* Return the user pointer associated with the error functions */ -extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); - -/* Replace the default data output functions with a user supplied one(s). - * If buffered output is not used, then output_flush_fn can be set to NULL. - * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time - * output_flush_fn will be ignored (and thus can be NULL). - * It is probably a mistake to use NULL for output_flush_fn if - * write_data_fn is not also NULL unless you have built libpng with - * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's - * default flush function, which uses the standard *FILE structure, will - * be used. - */ -extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); - -/* Replace the default data input function with a user supplied one. */ -extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, - png_voidp io_ptr, png_rw_ptr read_data_fn)); - -/* Return the user pointer associated with the I/O functions */ -extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); - -extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, - png_read_status_ptr read_row_fn)); - -extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, - png_write_status_ptr write_row_fn)); - -#ifdef PNG_USER_MEM_SUPPORTED -/* Replace the default memory allocation functions with user supplied one(s). */ -extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, - png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); -/* Return the user pointer associated with the memory functions */ -extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp - png_ptr, png_user_transform_ptr read_user_transform_fn)); -#endif - -#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp - png_ptr, png_user_transform_ptr write_user_transform_fn)); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) -extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp - png_ptr, png_voidp user_transform_ptr, int user_transform_depth, - int user_transform_channels)); -/* Return the user pointer associated with the user transform functions */ -extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) - PNGARG((png_structp png_ptr)); -#endif - -#ifdef PNG_USER_CHUNKS_SUPPORTED -extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, - png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); -extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp - png_ptr)); -#endif - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -/* Sets the function callbacks for the push reader, and a pointer to a - * user-defined structure available to the callback functions. - */ -extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, - png_voidp progressive_ptr, - png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, - png_progressive_end_ptr end_fn)); - -/* Returns the user pointer associated with the push read functions */ -extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) - PNGARG((png_structp png_ptr)); - -/* Function to be called when data becomes available */ -extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); - -/* Function that combines rows. Not very much different than the - * png_combine_row() call. Is this even used????? - */ -extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, - png_bytep old_row, png_bytep new_row)); -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, - png_uint_32 size)); - -#if defined(PNG_1_0_X) -# define png_malloc_warn png_malloc -#else -/* Added at libpng version 1.2.4 */ -extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, - png_uint_32 size)); -#endif - -/* Frees a pointer allocated by png_malloc() */ -extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); - -#if defined(PNG_1_0_X) -/* Function to allocate memory for zlib. */ -extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, - uInt size)); - -/* Function to free memory for zlib */ -extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); -#endif - -/* Free data that was allocated internally */ -extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 free_me, int num)); -#ifdef PNG_FREE_ME_SUPPORTED -/* Reassign responsibility for freeing existing data, whether allocated - * by libpng or by the application - */ -extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, - png_infop info_ptr, int freer, png_uint_32 mask)); -#endif -/* Assignments for png_data_freer */ -#define PNG_DESTROY_WILL_FREE_DATA 1 -#define PNG_SET_WILL_FREE_DATA 1 -#define PNG_USER_WILL_FREE_DATA 2 -/* Flags for png_ptr->free_me and info_ptr->free_me */ -#define PNG_FREE_HIST 0x0008 -#define PNG_FREE_ICCP 0x0010 -#define PNG_FREE_SPLT 0x0020 -#define PNG_FREE_ROWS 0x0040 -#define PNG_FREE_PCAL 0x0080 -#define PNG_FREE_SCAL 0x0100 -#define PNG_FREE_UNKN 0x0200 -#define PNG_FREE_LIST 0x0400 -#define PNG_FREE_PLTE 0x1000 -#define PNG_FREE_TRNS 0x2000 -#define PNG_FREE_TEXT 0x4000 -#define PNG_FREE_ALL 0x7fff -#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ - -#ifdef PNG_USER_MEM_SUPPORTED -extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, - png_uint_32 size)); -extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, - png_voidp ptr)); -#endif - -extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, - png_voidp s1, png_voidp s2, png_uint_32 size)); - -extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, - png_voidp s1, int value, png_uint_32 size)); - -#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ -extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, - int check)); -#endif /* USE_FAR_KEYWORD */ - -#ifndef PNG_NO_ERROR_TEXT -/* Fatal error in PNG image of libpng - can't continue */ -extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)); - -/* The same, but the chunk name is prepended to the error string. */ -extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, - png_const_charp error_message)); -#else -/* Fatal error in PNG image of libpng - can't continue */ -extern PNG_EXPORT(void,png_err) PNGARG((png_structp png_ptr)); -#endif - -#ifndef PNG_NO_WARNINGS -/* Non-fatal error in libpng. Can continue, but may have a problem. */ -extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); - -#ifdef PNG_READ_SUPPORTED -/* Non-fatal error in libpng, chunk name is prepended to message. */ -extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, - png_const_charp warning_message)); -#endif /* PNG_READ_SUPPORTED */ -#endif /* PNG_NO_WARNINGS */ - -/* The png_set_ functions are for storing values in the png_info_struct. - * Similarly, the png_get_ calls are used to read values from the - * png_info_struct, either storing the parameters in the passed variables, or - * setting pointers into the png_info_struct where the data is stored. The - * png_get_ functions return a non-zero value if the data was available - * in info_ptr, or return zero and do not change any of the parameters if the - * data was not available. - * - * These functions should be used instead of directly accessing png_info - * to avoid problems with future changes in the size and internal layout of - * png_info_struct. - */ -/* Returns "flag" if chunk data is valid in info_ptr. */ -extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, -png_infop info_ptr, png_uint_32 flag)); - -/* Returns number of bytes needed to hold a transformed row. */ -extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#if defined(PNG_INFO_IMAGE_SUPPORTED) -/* Returns row_pointers, which is an array of pointers to scanlines that was - * returned from png_read_png(). - */ -extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, -png_infop info_ptr)); -/* Set row_pointers, which is an array of pointers to scanlines for use - * by png_write_png(). - */ -extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytepp row_pointers)); -#endif - -/* Returns number of color channels in image. */ -extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#ifdef PNG_EASY_ACCESS_SUPPORTED -/* Returns image width in pixels. */ -extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image height in pixels. */ -extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image bit_depth. */ -extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image color_type. */ -extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image filter_type. */ -extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image interlace_type. */ -extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image compression_type. */ -extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns image resolution in pixels per meter, from pHYs chunk data. */ -extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -/* Returns pixel aspect ratio, computed from pHYs chunk data. */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -#endif - -/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ -extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp -png_ptr, png_infop info_ptr)); -extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp -png_ptr, png_infop info_ptr)); - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ - -/* Returns pointer to signature string read from PNG header */ -extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#if defined(PNG_bKGD_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_16p *background)); -#endif - -#if defined(PNG_bKGD_SUPPORTED) -extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_16p background)); -#endif - -#if defined(PNG_cHRM_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, double *white_x, double *white_y, double *red_x, - double *red_y, double *green_x, double *green_y, double *blue_x, - double *blue_y)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point - *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, - png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point - *int_blue_x, png_fixed_point *int_blue_y)); -#endif -#endif - -#if defined(PNG_cHRM_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, double white_x, double white_y, double red_x, - double red_y, double green_x, double green_y, double blue_x, double blue_y)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif -#endif - -#if defined(PNG_gAMA_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, double *file_gamma)); -#endif -extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point *int_file_gamma)); -#endif - -#if defined(PNG_gAMA_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, - png_infop info_ptr, double file_gamma)); -#endif -extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_file_gamma)); -#endif - -#if defined(PNG_hIST_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_16p *hist)); -#endif - -#if defined(PNG_hIST_SUPPORTED) -extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_16p hist)); -#endif - -extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, - int *bit_depth, int *color_type, int *interlace_method, - int *compression_method, int *filter_method)); - -extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_method, int compression_method, - int filter_method)); - -#if defined(PNG_oFFs_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, - int *unit_type)); -#endif - -#if defined(PNG_oFFs_SUPPORTED) -extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, - int unit_type)); -#endif - -#if defined(PNG_pCAL_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, - int *type, int *nparams, png_charp *units, png_charpp *params)); -#endif - -#if defined(PNG_pCAL_SUPPORTED) -extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, - int type, int nparams, png_charp units, png_charpp params)); -#endif - -#if defined(PNG_pHYs_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -#endif - -#if defined(PNG_pHYs_SUPPORTED) -extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); -#endif - -extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_colorp *palette, int *num_palette)); - -extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_colorp palette, int num_palette)); - -#if defined(PNG_sBIT_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_8p *sig_bit)); -#endif - -#if defined(PNG_sBIT_SUPPORTED) -extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_color_8p sig_bit)); -#endif - -#if defined(PNG_sRGB_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *intent)); -#endif - -#if defined(PNG_sRGB_SUPPORTED) -extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, - png_infop info_ptr, int intent)); -extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, - png_infop info_ptr, int intent)); -#endif - -#if defined(PNG_iCCP_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charpp name, int *compression_type, - png_charpp profile, png_uint_32 *proflen)); - /* Note to maintainer: profile should be png_bytepp */ -#endif - -#if defined(PNG_iCCP_SUPPORTED) -extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp name, int compression_type, - png_charp profile, png_uint_32 proflen)); - /* Note to maintainer: profile should be png_bytep */ -#endif - -#if defined(PNG_sPLT_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_sPLT_tpp entries)); -#endif - -#if defined(PNG_sPLT_SUPPORTED) -extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_sPLT_tp entries, int nentries)); -#endif - -#if defined(PNG_TEXT_SUPPORTED) -/* png_get_text also returns the number of text chunks in *num_text */ -extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp *text_ptr, int *num_text)); -#endif - -/* - * Note while png_set_text() will accept a structure whose text, - * language, and translated keywords are NULL pointers, the structure - * returned by png_get_text will always contain regular - * zero-terminated C strings. They might be empty strings but - * they will never be NULL pointers. - */ - -#if defined(PNG_TEXT_SUPPORTED) -extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)); -#endif - -#if defined(PNG_tIME_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_timep *mod_time)); -#endif - -#if defined(PNG_tIME_SUPPORTED) -extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_timep mod_time)); -#endif - -#if defined(PNG_tRNS_SUPPORTED) -extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep *trans, int *num_trans, - png_color_16p *trans_values)); -#endif - -#if defined(PNG_tRNS_SUPPORTED) -extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_bytep trans, int num_trans, - png_color_16p trans_values)); -#endif - -#if defined(PNG_tRNS_SUPPORTED) -#endif - -#if defined(PNG_sCAL_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *unit, double *width, double *height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, - png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); -#endif -#endif -#endif /* PNG_sCAL_SUPPORTED */ - -#if defined(PNG_sCAL_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, int unit, double width, double height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, - png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); -#endif -#endif -#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -/* Provide a list of chunks and how they are to be handled, if the built-in - handling or default unknown chunk handling is not desired. Any chunks not - listed will be handled in the default manner. The IHDR and IEND chunks - must not be listed. - keep = 0: follow default behaviour - = 1: do not keep - = 2: keep only if safe-to-copy - = 3: keep even if unsafe-to-copy -*/ -extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp - png_ptr, int keep, png_bytep chunk_list, int num_chunks)); -PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep - chunk_name)); -#endif -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) -extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); -extern PNG_EXPORT(void, png_set_unknown_chunk_location) - PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); -extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp - png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); -#endif - -/* Png_free_data() will turn off the "valid" flag for anything it frees. - * If you need to turn it off for a chunk that your application has freed, - * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); - */ -extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, - png_infop info_ptr, int mask)); - -#if defined(PNG_INFO_IMAGE_SUPPORTED) -/* The "params" pointer is currently not used and is for future expansion. */ -extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); -extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, - png_infop info_ptr, - int transforms, - png_voidp params)); -#endif - -/* Define PNG_DEBUG at compile time for debugging information. Higher - * numbers for PNG_DEBUG mean more debugging information. This has - * only been added since version 0.95 so it is not implemented throughout - * libpng yet, but more support will be added as needed. - */ -#ifdef PNG_DEBUG -#if (PNG_DEBUG > 0) -#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) -#include -#if (PNG_DEBUG > 1) -#ifndef _DEBUG -# define _DEBUG -#endif -#ifndef png_debug -#define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) -#endif -#ifndef png_debug1 -#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) -#endif -#ifndef png_debug2 -#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) -#endif -#endif -#else /* PNG_DEBUG_FILE || !_MSC_VER */ -#ifndef PNG_DEBUG_FILE -#define PNG_DEBUG_FILE stderr -#endif /* PNG_DEBUG_FILE */ - -#if (PNG_DEBUG > 1) -/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on non-ISO - * compilers. - */ -# ifdef __STDC__ -# ifndef png_debug -# define png_debug(l,m) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ - } -# endif -# ifndef png_debug1 -# define png_debug1(l,m,p1) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ - } -# endif -# ifndef png_debug2 -# define png_debug2(l,m,p1,p2) \ - { \ - int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ - } -# endif -# else /* __STDC __ */ -# ifndef png_debug -# define png_debug(l,m) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format); \ - } -# endif -# ifndef png_debug1 -# define png_debug1(l,m,p1) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format,p1); \ - } -# endif -# ifndef png_debug2 -# define png_debug2(l,m,p1,p2) \ - { \ - int num_tabs=l; \ - char format[256]; \ - snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ - m,PNG_STRING_NEWLINE); \ - fprintf(PNG_DEBUG_FILE,format,p1,p2); \ - } -# endif -# endif /* __STDC __ */ -#endif /* (PNG_DEBUG > 1) */ - -#endif /* _MSC_VER */ -#endif /* (PNG_DEBUG > 0) */ -#endif /* PNG_DEBUG */ -#ifndef png_debug -#define png_debug(l, m) -#endif -#ifndef png_debug1 -#define png_debug1(l, m, p1) -#endif -#ifndef png_debug2 -#define png_debug2(l, m, p1, p2) -#endif - -extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); -extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); - -#ifdef PNG_MNG_FEATURES_SUPPORTED -extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp - png_ptr, png_uint_32 mng_features_permitted)); -#endif - -/* For use in png_set_keep_unknown, added to version 1.2.6 */ -#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 -#define PNG_HANDLE_CHUNK_NEVER 1 -#define PNG_HANDLE_CHUNK_IF_SAFE 2 -#define PNG_HANDLE_CHUNK_ALWAYS 3 - -/* Added to version 1.2.0 */ -#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) -#if defined(PNG_MMX_CODE_SUPPORTED) -#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ -#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ -#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 -#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 -#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 -#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 -#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 -#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 -#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ - -#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ - | PNG_ASM_FLAG_MMX_READ_INTERLACE \ - | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ - | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ - | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ - | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ) -#define PNG_MMX_WRITE_FLAGS ( 0 ) - -#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \ - | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \ - | PNG_MMX_READ_FLAGS \ - | PNG_MMX_WRITE_FLAGS ) - -#define PNG_SELECT_READ 1 -#define PNG_SELECT_WRITE 2 -#endif /* PNG_MMX_CODE_SUPPORTED */ - -#if !defined(PNG_1_0_X) -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) - PNGARG((int flag_select, int *compilerID)); - -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) - PNGARG((int flag_select)); - -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_asm_flags) - PNGARG((png_structp png_ptr)); - -/* pngget.c */ -extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) - PNGARG((png_structp png_ptr)); - -/* pngget.c */ -extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) - PNGARG((png_structp png_ptr)); - -/* pngset.c */ -extern PNG_EXPORT(void,png_set_asm_flags) - PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); - -/* pngset.c */ -extern PNG_EXPORT(void,png_set_mmx_thresholds) - PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, - png_uint_32 mmx_rowbytes_threshold)); - -#endif /* PNG_1_0_X */ - -#if !defined(PNG_1_0_X) -/* png.c, pnggccrd.c, or pngvcrd.c */ -extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); -#endif /* PNG_1_0_X */ -#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ - -/* Strip the prepended error numbers ("#nnn ") from error and warning - * messages before passing them to the error or warning handler. - */ -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp - png_ptr, png_uint_32 strip_mode)); -#endif - -/* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp - png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); -extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp - png_ptr)); -extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp - png_ptr)); -#endif - - -/* Maintainer: Put new public prototypes here ^, in libpng.3, and in - * project defs - */ - -#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED -/* With these routines we avoid an integer divide, which will be slower on - * most machines. However, it does take more operations than the corresponding - * divide method, so it may be slower on a few RISC systems. There are two - * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. - * - * Note that the rounding factors are NOT supposed to be the same! 128 and - * 32768 are correct for the NODIV code; 127 and 32767 are correct for the - * standard method. - * - * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] - */ - - /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ - -# define png_composite(composite, fg, alpha, bg) \ - { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ - + (png_uint_16)(bg)*(png_uint_16)(255 - \ - (png_uint_16)(alpha)) + (png_uint_16)128); \ - (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } - -# define png_composite_16(composite, fg, alpha, bg) \ - { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ - + (png_uint_32)(bg)*(png_uint_32)(65535L - \ - (png_uint_32)(alpha)) + (png_uint_32)32768L); \ - (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } - -#else /* Standard method using integer division */ - -# define png_composite(composite, fg, alpha, bg) \ - (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ - (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ - (png_uint_16)127) / 255) - -# define png_composite_16(composite, fg, alpha, bg) \ - (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ - (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ - (png_uint_32)32767) / (png_uint_32)65535L) - -#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ - -/* Inline macros to do direct reads of bytes from the input buffer. These - * require that you are using an architecture that uses PNG byte ordering - * (MSB first) and supports unaligned data storage. I think that PowerPC - * in big-endian mode and 680x0 are the only ones that will support this. - * The x86 line of processors definitely do not. The png_get_int_32() - * routine also assumes we are using two's complement format for negative - * values, which is almost certainly true. - */ -#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED) -# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) -# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) -# define png_get_int_32(buf) ( *((png_int_32p) (buf))) -#else -extern PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf)); -extern PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf)); -extern PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf)); -#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ -extern PNG_EXPORT(png_uint_32,png_get_uint_31) - PNGARG((png_structp png_ptr, png_bytep buf)); -/* No png_get_int_16 -- may be added if there's a real need for it. */ - -/* Place a 32-bit number into a buffer in PNG byte order (big-endian). - */ -extern PNG_EXPORT(void,png_save_uint_32) - PNGARG((png_bytep buf, png_uint_32 i)); -extern PNG_EXPORT(void,png_save_int_32) - PNGARG((png_bytep buf, png_int_32 i)); - -/* Place a 16-bit number into a buffer in PNG byte order. - * The parameter is declared unsigned int, not png_uint_16, - * just to avoid potential problems on pre-ANSI C compilers. - */ -extern PNG_EXPORT(void,png_save_uint_16) - PNGARG((png_bytep buf, unsigned int i)); -/* No png_save_int_16 -- may be added if there's a real need for it. */ - -/* ************************************************************************* */ - -/* These next functions are used internally in the code. They generally - * shouldn't be used unless you are writing code to add or replace some - * functionality in libpng. More information about most functions can - * be found in the files where the functions are located. - */ - - -/* Various modes of operation, that are visible to applications because - * they are used for unknown chunk location. - */ -#define PNG_HAVE_IHDR 0x01 -#define PNG_HAVE_PLTE 0x02 -#define PNG_HAVE_IDAT 0x04 -#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ -#define PNG_HAVE_IEND 0x10 - -#if defined(PNG_INTERNAL) - -/* More modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. - */ -#define PNG_HAVE_gAMA 0x20 -#define PNG_HAVE_cHRM 0x40 -#define PNG_HAVE_sRGB 0x80 -#define PNG_HAVE_CHUNK_HEADER 0x100 -#define PNG_WROTE_tIME 0x200 -#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 -#define PNG_BACKGROUND_IS_GRAY 0x800 -#define PNG_HAVE_PNG_SIGNATURE 0x1000 -#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ - -/* Flags for the transformations the PNG library does on the image data */ -#define PNG_BGR 0x0001 -#define PNG_INTERLACE 0x0002 -#define PNG_PACK 0x0004 -#define PNG_SHIFT 0x0008 -#define PNG_SWAP_BYTES 0x0010 -#define PNG_INVERT_MONO 0x0020 -#define PNG_DITHER 0x0040 -#define PNG_BACKGROUND 0x0080 -#define PNG_BACKGROUND_EXPAND 0x0100 - /* 0x0200 unused */ -#define PNG_16_TO_8 0x0400 -#define PNG_RGBA 0x0800 -#define PNG_EXPAND 0x1000 -#define PNG_GAMMA 0x2000 -#define PNG_GRAY_TO_RGB 0x4000 -#define PNG_FILLER 0x8000L -#define PNG_PACKSWAP 0x10000L -#define PNG_SWAP_ALPHA 0x20000L -#define PNG_STRIP_ALPHA 0x40000L -#define PNG_INVERT_ALPHA 0x80000L -#define PNG_USER_TRANSFORM 0x100000L -#define PNG_RGB_TO_GRAY_ERR 0x200000L -#define PNG_RGB_TO_GRAY_WARN 0x400000L -#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ - /* 0x800000L Unused */ -#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - -/* Flags for png_create_struct */ -#define PNG_STRUCT_PNG 0x0001 -#define PNG_STRUCT_INFO 0x0002 - -/* Scaling factor for filter heuristic weighting calculations */ -#define PNG_WEIGHT_SHIFT 8 -#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) -#define PNG_COST_SHIFT 3 -#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) - -/* Flags for the png_ptr->flags rather than declaring a byte for each one */ -#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 -#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 -#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 -#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 -#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 -#define PNG_FLAG_ZLIB_FINISHED 0x0020 -#define PNG_FLAG_ROW_INIT 0x0040 -#define PNG_FLAG_FILLER_AFTER 0x0080 -#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 -#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 -#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 -#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 -#define PNG_FLAG_FREE_PLTE 0x1000 -#define PNG_FLAG_FREE_TRNS 0x2000 -#define PNG_FLAG_FREE_HIST 0x4000 -#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L -#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L -#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L -#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L -#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L -#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L -#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ - /* 0x800000L unused */ - /* 0x1000000L unused */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - -#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ - PNG_FLAG_CRC_ANCILLARY_NOWARN) - -#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ - PNG_FLAG_CRC_CRITICAL_IGNORE) - -#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ - PNG_FLAG_CRC_CRITICAL_MASK) - -/* Save typing and make code easier to understand */ - -#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ - abs((int)((c1).green) - (int)((c2).green)) + \ - abs((int)((c1).blue) - (int)((c2).blue))) - -/* Added to libpng-1.2.6 JB */ -#define PNG_ROWBYTES(pixel_bits, width) \ - ((pixel_bits) >= 8 ? \ - ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \ - (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) ) - -/* PNG_OUT_OF_RANGE returns true if value is outside the range - * ideal-delta..ideal+delta. Each argument is evaluated twice. - * "ideal" and "delta" should be constants, normally simple - * integers, "value" a variable. Added to libpng-1.2.6 JB - */ -#define PNG_OUT_OF_RANGE(value, ideal, delta) \ - ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) - -/* Variables declared in png.c - only it needs to define PNG_NO_EXTERN */ -#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) -/* Place to hold the signature string for a PNG file. */ -#ifdef PNG_USE_GLOBAL_ARRAYS - PNG_EXPORT_VAR (PNG_CONST png_byte FARDATA) png_sig[8]; -#else -#endif -#endif /* PNG_NO_EXTERN */ - -/* Constant strings for known chunk types. If you need to add a chunk, - * define the name here, and add an invocation of the macro in png.c and - * wherever it's needed. - */ -#define PNG_IHDR png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} -#define PNG_IDAT png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} -#define PNG_IEND png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} -#define PNG_PLTE png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} -#define PNG_bKGD png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} -#define PNG_cHRM png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} -#define PNG_gAMA png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} -#define PNG_hIST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} -#define PNG_iCCP png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} -#define PNG_iTXt png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} -#define PNG_oFFs png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} -#define PNG_pCAL png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} -#define PNG_sCAL png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} -#define PNG_pHYs png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} -#define PNG_sBIT png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} -#define PNG_sPLT png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} -#define PNG_sRGB png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} -#define PNG_tEXt png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} -#define PNG_tIME png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} -#define PNG_tRNS png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} -#define PNG_zTXt png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} - -#ifdef PNG_USE_GLOBAL_ARRAYS -PNG_EXPORT_VAR (png_byte FARDATA) png_IHDR[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_IDAT[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_IEND[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_PLTE[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_bKGD[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_cHRM[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_gAMA[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_hIST[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_iCCP[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_iTXt[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_oFFs[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_pCAL[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sCAL[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_pHYs[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sBIT[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sPLT[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_sRGB[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_tEXt[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_tIME[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_tRNS[5]; -PNG_EXPORT_VAR (png_byte FARDATA) png_zTXt[5]; -#endif /* PNG_USE_GLOBAL_ARRAYS */ - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Initialize png_ptr struct for reading, and allocate any other memory. - * (old interface - DEPRECATED - use png_create_read_struct instead). - */ -extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); -#undef png_read_init -#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ - PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); -#endif - -extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size)); -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t - png_info_size)); -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Initialize png_ptr struct for writing, and allocate any other memory. - * (old interface - DEPRECATED - use png_create_write_struct instead). - */ -extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); -#undef png_write_init -#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ - PNG_LIBPNG_VER_STRING, png_sizeof(png_struct)); -#endif - -extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size)); -extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t - png_info_size)); - -/* Allocate memory for an internal libpng struct */ -PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); - -/* Free memory from internal libpng struct */ -PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); - -PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr - malloc_fn, png_voidp mem_ptr)); -PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, - png_free_ptr free_fn, png_voidp mem_ptr)); - -/* Free any memory that info_ptr points to and reset struct. */ -PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -#ifndef PNG_1_0_X -/* Function to allocate memory for zlib. */ -PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); - -/* Function to free memory for zlib */ -PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); - -#ifdef PNG_SIZE_T -/* Function to convert a sizeof an item to png_sizeof item */ - PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size)); -#endif - -/* Next four functions are used internally as callbacks. PNGAPI is required - * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. - */ - -PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)); -#endif - -PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -#if !defined(PNG_NO_STDIO) -PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); -#endif -#endif -#else /* PNG_1_0_X */ -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)); -#endif -#endif /* PNG_1_0_X */ - -/* Reset the CRC variable */ -PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); - -/* Write the "data" buffer to whatever output you are using. */ -PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); - -/* Read data from whatever input you are using into the "data" buffer */ -PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); - -/* Read bytes into buf, and update png_ptr->crc */ -PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, - png_size_t length)); - -/* Decompress data in a chunk that uses compression */ -#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ - defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) -PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, - int comp_type, png_size_t chunklength, - png_size_t prefix_length, png_size_t *data_length)); -#endif - -/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ -PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); - -/* Read the CRC from the file and compare it to the libpng calculated CRC */ -PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); - -/* Calculate the CRC over a section of data. Note that we are only - * passing a maximum of 64K on systems that have this as a memory limit, - * since this is the maximum buffer size we can specify. - */ -PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, - png_size_t length)); - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); -#endif - -/* Simple function to write the signature */ -PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); - -/* Write various chunks */ - -/* Write the IHDR chunk, and update the png_struct with the necessary - * information. - */ -PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, - png_uint_32 height, - int bit_depth, int color_type, int compression_method, int filter_method, - int interlace_method)); - -PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, - png_uint_32 num_pal)); - -PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); - -PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); - -#if defined(PNG_WRITE_gAMA_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point - file_gamma)); -#endif -#endif - -#if defined(PNG_WRITE_sBIT_SUPPORTED) -PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, - int color_type)); -#endif - -#if defined(PNG_WRITE_cHRM_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, - double white_x, double white_y, - double red_x, double red_y, double green_x, double green_y, - double blue_x, double blue_y)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif -#endif - -#if defined(PNG_WRITE_sRGB_SUPPORTED) -PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, - int intent)); -#endif - -#if defined(PNG_WRITE_iCCP_SUPPORTED) -PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, - png_charp name, int compression_type, - png_charp profile, int proflen)); - /* Note to maintainer: profile should be png_bytep */ -#endif - -#if defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_sPLT_tp palette)); -#endif - -#if defined(PNG_WRITE_tRNS_SUPPORTED) -PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, - png_color_16p values, int number, int color_type)); -#endif - -#if defined(PNG_WRITE_bKGD_SUPPORTED) -PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, - png_color_16p values, int color_type)); -#endif - -#if defined(PNG_WRITE_hIST_SUPPORTED) -PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, - int num_hist)); -#endif - -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, - png_charp key, png_charpp new_key)); -#endif - -#if defined(PNG_WRITE_tEXt_SUPPORTED) -PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len)); -#endif - -#if defined(PNG_WRITE_zTXt_SUPPORTED) -PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len, int compression)); -#endif - -#if defined(PNG_WRITE_iTXt_SUPPORTED) -PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, - int compression, png_charp key, png_charp lang, png_charp lang_key, - png_charp text)); -#endif - -#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ -PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)); -#endif - -#if defined(PNG_WRITE_oFFs_SUPPORTED) -PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type)); -#endif - -#if defined(PNG_WRITE_pCAL_SUPPORTED) -PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, - png_int_32 X0, png_int_32 X1, int type, int nparams, - png_charp units, png_charpp params)); -#endif - -#if defined(PNG_WRITE_pHYs_SUPPORTED) -PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, - png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, - int unit_type)); -#endif - -#if defined(PNG_WRITE_tIME_SUPPORTED) -PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, - png_timep mod_time)); -#endif - -#if defined(PNG_WRITE_sCAL_SUPPORTED) -#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) -PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, - int unit, double width, double height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, - int unit, png_charp width, png_charp height)); -#endif -#endif -#endif - -/* Called when finished processing a row of data */ -PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); - -/* Internal use only. Called before first row of data */ -PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); - -#if defined(PNG_READ_GAMMA_SUPPORTED) -PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); -#endif - -/* Combine a row of data, dealing with alpha, etc. if requested */ -PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, - int mask)); - -#if defined(PNG_READ_INTERLACING_SUPPORTED) -/* Expand an interlaced row */ -/* OLD pre-1.0.9 interface: -PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass, png_uint_32 transformations)); - */ -PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); -#endif - -/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ - -#if defined(PNG_WRITE_INTERLACING_SUPPORTED) -/* Grab pixels out of a row for an interlaced pass */ -PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass)); -#endif - -/* Unfilter a row */ -PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, - png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); - -/* Choose the best filter to use and filter the row data */ -PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, - png_row_infop row_info)); - -/* Write out the filtered row. */ -PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, - png_bytep filtered_row)); -/* Finish a row while reading, dealing with interlacing passes, etc. */ -PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); - -/* Initialize the row buffers, etc. */ -PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); -/* Optional call to update the users info structure */ -PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -/* These are the functions that do the transformations */ -#if defined(PNG_READ_FILLER_SUPPORTED) -PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 filler, png_uint_32 flags)); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ - defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 flags)); -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) -PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop - row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) -PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) -PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) -PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p sig_bits)); -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) -PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) -PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, - png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); - -# if defined(PNG_CORRECT_PALETTE_SUPPORTED) -PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette)); -# endif -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_WRITE_PACK_SUPPORTED) -PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 bit_depth)); -#endif - -#if defined(PNG_WRITE_SHIFT_SUPPORTED) -PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p bit_depth)); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) -#if defined(PNG_READ_GAMMA_SUPPORTED) -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background, - png_color_16p background_1, - png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, - png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, - png_uint_16pp gamma_16_to_1, int gamma_shift)); -#else -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background)); -#endif -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) -PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, - png_bytep gamma_table, png_uint_16pp gamma_16_table, - int gamma_shift)); -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) -PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, - png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); -PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, - png_bytep row, png_color_16p trans_value)); -#endif - -/* The following decodes the appropriate chunks, and does error correction, - * then calls the appropriate callback for the chunk if it is valid. - */ - -/* Decode the IHDR chunk */ -PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); - -#if defined(PNG_READ_bKGD_SUPPORTED) -PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_cHRM_SUPPORTED) -PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_gAMA_SUPPORTED) -PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_hIST_SUPPORTED) -PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_iCCP_SUPPORTED) -extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#if defined(PNG_READ_iTXt_SUPPORTED) -PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_oFFs_SUPPORTED) -PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_pCAL_SUPPORTED) -PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_pHYs_SUPPORTED) -PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_sBIT_SUPPORTED) -PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_sCAL_SUPPORTED) -PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_sPLT_SUPPORTED) -extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#if defined(PNG_READ_sRGB_SUPPORTED) -PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_tEXt_SUPPORTED) -PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_tIME_SUPPORTED) -PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_tRNS_SUPPORTED) -PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_zTXt_SUPPORTED) -PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); - -PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, - png_bytep chunk_name)); - -/* Handle the transformations for reading and writing */ -PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); - -PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, - png_uint_32 length)); -PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)); -PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)); -PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); -PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); -#if defined(PNG_READ_tEXt_SUPPORTED) -PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) -PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) -PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); -PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) -#if defined(PNG_MMX_CODE_SUPPORTED) -/* png.c */ /* PRIVATE */ -PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); -#endif -#endif - -#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) -PNG_EXTERN png_uint_32 png_get_pixels_per_inch PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN png_uint_32 png_get_x_pixels_per_inch PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN png_uint_32 png_get_y_pixels_per_inch PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN float png_get_x_offset_inches PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -PNG_EXTERN float png_get_y_offset_inches PNGARG((png_structp png_ptr, -png_infop info_ptr)); - -#if defined(PNG_pHYs_SUPPORTED) -PNG_EXTERN png_uint_32 png_get_pHYs_dpi PNGARG((png_structp png_ptr, -png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ - -/* Read the chunk header (length + type name) */ -PNG_EXTERN png_uint_32 png_read_chunk_header PNGARG((png_structp png_ptr)); - -/* Added at libpng version 1.2.34 */ -#if defined(PNG_cHRM_SUPPORTED) -PNG_EXTERN int png_check_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif - -#if defined(PNG_cHRM_SUPPORTED) -#if !defined(PNG_NO_CHECK_cHRM) -/* Added at libpng version 1.2.34 */ -PNG_EXTERN void png_64bit_product (long v1, long v2, unsigned long *hi_product, - unsigned long *lo_product); -#endif -#endif - -/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -#endif /* PNG_INTERNAL */ - -#ifdef __cplusplus -} -#endif - -#endif /* PNG_VERSION_INFO_ONLY */ -/* Do not put anything past this line */ -#endif /* PNG_H */ diff --git a/src/3rdparty/libpng/pngbar.jpg b/src/3rdparty/libpng/pngbar.jpg deleted file mode 100644 index 70ba8d8..0000000 Binary files a/src/3rdparty/libpng/pngbar.jpg and /dev/null differ diff --git a/src/3rdparty/libpng/pngbar.png b/src/3rdparty/libpng/pngbar.png deleted file mode 100644 index 49798c8..0000000 Binary files a/src/3rdparty/libpng/pngbar.png and /dev/null differ diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h deleted file mode 100644 index c1c1d92..0000000 --- a/src/3rdparty/libpng/pngconf.h +++ /dev/null @@ -1,1518 +0,0 @@ - -/* pngconf.h - machine configurable file for libpng - * - * libpng version 1.2.40 - September 10, 2009 - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -/* Any machine specific code is near the front of this file, so if you - * are configuring libpng for a machine, you may want to read the section - * starting here down to where it starts to typedef png_color, png_text, - * and png_info. - */ - -#ifndef PNGCONF_H -#define PNGCONF_H - -#define PNG_1_2_X - -/* - * PNG_USER_CONFIG has to be defined on the compiler command line. This - * includes the resource compiler for Windows DLL configurations. - */ -#ifdef PNG_USER_CONFIG -# ifndef PNG_USER_PRIVATEBUILD -# define PNG_USER_PRIVATEBUILD -# endif -#include "pngusr.h" -#endif - -/* PNG_CONFIGURE_LIBPNG is set by the "configure" script. */ -#ifdef PNG_CONFIGURE_LIBPNG -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#endif - -/* - * Added at libpng-1.2.8 - * - * If you create a private DLL you need to define in "pngusr.h" the followings: - * #define PNG_USER_PRIVATEBUILD - * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons." - * #define PNG_USER_DLLFNAME_POSTFIX - * e.g. // private DLL "libpng13gx.dll" - * #define PNG_USER_DLLFNAME_POSTFIX "gx" - * - * The following macros are also at your disposal if you want to complete the - * DLL VERSIONINFO structure. - * - PNG_USER_VERSIONINFO_COMMENTS - * - PNG_USER_VERSIONINFO_COMPANYNAME - * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS - */ - -#ifdef __STDC__ -#ifdef SPECIALBUILD -# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\ - are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.") -#endif - -#ifdef PRIVATEBUILD -# pragma message("PRIVATEBUILD is deprecated.\ - Use PNG_USER_PRIVATEBUILD instead.") -# define PNG_USER_PRIVATEBUILD PRIVATEBUILD -#endif -#endif /* __STDC__ */ - -#ifndef PNG_VERSION_INFO_ONLY - -/* End of material added to libpng-1.2.8 */ - -/* Added at libpng-1.2.19, removed at libpng-1.2.20 because it caused trouble - Restored at libpng-1.2.21 */ -#if !defined(PNG_NO_WARN_UNINITIALIZED_ROW) && \ - !defined(PNG_WARN_UNINITIALIZED_ROW) -# define PNG_WARN_UNINITIALIZED_ROW 1 -#endif -/* End of material added at libpng-1.2.19/1.2.21 */ - -/* This is the size of the compression buffer, and thus the size of - * an IDAT chunk. Make this whatever size you feel is best for your - * machine. One of these will be allocated per png_struct. When this - * is full, it writes the data to the disk, and does some other - * calculations. Making this an extremely small size will slow - * the library down, but you may want to experiment to determine - * where it becomes significant, if you are concerned with memory - * usage. Note that zlib allocates at least 32Kb also. For readers, - * this describes the size of the buffer available to read the data in. - * Unless this gets smaller than the size of a row (compressed), - * it should not make much difference how big this is. - */ - -#ifndef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 8192 -#endif - -/* Enable if you want a write-only libpng */ - -#ifndef PNG_NO_READ_SUPPORTED -# define PNG_READ_SUPPORTED -#endif - -/* Enable if you want a read-only libpng */ - -#ifndef PNG_NO_WRITE_SUPPORTED -# define PNG_WRITE_SUPPORTED -#endif - -/* Enabled by default in 1.2.0. You can disable this if you don't need to - support PNGs that are embedded in MNG datastreams */ -#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES) -# ifndef PNG_MNG_FEATURES_SUPPORTED -# define PNG_MNG_FEATURES_SUPPORTED -# endif -#endif - -#ifndef PNG_NO_FLOATING_POINT_SUPPORTED -# ifndef PNG_FLOATING_POINT_SUPPORTED -# define PNG_FLOATING_POINT_SUPPORTED -# endif -#endif - -/* If you are running on a machine where you cannot allocate more - * than 64K of memory at once, uncomment this. While libpng will not - * normally need that much memory in a chunk (unless you load up a very - * large file), zlib needs to know how big of a chunk it can use, and - * libpng thus makes sure to check any memory allocation to verify it - * will fit into memory. -#define PNG_MAX_MALLOC_64K - */ -#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) -# define PNG_MAX_MALLOC_64K -#endif - -/* Special munging to support doing things the 'cygwin' way: - * 'Normal' png-on-win32 defines/defaults: - * PNG_BUILD_DLL -- building dll - * PNG_USE_DLL -- building an application, linking to dll - * (no define) -- building static library, or building an - * application and linking to the static lib - * 'Cygwin' defines/defaults: - * PNG_BUILD_DLL -- (ignored) building the dll - * (no define) -- (ignored) building an application, linking to the dll - * PNG_STATIC -- (ignored) building the static lib, or building an - * application that links to the static lib. - * ALL_STATIC -- (ignored) building various static libs, or building an - * application that links to the static libs. - * Thus, - * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and - * this bit of #ifdefs will define the 'correct' config variables based on - * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but - * unnecessary. - * - * Also, the precedence order is: - * ALL_STATIC (since we can't #undef something outside our namespace) - * PNG_BUILD_DLL - * PNG_STATIC - * (nothing) == PNG_USE_DLL - * - * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent - * of auto-import in binutils, we no longer need to worry about - * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, - * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes - * to __declspec() stuff. However, we DO need to worry about - * PNG_BUILD_DLL and PNG_STATIC because those change some defaults - * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed. - */ -#if defined(__CYGWIN__) -# if defined(ALL_STATIC) -# if defined(PNG_BUILD_DLL) -# undef PNG_BUILD_DLL -# endif -# if defined(PNG_USE_DLL) -# undef PNG_USE_DLL -# endif -# if defined(PNG_DLL) -# undef PNG_DLL -# endif -# if !defined(PNG_STATIC) -# define PNG_STATIC -# endif -# else -# if defined (PNG_BUILD_DLL) -# if defined(PNG_STATIC) -# undef PNG_STATIC -# endif -# if defined(PNG_USE_DLL) -# undef PNG_USE_DLL -# endif -# if !defined(PNG_DLL) -# define PNG_DLL -# endif -# else -# if defined(PNG_STATIC) -# if defined(PNG_USE_DLL) -# undef PNG_USE_DLL -# endif -# if defined(PNG_DLL) -# undef PNG_DLL -# endif -# else -# if !defined(PNG_USE_DLL) -# define PNG_USE_DLL -# endif -# if !defined(PNG_DLL) -# define PNG_DLL -# endif -# endif -# endif -# endif -#endif - -/* This protects us against compilers that run on a windowing system - * and thus don't have or would rather us not use the stdio types: - * stdin, stdout, and stderr. The only one currently used is stderr - * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will - * prevent these from being compiled and used. #defining PNG_NO_STDIO - * will also prevent these, plus will prevent the entire set of stdio - * macros and functions (FILE *, printf, etc.) from being compiled and used, - * unless (PNG_DEBUG > 0) has been #defined. - * - * #define PNG_NO_CONSOLE_IO - * #define PNG_NO_STDIO - */ - -#if defined(_WIN32_WCE) -# include - /* Console I/O functions are not supported on WindowsCE */ -# define PNG_NO_CONSOLE_IO - /* abort() may not be supported on some/all Windows CE platforms */ -# define PNG_ABORT() exit(-1) -# ifdef PNG_DEBUG -# undef PNG_DEBUG -# endif -#endif - -#ifdef PNG_BUILD_DLL -# ifndef PNG_CONSOLE_IO_SUPPORTED -# ifndef PNG_NO_CONSOLE_IO -# define PNG_NO_CONSOLE_IO -# endif -# endif -#endif - -# ifdef PNG_NO_STDIO -# ifndef PNG_NO_CONSOLE_IO -# define PNG_NO_CONSOLE_IO -# endif -# ifdef PNG_DEBUG -# if (PNG_DEBUG > 0) -# include -# endif -# endif -# else -# if !defined(_WIN32_WCE) -/* "stdio.h" functions are not supported on WindowsCE */ -# include -# endif -# endif - -/* This macro protects us against machines that don't have function - * prototypes (ie K&R style headers). If your compiler does not handle - * function prototypes, define this macro and use the included ansi2knr. - * I've always been able to use _NO_PROTO as the indicator, but you may - * need to drag the empty declaration out in front of here, or change the - * ifdef to suit your own needs. - */ -#ifndef PNGARG - -#ifdef OF /* zlib prototype munger */ -# define PNGARG(arglist) OF(arglist) -#else - -#ifdef _NO_PROTO -# define PNGARG(arglist) () -# ifndef PNG_TYPECAST_NULL -# define PNG_TYPECAST_NULL -# endif -#else -# define PNGARG(arglist) arglist -#endif /* _NO_PROTO */ - - -#endif /* OF */ - -#endif /* PNGARG */ - -/* Try to determine if we are compiling on a Mac. Note that testing for - * just __MWERKS__ is not good enough, because the Codewarrior is now used - * on non-Mac platforms. - */ -#ifndef MACOS -# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ - defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) -# define MACOS -# endif -#endif - -/* enough people need this for various reasons to include it here */ -#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) -# include -#endif - -#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) -# define PNG_SETJMP_SUPPORTED -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* This is an attempt to force a single setjmp behaviour on Linux. If - * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. - * - * You can bypass this test if you know that your application uses exactly - * the same setjmp.h that was included when libpng was built. Only define - * PNG_SKIP_SETJMP_CHECK while building your application, prior to the - * application's '#include "png.h"'. Don't define PNG_SKIP_SETJMP_CHECK - * while building a separate libpng library for general use. - */ - -# ifndef PNG_SKIP_SETJMP_CHECK -# ifdef __linux__ -# ifdef _BSD_SOURCE -# define PNG_SAVE_BSD_SOURCE -# undef _BSD_SOURCE -# endif -# ifdef _SETJMP_H - /* If you encounter a compiler error here, see the explanation - * near the end of INSTALL. - */ - __pngconf.h__ in libpng already includes setjmp.h; - __dont__ include it again.; -# endif -# endif /* __linux__ */ -# endif /* PNG_SKIP_SETJMP_CHECK */ - - /* include setjmp.h for error handling */ -# include - -# ifdef __linux__ -# ifdef PNG_SAVE_BSD_SOURCE -# ifndef _BSD_SOURCE -# define _BSD_SOURCE -# endif -# undef PNG_SAVE_BSD_SOURCE -# endif -# endif /* __linux__ */ -#endif /* PNG_SETJMP_SUPPORTED */ - -#if defined(BSD) && !defined(VXWORKS) -# include -#else -# include -#endif - -/* Other defines for things like memory and the like can go here. */ -#ifdef PNG_INTERNAL - -#include - -/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which - * aren't usually used outside the library (as far as I know), so it is - * debatable if they should be exported at all. In the future, when it is - * possible to have run-time registry of chunk-handling functions, some of - * these will be made available again. -#define PNG_EXTERN extern - */ -#define PNG_EXTERN - -/* Other defines specific to compilers can go here. Try to keep - * them inside an appropriate ifdef/endif pair for portability. - */ - -#if defined(PNG_FLOATING_POINT_SUPPORTED) -# if defined(MACOS) - /* We need to check that hasn't already been included earlier - * as it seems it doesn't agree with , yet we should really use - * if possible. - */ -# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) -# include -# endif -# else -# include -# endif -# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) - /* Amiga SAS/C: We must include builtin FPU functions when compiling using - * MATH=68881 - */ -# include -# endif -#endif - -/* Codewarrior on NT has linking problems without this. */ -#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) -# define PNG_ALWAYS_EXTERN -#endif - -/* This provides the non-ANSI (far) memory allocation routines. */ -#if defined(__TURBOC__) && defined(__MSDOS__) -# include -# include -#endif - -/* I have no idea why is this necessary... */ -#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ - defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) -# include -#endif - -/* This controls how fine the dithering gets. As this allocates - * a largish chunk of memory (32K), those who are not as concerned - * with dithering quality can decrease some or all of these. - */ -#ifndef PNG_DITHER_RED_BITS -# define PNG_DITHER_RED_BITS 5 -#endif -#ifndef PNG_DITHER_GREEN_BITS -# define PNG_DITHER_GREEN_BITS 5 -#endif -#ifndef PNG_DITHER_BLUE_BITS -# define PNG_DITHER_BLUE_BITS 5 -#endif - -/* This controls how fine the gamma correction becomes when you - * are only interested in 8 bits anyway. Increasing this value - * results in more memory being used, and more pow() functions - * being called to fill in the gamma tables. Don't set this value - * less then 8, and even that may not work (I haven't tested it). - */ - -#ifndef PNG_MAX_GAMMA_8 -# define PNG_MAX_GAMMA_8 11 -#endif - -/* This controls how much a difference in gamma we can tolerate before - * we actually start doing gamma conversion. - */ -#ifndef PNG_GAMMA_THRESHOLD -# define PNG_GAMMA_THRESHOLD 0.05 -#endif - -#endif /* PNG_INTERNAL */ - -/* The following uses const char * instead of char * for error - * and warning message functions, so some compilers won't complain. - * If you do not want to use const, define PNG_NO_CONST here. - */ - -#ifndef PNG_NO_CONST -# define PNG_CONST const -#else -# define PNG_CONST -#endif - -/* The following defines give you the ability to remove code from the - * library that you will not be using. I wish I could figure out how to - * automate this, but I can't do that without making it seriously hard - * on the users. So if you are not using an ability, change the #define - * to and #undef, and that part of the library will not be compiled. If - * your linker can't find a function, you may want to make sure the - * ability is defined here. Some of these depend upon some others being - * defined. I haven't figured out all the interactions here, so you may - * have to experiment awhile to get everything to compile. If you are - * creating or using a shared library, you probably shouldn't touch this, - * as it will affect the size of the structures, and this will cause bad - * things to happen if the library and/or application ever change. - */ - -/* Any features you will not be using can be undef'ed here */ - -/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user - * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS - * on the compile line, then pick and choose which ones to define without - * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED - * if you only want to have a png-compliant reader/writer but don't need - * any of the extra transformations. This saves about 80 kbytes in a - * typical installation of the library. (PNG_NO_* form added in version - * 1.0.1c, for consistency) - */ - -/* The size of the png_text structure changed in libpng-1.0.6 when - * iTXt support was added. iTXt support was turned off by default through - * libpng-1.2.x, to support old apps that malloc the png_text structure - * instead of calling png_set_text() and letting libpng malloc it. It - * will be turned on by default in libpng-1.4.0. - */ - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -# ifndef PNG_NO_iTXt_SUPPORTED -# define PNG_NO_iTXt_SUPPORTED -# endif -# ifndef PNG_NO_READ_iTXt -# define PNG_NO_READ_iTXt -# endif -# ifndef PNG_NO_WRITE_iTXt -# define PNG_NO_WRITE_iTXt -# endif -#endif - -#if !defined(PNG_NO_iTXt_SUPPORTED) -# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt) -# define PNG_READ_iTXt -# endif -# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt) -# define PNG_WRITE_iTXt -# endif -#endif - -/* The following support, added after version 1.0.0, can be turned off here en - * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility - * with old applications that require the length of png_struct and png_info - * to remain unchanged. - */ - -#ifdef PNG_LEGACY_SUPPORTED -# define PNG_NO_FREE_ME -# define PNG_NO_READ_UNKNOWN_CHUNKS -# define PNG_NO_WRITE_UNKNOWN_CHUNKS -# define PNG_NO_HANDLE_AS_UNKNOWN -# define PNG_NO_READ_USER_CHUNKS -# define PNG_NO_READ_iCCP -# define PNG_NO_WRITE_iCCP -# define PNG_NO_READ_iTXt -# define PNG_NO_WRITE_iTXt -# define PNG_NO_READ_sCAL -# define PNG_NO_WRITE_sCAL -# define PNG_NO_READ_sPLT -# define PNG_NO_WRITE_sPLT -# define PNG_NO_INFO_IMAGE -# define PNG_NO_READ_RGB_TO_GRAY -# define PNG_NO_READ_USER_TRANSFORM -# define PNG_NO_WRITE_USER_TRANSFORM -# define PNG_NO_USER_MEM -# define PNG_NO_READ_EMPTY_PLTE -# define PNG_NO_MNG_FEATURES -# define PNG_NO_FIXED_POINT_SUPPORTED -#endif - -/* Ignore attempt to turn off both floating and fixed point support */ -#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ - !defined(PNG_NO_FIXED_POINT_SUPPORTED) -# define PNG_FIXED_POINT_SUPPORTED -#endif - -#ifndef PNG_NO_FREE_ME -# define PNG_FREE_ME_SUPPORTED -#endif - -#ifdef PNG_READ_SUPPORTED - -#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ - !defined(PNG_NO_READ_TRANSFORMS) -# define PNG_READ_TRANSFORMS_SUPPORTED -#endif - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -# ifndef PNG_NO_READ_EXPAND -# define PNG_READ_EXPAND_SUPPORTED -# endif -# ifndef PNG_NO_READ_SHIFT -# define PNG_READ_SHIFT_SUPPORTED -# endif -# ifndef PNG_NO_READ_PACK -# define PNG_READ_PACK_SUPPORTED -# endif -# ifndef PNG_NO_READ_BGR -# define PNG_READ_BGR_SUPPORTED -# endif -# ifndef PNG_NO_READ_SWAP -# define PNG_READ_SWAP_SUPPORTED -# endif -# ifndef PNG_NO_READ_PACKSWAP -# define PNG_READ_PACKSWAP_SUPPORTED -# endif -# ifndef PNG_NO_READ_INVERT -# define PNG_READ_INVERT_SUPPORTED -# endif -# ifndef PNG_NO_READ_DITHER -# define PNG_READ_DITHER_SUPPORTED -# endif -# ifndef PNG_NO_READ_BACKGROUND -# define PNG_READ_BACKGROUND_SUPPORTED -# endif -# ifndef PNG_NO_READ_16_TO_8 -# define PNG_READ_16_TO_8_SUPPORTED -# endif -# ifndef PNG_NO_READ_FILLER -# define PNG_READ_FILLER_SUPPORTED -# endif -# ifndef PNG_NO_READ_GAMMA -# define PNG_READ_GAMMA_SUPPORTED -# endif -# ifndef PNG_NO_READ_GRAY_TO_RGB -# define PNG_READ_GRAY_TO_RGB_SUPPORTED -# endif -# ifndef PNG_NO_READ_SWAP_ALPHA -# define PNG_READ_SWAP_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_READ_INVERT_ALPHA -# define PNG_READ_INVERT_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_READ_STRIP_ALPHA -# define PNG_READ_STRIP_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_READ_USER_TRANSFORM -# define PNG_READ_USER_TRANSFORM_SUPPORTED -# endif -# ifndef PNG_NO_READ_RGB_TO_GRAY -# define PNG_READ_RGB_TO_GRAY_SUPPORTED -# endif -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -#if !defined(PNG_NO_PROGRESSIVE_READ) && \ - !defined(PNG_PROGRESSIVE_READ_SUPPORTED) /* if you don't do progressive */ -# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ -#endif /* about interlacing capability! You'll */ - /* still have interlacing unless you change the following line: */ - -#define PNG_READ_INTERLACING_SUPPORTED /* required in PNG-compliant decoders */ - -#ifndef PNG_NO_READ_COMPOSITE_NODIV -# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ -# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ -# endif -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Deprecated, will be removed from version 2.0.0. - Use PNG_MNG_FEATURES_SUPPORTED instead. */ -#ifndef PNG_NO_READ_EMPTY_PLTE -# define PNG_READ_EMPTY_PLTE_SUPPORTED -#endif -#endif - -#endif /* PNG_READ_SUPPORTED */ - -#ifdef PNG_WRITE_SUPPORTED - -# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ - !defined(PNG_NO_WRITE_TRANSFORMS) -# define PNG_WRITE_TRANSFORMS_SUPPORTED -#endif - -#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -# ifndef PNG_NO_WRITE_SHIFT -# define PNG_WRITE_SHIFT_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_PACK -# define PNG_WRITE_PACK_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_BGR -# define PNG_WRITE_BGR_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_SWAP -# define PNG_WRITE_SWAP_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_PACKSWAP -# define PNG_WRITE_PACKSWAP_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_INVERT -# define PNG_WRITE_INVERT_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_FILLER -# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ -# endif -# ifndef PNG_NO_WRITE_SWAP_ALPHA -# define PNG_WRITE_SWAP_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_INVERT_ALPHA -# define PNG_WRITE_INVERT_ALPHA_SUPPORTED -# endif -# ifndef PNG_NO_WRITE_USER_TRANSFORM -# define PNG_WRITE_USER_TRANSFORM_SUPPORTED -# endif -#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ - -#if !defined(PNG_NO_WRITE_INTERLACING_SUPPORTED) && \ - !defined(PNG_WRITE_INTERLACING_SUPPORTED) -#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant - encoders, but can cause trouble - if left undefined */ -#endif - -#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ - !defined(PNG_WRITE_WEIGHTED_FILTER) && \ - defined(PNG_FLOATING_POINT_SUPPORTED) -# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED -#endif - -#ifndef PNG_NO_WRITE_FLUSH -# define PNG_WRITE_FLUSH_SUPPORTED -#endif - -#if defined(PNG_1_0_X) || defined (PNG_1_2_X) -/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ -#ifndef PNG_NO_WRITE_EMPTY_PLTE -# define PNG_WRITE_EMPTY_PLTE_SUPPORTED -#endif -#endif - -#endif /* PNG_WRITE_SUPPORTED */ - -#ifndef PNG_1_0_X -# ifndef PNG_NO_ERROR_NUMBERS -# define PNG_ERROR_NUMBERS_SUPPORTED -# endif -#endif /* PNG_1_0_X */ - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -# ifndef PNG_NO_USER_TRANSFORM_PTR -# define PNG_USER_TRANSFORM_PTR_SUPPORTED -# endif -#endif - -#ifndef PNG_NO_STDIO -# define PNG_TIME_RFC1123_SUPPORTED -#endif - -/* This adds extra functions in pngget.c for accessing data from the - * info pointer (added in version 0.99) - * png_get_image_width() - * png_get_image_height() - * png_get_bit_depth() - * png_get_color_type() - * png_get_compression_type() - * png_get_filter_type() - * png_get_interlace_type() - * png_get_pixel_aspect_ratio() - * png_get_pixels_per_meter() - * png_get_x_offset_pixels() - * png_get_y_offset_pixels() - * png_get_x_offset_microns() - * png_get_y_offset_microns() - */ -#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) -# define PNG_EASY_ACCESS_SUPPORTED -#endif - -/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 - * and removed from version 1.2.20. The following will be removed - * from libpng-1.4.0 -*/ - -#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_OPTIMIZED_CODE) -# ifndef PNG_OPTIMIZED_CODE_SUPPORTED -# define PNG_OPTIMIZED_CODE_SUPPORTED -# endif -#endif - -#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) -# ifndef PNG_ASSEMBLER_CODE_SUPPORTED -# define PNG_ASSEMBLER_CODE_SUPPORTED -# endif - -# if defined(__GNUC__) && defined(__x86_64__) && (__GNUC__ < 4) - /* work around 64-bit gcc compiler bugs in gcc-3.x */ -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_NO_MMX_CODE -# endif -# endif - -# if defined(__APPLE__) -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_NO_MMX_CODE -# endif -# endif - -# if (defined(__MWERKS__) && ((__MWERKS__ < 0x0900) || macintosh)) -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_NO_MMX_CODE -# endif -# endif - -# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) -# define PNG_MMX_CODE_SUPPORTED -# endif - -#endif -/* end of obsolete code to be removed from libpng-1.4.0 */ - -#if !defined(PNG_1_0_X) -#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) -# define PNG_USER_MEM_SUPPORTED -#endif -#endif /* PNG_1_0_X */ - -/* Added at libpng-1.2.6 */ -#if !defined(PNG_1_0_X) -#ifndef PNG_SET_USER_LIMITS_SUPPORTED -#if !defined(PNG_NO_SET_USER_LIMITS) && !defined(PNG_SET_USER_LIMITS_SUPPORTED) -# define PNG_SET_USER_LIMITS_SUPPORTED -#endif -#endif -#endif /* PNG_1_0_X */ - -/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter - * how large, set these limits to 0x7fffffffL - */ -#ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000L -#endif -#ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000L -#endif - -/* Added at libpng-1.2.34 and 1.4.0 */ -#ifndef PNG_STRING_NEWLINE -#define PNG_STRING_NEWLINE "\n" -#endif - -/* These are currently experimental features, define them if you want */ - -/* very little testing */ -/* -#ifdef PNG_READ_SUPPORTED -# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED -# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED -# endif -#endif -*/ - -/* This is only for PowerPC big-endian and 680x0 systems */ -/* some testing */ -/* -#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED -# define PNG_READ_BIG_ENDIAN_SUPPORTED -#endif -*/ - -/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ -/* -#define PNG_NO_POINTER_INDEXING -*/ - -/* These functions are turned off by default, as they will be phased out. */ -/* -#define PNG_USELESS_TESTS_SUPPORTED -#define PNG_CORRECT_PALETTE_SUPPORTED -*/ - -/* Any chunks you are not interested in, you can undef here. The - * ones that allocate memory may be expecially important (hIST, - * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info - * a bit smaller. - */ - -#if defined(PNG_READ_SUPPORTED) && \ - !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ - !defined(PNG_NO_READ_ANCILLARY_CHUNKS) -# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED -#endif - -#if defined(PNG_WRITE_SUPPORTED) && \ - !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ - !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) -# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED -#endif - -#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED - -#ifdef PNG_NO_READ_TEXT -# define PNG_NO_READ_iTXt -# define PNG_NO_READ_tEXt -# define PNG_NO_READ_zTXt -#endif -#ifndef PNG_NO_READ_bKGD -# define PNG_READ_bKGD_SUPPORTED -# define PNG_bKGD_SUPPORTED -#endif -#ifndef PNG_NO_READ_cHRM -# define PNG_READ_cHRM_SUPPORTED -# define PNG_cHRM_SUPPORTED -#endif -#ifndef PNG_NO_READ_gAMA -# define PNG_READ_gAMA_SUPPORTED -# define PNG_gAMA_SUPPORTED -#endif -#ifndef PNG_NO_READ_hIST -# define PNG_READ_hIST_SUPPORTED -# define PNG_hIST_SUPPORTED -#endif -#ifndef PNG_NO_READ_iCCP -# define PNG_READ_iCCP_SUPPORTED -# define PNG_iCCP_SUPPORTED -#endif -#ifndef PNG_NO_READ_iTXt -# ifndef PNG_READ_iTXt_SUPPORTED -# define PNG_READ_iTXt_SUPPORTED -# endif -# ifndef PNG_iTXt_SUPPORTED -# define PNG_iTXt_SUPPORTED -# endif -#endif -#ifndef PNG_NO_READ_oFFs -# define PNG_READ_oFFs_SUPPORTED -# define PNG_oFFs_SUPPORTED -#endif -#ifndef PNG_NO_READ_pCAL -# define PNG_READ_pCAL_SUPPORTED -# define PNG_pCAL_SUPPORTED -#endif -#ifndef PNG_NO_READ_sCAL -# define PNG_READ_sCAL_SUPPORTED -# define PNG_sCAL_SUPPORTED -#endif -#ifndef PNG_NO_READ_pHYs -# define PNG_READ_pHYs_SUPPORTED -# define PNG_pHYs_SUPPORTED -#endif -#ifndef PNG_NO_READ_sBIT -# define PNG_READ_sBIT_SUPPORTED -# define PNG_sBIT_SUPPORTED -#endif -#ifndef PNG_NO_READ_sPLT -# define PNG_READ_sPLT_SUPPORTED -# define PNG_sPLT_SUPPORTED -#endif -#ifndef PNG_NO_READ_sRGB -# define PNG_READ_sRGB_SUPPORTED -# define PNG_sRGB_SUPPORTED -#endif -#ifndef PNG_NO_READ_tEXt -# define PNG_READ_tEXt_SUPPORTED -# define PNG_tEXt_SUPPORTED -#endif -#ifndef PNG_NO_READ_tIME -# define PNG_READ_tIME_SUPPORTED -# define PNG_tIME_SUPPORTED -#endif -#ifndef PNG_NO_READ_tRNS -# define PNG_READ_tRNS_SUPPORTED -# define PNG_tRNS_SUPPORTED -#endif -#ifndef PNG_NO_READ_zTXt -# define PNG_READ_zTXt_SUPPORTED -# define PNG_zTXt_SUPPORTED -#endif -#ifndef PNG_NO_READ_OPT_PLTE -# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ -#endif /* optional PLTE chunk in RGB and RGBA images */ -#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ - defined(PNG_READ_zTXt_SUPPORTED) -# define PNG_READ_TEXT_SUPPORTED -# define PNG_TEXT_SUPPORTED -#endif - -#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ - -#ifndef PNG_NO_READ_UNKNOWN_CHUNKS -# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_UNKNOWN_CHUNKS_SUPPORTED -# endif -#endif -#if !defined(PNG_NO_READ_USER_CHUNKS) && \ - defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) -# define PNG_READ_USER_CHUNKS_SUPPORTED -# define PNG_USER_CHUNKS_SUPPORTED -# ifdef PNG_NO_READ_UNKNOWN_CHUNKS -# undef PNG_NO_READ_UNKNOWN_CHUNKS -# endif -# ifdef PNG_NO_HANDLE_AS_UNKNOWN -# undef PNG_NO_HANDLE_AS_UNKNOWN -# endif -#endif - -#ifndef PNG_NO_HANDLE_AS_UNKNOWN -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# endif -#endif - -#ifdef PNG_WRITE_SUPPORTED -#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED - -#ifdef PNG_NO_WRITE_TEXT -# define PNG_NO_WRITE_iTXt -# define PNG_NO_WRITE_tEXt -# define PNG_NO_WRITE_zTXt -#endif -#ifndef PNG_NO_WRITE_bKGD -# define PNG_WRITE_bKGD_SUPPORTED -# ifndef PNG_bKGD_SUPPORTED -# define PNG_bKGD_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_cHRM -# define PNG_WRITE_cHRM_SUPPORTED -# ifndef PNG_cHRM_SUPPORTED -# define PNG_cHRM_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_gAMA -# define PNG_WRITE_gAMA_SUPPORTED -# ifndef PNG_gAMA_SUPPORTED -# define PNG_gAMA_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_hIST -# define PNG_WRITE_hIST_SUPPORTED -# ifndef PNG_hIST_SUPPORTED -# define PNG_hIST_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_iCCP -# define PNG_WRITE_iCCP_SUPPORTED -# ifndef PNG_iCCP_SUPPORTED -# define PNG_iCCP_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_iTXt -# ifndef PNG_WRITE_iTXt_SUPPORTED -# define PNG_WRITE_iTXt_SUPPORTED -# endif -# ifndef PNG_iTXt_SUPPORTED -# define PNG_iTXt_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_oFFs -# define PNG_WRITE_oFFs_SUPPORTED -# ifndef PNG_oFFs_SUPPORTED -# define PNG_oFFs_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_pCAL -# define PNG_WRITE_pCAL_SUPPORTED -# ifndef PNG_pCAL_SUPPORTED -# define PNG_pCAL_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sCAL -# define PNG_WRITE_sCAL_SUPPORTED -# ifndef PNG_sCAL_SUPPORTED -# define PNG_sCAL_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_pHYs -# define PNG_WRITE_pHYs_SUPPORTED -# ifndef PNG_pHYs_SUPPORTED -# define PNG_pHYs_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sBIT -# define PNG_WRITE_sBIT_SUPPORTED -# ifndef PNG_sBIT_SUPPORTED -# define PNG_sBIT_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sPLT -# define PNG_WRITE_sPLT_SUPPORTED -# ifndef PNG_sPLT_SUPPORTED -# define PNG_sPLT_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_sRGB -# define PNG_WRITE_sRGB_SUPPORTED -# ifndef PNG_sRGB_SUPPORTED -# define PNG_sRGB_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_tEXt -# define PNG_WRITE_tEXt_SUPPORTED -# ifndef PNG_tEXt_SUPPORTED -# define PNG_tEXt_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_tIME -# define PNG_WRITE_tIME_SUPPORTED -# ifndef PNG_tIME_SUPPORTED -# define PNG_tIME_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_tRNS -# define PNG_WRITE_tRNS_SUPPORTED -# ifndef PNG_tRNS_SUPPORTED -# define PNG_tRNS_SUPPORTED -# endif -#endif -#ifndef PNG_NO_WRITE_zTXt -# define PNG_WRITE_zTXt_SUPPORTED -# ifndef PNG_zTXt_SUPPORTED -# define PNG_zTXt_SUPPORTED -# endif -#endif -#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ - defined(PNG_WRITE_zTXt_SUPPORTED) -# define PNG_WRITE_TEXT_SUPPORTED -# ifndef PNG_TEXT_SUPPORTED -# define PNG_TEXT_SUPPORTED -# endif -#endif - -#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ - -#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS -# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_UNKNOWN_CHUNKS_SUPPORTED -# endif -#endif - -#ifndef PNG_NO_HANDLE_AS_UNKNOWN -# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -# endif -#endif -#endif /* PNG_WRITE_SUPPORTED */ - -/* Turn this off to disable png_read_png() and - * png_write_png() and leave the row_pointers member - * out of the info structure. - */ -#ifndef PNG_NO_INFO_IMAGE -# define PNG_INFO_IMAGE_SUPPORTED -#endif - -/* need the time information for reading tIME chunks */ -#if defined(PNG_tIME_SUPPORTED) -# if !defined(_WIN32_WCE) - /* "time.h" functions are not supported on WindowsCE */ -# include -# endif -#endif - -/* Some typedefs to get us started. These should be safe on most of the - * common platforms. The typedefs should be at least as large as the - * numbers suggest (a png_uint_32 must be at least 32 bits long), but they - * don't have to be exactly that size. Some compilers dislike passing - * unsigned shorts as function parameters, so you may be better off using - * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may - * want to have unsigned int for png_uint_32 instead of unsigned long. - */ - -typedef unsigned long png_uint_32; -typedef long png_int_32; -typedef unsigned short png_uint_16; -typedef short png_int_16; -typedef unsigned char png_byte; - -/* This is usually size_t. It is typedef'ed just in case you need it to - change (I'm not sure if you will or not, so I thought I'd be safe) */ -#ifdef PNG_SIZE_T - typedef PNG_SIZE_T png_size_t; -# define png_sizeof(x) png_convert_size(sizeof(x)) -#else - typedef size_t png_size_t; -# define png_sizeof(x) sizeof(x) -#endif - -/* The following is needed for medium model support. It cannot be in the - * PNG_INTERNAL section. Needs modification for other compilers besides - * MSC. Model independent support declares all arrays and pointers to be - * large using the far keyword. The zlib version used must also support - * model independent data. As of version zlib 1.0.4, the necessary changes - * have been made in zlib. The USE_FAR_KEYWORD define triggers other - * changes that are needed. (Tim Wegner) - */ - -/* Separate compiler dependencies (problem here is that zlib.h always - defines FAR. (SJT) */ -#ifdef __BORLANDC__ -# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) -# define LDATA 1 -# else -# define LDATA 0 -# endif - /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ -# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) -# define PNG_MAX_MALLOC_64K -# if (LDATA != 1) -# ifndef FAR -# define FAR __far -# endif -# define USE_FAR_KEYWORD -# endif /* LDATA != 1 */ - /* Possibly useful for moving data out of default segment. - * Uncomment it if you want. Could also define FARDATA as - * const if your compiler supports it. (SJT) -# define FARDATA FAR - */ -# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ -#endif /* __BORLANDC__ */ - - -/* Suggest testing for specific compiler first before testing for - * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, - * making reliance oncertain keywords suspect. (SJT) - */ - -/* MSC Medium model */ -#if defined(FAR) -# if defined(M_I86MM) -# define USE_FAR_KEYWORD -# define FARDATA FAR -# include -# endif -#endif - -/* SJT: default case */ -#ifndef FAR -# define FAR -#endif - -/* At this point FAR is always defined */ -#ifndef FARDATA -# define FARDATA -#endif - -/* Typedef for floating-point numbers that are converted - to fixed-point with a multiple of 100,000, e.g., int_gamma */ -typedef png_int_32 png_fixed_point; - -/* Add typedefs for pointers */ -typedef void FAR * png_voidp; -typedef png_byte FAR * png_bytep; -typedef png_uint_32 FAR * png_uint_32p; -typedef png_int_32 FAR * png_int_32p; -typedef png_uint_16 FAR * png_uint_16p; -typedef png_int_16 FAR * png_int_16p; -typedef PNG_CONST char FAR * png_const_charp; -typedef char FAR * png_charp; -typedef png_fixed_point FAR * png_fixed_point_p; - -#ifndef PNG_NO_STDIO -#if defined(_WIN32_WCE) -typedef HANDLE png_FILE_p; -#else -typedef FILE * png_FILE_p; -#endif -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR * png_doublep; -#endif - -/* Pointers to pointers; i.e. arrays */ -typedef png_byte FAR * FAR * png_bytepp; -typedef png_uint_32 FAR * FAR * png_uint_32pp; -typedef png_int_32 FAR * FAR * png_int_32pp; -typedef png_uint_16 FAR * FAR * png_uint_16pp; -typedef png_int_16 FAR * FAR * png_int_16pp; -typedef PNG_CONST char FAR * FAR * png_const_charpp; -typedef char FAR * FAR * png_charpp; -typedef png_fixed_point FAR * FAR * png_fixed_point_pp; -#ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR * FAR * png_doublepp; -#endif - -/* Pointers to pointers to pointers; i.e., pointer to array */ -typedef char FAR * FAR * FAR * png_charppp; - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* SPC - Is this stuff deprecated? */ -/* It'll be removed as of libpng-1.4.0 - GR-P */ -/* libpng typedefs for types in zlib. If zlib changes - * or another compression library is used, then change these. - * Eliminates need to change all the source files. - */ -typedef charf * png_zcharp; -typedef charf * FAR * png_zcharpp; -typedef z_stream FAR * png_zstreamp; -#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */ - -/* - * Define PNG_BUILD_DLL if the module being built is a Windows - * LIBPNG DLL. - * - * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. - * It is equivalent to Microsoft predefined macro _DLL that is - * automatically defined when you compile using the share - * version of the CRT (C Run-Time library) - * - * The cygwin mods make this behavior a little different: - * Define PNG_BUILD_DLL if you are building a dll for use with cygwin - * Define PNG_STATIC if you are building a static library for use with cygwin, - * -or- if you are building an application that you want to link to the - * static library. - * PNG_USE_DLL is defined by default (no user action needed) unless one of - * the other flags is defined. - */ - -#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) -# define PNG_DLL -#endif -/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. - * When building a static lib, default to no GLOBAL ARRAYS, but allow - * command-line override - */ -#if defined(__CYGWIN__) -# if !defined(PNG_STATIC) -# if defined(PNG_USE_GLOBAL_ARRAYS) -# undef PNG_USE_GLOBAL_ARRAYS -# endif -# if !defined(PNG_USE_LOCAL_ARRAYS) -# define PNG_USE_LOCAL_ARRAYS -# endif -# else -# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) -# if defined(PNG_USE_GLOBAL_ARRAYS) -# undef PNG_USE_GLOBAL_ARRAYS -# endif -# endif -# endif -# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) -# define PNG_USE_LOCAL_ARRAYS -# endif -#endif - -/* Do not use global arrays (helps with building DLL's) - * They are no longer used in libpng itself, since version 1.0.5c, - * but might be required for some pre-1.0.5c applications. - */ -#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) -# if defined(PNG_NO_GLOBAL_ARRAYS) || \ - (defined(__GNUC__) && defined(PNG_DLL)) || defined(_MSC_VER) -# define PNG_USE_LOCAL_ARRAYS -# else -# define PNG_USE_GLOBAL_ARRAYS -# endif -#endif - -#if defined(__CYGWIN__) -# undef PNGAPI -# define PNGAPI __cdecl -# undef PNG_IMPEXP -# define PNG_IMPEXP -#endif - -/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", - * you may get warnings regarding the linkage of png_zalloc and png_zfree. - * Don't ignore those warnings; you must also reset the default calling - * convention in your compiler to match your PNGAPI, and you must build - * zlib and your applications the same way you build libpng. - */ - -#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) -# ifndef PNG_NO_MODULEDEF -# define PNG_NO_MODULEDEF -# endif -#endif - -#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) -# define PNG_IMPEXP -#endif - -#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ - (( defined(_Windows) || defined(_WINDOWS) || \ - defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) - -# ifndef PNGAPI -# if (defined(__GNUC__) && defined(__arm__)) || defined (__ARMCC__) -# define PNGAPI -# elif defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) || defined(__WINSCW__) -# define PNGAPI __cdecl -# else -# define PNGAPI _cdecl -# endif -# endif - -# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ - 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) -# define PNG_IMPEXP -# endif - -# if !defined(PNG_IMPEXP) - -# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol -# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol - - /* Borland/Microsoft */ -# if defined(_MSC_VER) || defined(__BORLANDC__) -# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) -# define PNG_EXPORT PNG_EXPORT_TYPE1 -# else -# define PNG_EXPORT PNG_EXPORT_TYPE2 -# if defined(PNG_BUILD_DLL) -# define PNG_IMPEXP __export -# else -# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in - VC++ */ -# endif /* Exists in Borland C++ for - C++ classes (== huge) */ -# endif -# endif - -# if !defined(PNG_IMPEXP) -# if defined(PNG_BUILD_DLL) -# define PNG_IMPEXP __declspec(dllexport) -# else -# define PNG_IMPEXP __declspec(dllimport) -# endif -# endif -# endif /* PNG_IMPEXP */ -#else /* !(DLL || non-cygwin WINDOWS) */ -# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) -# ifndef PNGAPI -# define PNGAPI _System -# endif -# else -# if 0 /* ... other platforms, with other meanings */ -# endif -# endif - -# if !defined(PNG_IMPEXP) -# include -# if defined(QT_VISIBILITY_AVAILABLE) -# define PNG_IMPEXP __attribute__((visibility("default"))) -# endif -# endif - -#endif - -#ifndef PNGAPI -# define PNGAPI -#endif -#ifndef PNG_IMPEXP -# define PNG_IMPEXP -#endif - -#ifdef PNG_BUILDSYMS -# ifndef PNG_EXPORT -# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END -# endif -# ifdef PNG_USE_GLOBAL_ARRAYS -# ifndef PNG_EXPORT_VAR -# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT -# endif -# endif -#endif - -#ifndef PNG_EXPORT -# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol -#endif - -#ifdef PNG_USE_GLOBAL_ARRAYS -# ifndef PNG_EXPORT_VAR -# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type -# endif -#endif - -/* User may want to use these so they are not in PNG_INTERNAL. Any library - * functions that are passed far data must be model independent. - */ - -#ifndef PNG_ABORT -# define PNG_ABORT() abort() -#endif - -#ifdef PNG_SETJMP_SUPPORTED -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#else -# define png_jmpbuf(png_ptr) \ - (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) -#endif - -#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ -/* use this to make far-to-near assignments */ -# define CHECK 1 -# define NOCHECK 0 -# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) -# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) -# define png_snprintf _fsnprintf /* Added to v 1.2.19 */ -# define png_strlen _fstrlen -# define png_memcmp _fmemcmp /* SJT: added */ -# define png_memcpy _fmemcpy -# define png_memset _fmemset -#else /* use the usual functions */ -# define CVT_PTR(ptr) (ptr) -# define CVT_PTR_NOCHECK(ptr) (ptr) -# ifndef PNG_NO_SNPRINTF -# ifdef _MSC_VER -# define png_snprintf _snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 _snprintf -# define png_snprintf6 _snprintf -# else -# define png_snprintf snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 snprintf -# define png_snprintf6 snprintf -# endif -# else - /* You don't have or don't want to use snprintf(). Caution: Using - * sprintf instead of snprintf exposes your application to accidental - * or malevolent buffer overflows. If you don't have snprintf() - * as a general rule you should provide one (you can get one from - * Portable OpenSSH). */ -# define png_snprintf(s1,n,fmt,x1) sprintf(s1,fmt,x1) -# define png_snprintf2(s1,n,fmt,x1,x2) sprintf(s1,fmt,x1,x2) -# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \ - sprintf(s1,fmt,x1,x2,x3,x4,x5,x6) -# endif -# define png_strlen strlen -# define png_memcmp memcmp /* SJT: added */ -# define png_memcpy memcpy -# define png_memset memset -#endif -/* End of memory model independent support */ - -/* Just a little check that someone hasn't tried to define something - * contradictory. - */ -#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) -# undef PNG_ZBUF_SIZE -# define PNG_ZBUF_SIZE 65536L -#endif - -/* Added at libpng-1.2.8 */ -#endif /* PNG_VERSION_INFO_ONLY */ - -#endif /* PNGCONF_H */ diff --git a/src/3rdparty/libpng/pngerror.c b/src/3rdparty/libpng/pngerror.c deleted file mode 100644 index d68416b..0000000 --- a/src/3rdparty/libpng/pngerror.c +++ /dev/null @@ -1,364 +0,0 @@ - -/* pngerror.c - stub functions for i/o and memory allocation - * - * Last changed in libpng 1.2.37 [June 4, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all error handling. Users who - * need special error handling are expected to write replacement functions - * and use png_set_error_fn() to use those functions. See the instructions - * at each function. - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -static void /* PRIVATE */ -png_default_error PNGARG((png_structp png_ptr, - png_const_charp error_message)); -#ifndef PNG_NO_WARNINGS -static void /* PRIVATE */ -png_default_warning PNGARG((png_structp png_ptr, - png_const_charp warning_message)); -#endif /* PNG_NO_WARNINGS */ - -/* This function is called whenever there is a fatal error. This function - * should not be changed. If there is a need to handle errors differently, - * you should supply a replacement error function and use png_set_error_fn() - * to replace the error function at run-time. - */ -#ifndef PNG_NO_ERROR_TEXT -void PNGAPI -png_error(png_structp png_ptr, png_const_charp error_message) -{ -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - char msg[16]; - if (png_ptr != NULL) - { - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) - { - if (*error_message == '#') - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - for (offset = 1; offset<15; offset++) - if (error_message[offset] == ' ') - break; - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - int i; - for (i = 0; i < offset - 1; i++) - msg[i] = error_message[i + 1]; - msg[i - 1] = '\0'; - error_message = msg; - } - else - error_message += offset; - } - else - { - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) - { - msg[0] = '0'; - msg[1] = '\0'; - error_message = msg; - } - } - } - } -#endif - if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, error_message); - - /* If the custom handler doesn't exist, or if it returns, - use the default handler, which will not return. */ - png_default_error(png_ptr, error_message); -} -#else -void PNGAPI -png_err(png_structp png_ptr) -{ - if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, '\0'); - - /* If the custom handler doesn't exist, or if it returns, - use the default handler, which will not return. */ - png_default_error(png_ptr, '\0'); -} -#endif /* PNG_NO_ERROR_TEXT */ - -#ifndef PNG_NO_WARNINGS -/* This function is called whenever there is a non-fatal error. This function - * should not be changed. If there is a need to handle warnings differently, - * you should supply a replacement warning function and use - * png_set_error_fn() to replace the warning function at run-time. - */ -void PNGAPI -png_warning(png_structp png_ptr, png_const_charp warning_message) -{ - int offset = 0; - if (png_ptr != NULL) - { -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) -#endif - { - if (*warning_message == '#') - { - for (offset = 1; offset < 15; offset++) - if (warning_message[offset] == ' ') - break; - } - } - } - if (png_ptr != NULL && png_ptr->warning_fn != NULL) - (*(png_ptr->warning_fn))(png_ptr, warning_message + offset); - else - png_default_warning(png_ptr, warning_message + offset); -} -#endif /* PNG_NO_WARNINGS */ - - -/* These utilities are used internally to build an error message that relates - * to the current chunk. The chunk name comes from png_ptr->chunk_name, - * this is used to prefix the message. The message is limited in length - * to 63 bytes, the name characters are output as hex digits wrapped in [] - * if the character is invalid. - */ -#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) -static PNG_CONST char png_digit[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' -}; - -#define PNG_MAX_ERROR_TEXT 64 - -#if !defined(PNG_NO_WARNINGS) || !defined(PNG_NO_ERROR_TEXT) -static void /* PRIVATE */ -png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp - error_message) -{ - int iout = 0, iin = 0; - - while (iin < 4) - { - int c = png_ptr->chunk_name[iin++]; - if (isnonalpha(c)) - { - buffer[iout++] = '['; - buffer[iout++] = png_digit[(c & 0xf0) >> 4]; - buffer[iout++] = png_digit[c & 0x0f]; - buffer[iout++] = ']'; - } - else - { - buffer[iout++] = (png_byte)c; - } - } - - if (error_message == NULL) - buffer[iout] = '\0'; - else - { - buffer[iout++] = ':'; - buffer[iout++] = ' '; - png_memcpy(buffer + iout, error_message, PNG_MAX_ERROR_TEXT); - buffer[iout + PNG_MAX_ERROR_TEXT - 1] = '\0'; - } -} - -#ifdef PNG_READ_SUPPORTED -void PNGAPI -png_chunk_error(png_structp png_ptr, png_const_charp error_message) -{ - char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) - png_error(png_ptr, error_message); - else - { - png_format_buffer(png_ptr, msg, error_message); - png_error(png_ptr, msg); - } -} -#endif /* PNG_READ_SUPPORTED */ -#endif /* !defined(PNG_NO_WARNINGS) || !defined(PNG_NO_ERROR_TEXT) */ - -#ifndef PNG_NO_WARNINGS -void PNGAPI -png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) -{ - char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) - png_warning(png_ptr, warning_message); - else - { - png_format_buffer(png_ptr, msg, warning_message); - png_warning(png_ptr, msg); - } -} -#endif /* PNG_NO_WARNINGS */ - - -/* This is the default error handling function. Note that replacements for - * this function MUST NOT RETURN, or the program will likely crash. This - * function is used by default, or if the program supplies NULL for the - * error function pointer in png_set_error_fn(). - */ -static void /* PRIVATE */ -png_default_error(png_structp png_ptr, png_const_charp error_message) -{ -#ifndef PNG_NO_CONSOLE_IO -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*error_message == '#') - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - char error_number[16]; - for (offset = 0; offset<15; offset++) - { - error_number[offset] = error_message[offset + 1]; - if (error_message[offset] == ' ') - break; - } - if ((offset > 1) && (offset < 15)) - { - error_number[offset - 1] = '\0'; - fprintf(stderr, "libpng error no. %s: %s", - error_number, error_message + offset + 1); - fprintf(stderr, PNG_STRING_NEWLINE); - } - else - { - fprintf(stderr, "libpng error: %s, offset=%d", - error_message, offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -#endif - { - fprintf(stderr, "libpng error: %s", error_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } -#endif - -#ifdef PNG_SETJMP_SUPPORTED - if (png_ptr) - { -# ifdef USE_FAR_KEYWORD - { - jmp_buf jmpbuf; - png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf)); - longjmp(jmpbuf, 1); - } -# else - longjmp(png_ptr->jmpbuf, 1); -# endif - } -#else - PNG_ABORT(); -#endif -#ifdef PNG_NO_CONSOLE_IO - error_message = error_message; /* Make compiler happy */ -#endif -} - -#ifndef PNG_NO_WARNINGS -/* This function is called when there is a warning, but the library thinks - * it can continue anyway. Replacement functions don't have to do anything - * here if you don't want them to. In the default configuration, png_ptr is - * not used, but it is passed in case it may be useful. - */ -static void /* PRIVATE */ -png_default_warning(png_structp png_ptr, png_const_charp warning_message) -{ -#ifndef PNG_NO_CONSOLE_IO -# ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*warning_message == '#') - { - int offset; - char warning_number[16]; - for (offset = 0; offset < 15; offset++) - { - warning_number[offset] = warning_message[offset + 1]; - if (warning_message[offset] == ' ') - break; - } - if ((offset > 1) && (offset < 15)) - { - warning_number[offset + 1] = '\0'; - fprintf(stderr, "libpng warning no. %s: %s", - warning_number, warning_message + offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - else - { - fprintf(stderr, "libpng warning: %s", - warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -# endif - { - fprintf(stderr, "libpng warning: %s", warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } -#else - warning_message = warning_message; /* Make compiler happy */ -#endif - png_ptr = png_ptr; /* Make compiler happy */ -} -#endif /* PNG_NO_WARNINGS */ - -/* This function is called when the application wants to use another method - * of handling errors and warnings. Note that the error function MUST NOT - * return to the calling routine or serious problems will occur. The return - * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) - */ -void PNGAPI -png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warning_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->error_ptr = error_ptr; - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; -} - - -/* This function returns a pointer to the error_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy and png_read_destroy are called. - */ -png_voidp PNGAPI -png_get_error_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return NULL; - return ((png_voidp)png_ptr->error_ptr); -} - - -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -void PNGAPI -png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) -{ - if (png_ptr != NULL) - { - png_ptr->flags &= - ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); - } -} -#endif -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/src/3rdparty/libpng/pnggccrd.c b/src/3rdparty/libpng/pnggccrd.c deleted file mode 100644 index e61523e..0000000 --- a/src/3rdparty/libpng/pnggccrd.c +++ /dev/null @@ -1,103 +0,0 @@ -/* pnggccrd.c was removed from libpng-1.2.20. */ - -/* This code snippet is for use by configure's compilation test. */ - -#if (!defined _MSC_VER) && \ - defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \ - defined(PNG_MMX_CODE_SUPPORTED) - -int PNGAPI png_dummy_mmx_support(void); - -static int _mmx_supported = 2; // 0: no MMX; 1: MMX supported; 2: not tested - -int PNGAPI -png_dummy_mmx_support(void) __attribute__((noinline)); - -int PNGAPI -png_dummy_mmx_support(void) -{ - int result; -#if defined(PNG_MMX_CODE_SUPPORTED) // superfluous, but what the heck - __asm__ __volatile__ ( -#if defined(__x86_64__) - "pushq %%rbx \n\t" // rbx gets clobbered by CPUID instruction - "pushq %%rcx \n\t" // so does rcx... - "pushq %%rdx \n\t" // ...and rdx (but rcx & rdx safe on Linux) - "pushfq \n\t" // save Eflag to stack - "popq %%rax \n\t" // get Eflag from stack into rax - "movq %%rax, %%rcx \n\t" // make another copy of Eflag in rcx - "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21) - "pushq %%rax \n\t" // save modified Eflag back to stack - "popfq \n\t" // restore modified value to Eflag reg - "pushfq \n\t" // save Eflag to stack - "popq %%rax \n\t" // get Eflag from stack - "pushq %%rcx \n\t" // save original Eflag to stack - "popfq \n\t" // restore original Eflag -#else - "pushl %%ebx \n\t" // ebx gets clobbered by CPUID instruction - "pushl %%ecx \n\t" // so does ecx... - "pushl %%edx \n\t" // ...and edx (but ecx & edx safe on Linux) - "pushfl \n\t" // save Eflag to stack - "popl %%eax \n\t" // get Eflag from stack into eax - "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx - "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21) - "pushl %%eax \n\t" // save modified Eflag back to stack - "popfl \n\t" // restore modified value to Eflag reg - "pushfl \n\t" // save Eflag to stack - "popl %%eax \n\t" // get Eflag from stack - "pushl %%ecx \n\t" // save original Eflag to stack - "popfl \n\t" // restore original Eflag -#endif - "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag - "jz 0f \n\t" // if same, CPUID instr. is not supported - - "xorl %%eax, %%eax \n\t" // set eax to zero -// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode) - "cpuid \n\t" // get the CPU identification info - "cmpl $1, %%eax \n\t" // make sure eax return non-zero value - "jl 0f \n\t" // if eax is zero, MMX is not supported - - "xorl %%eax, %%eax \n\t" // set eax to zero and... - "incl %%eax \n\t" // ...increment eax to 1. This pair is - // faster than the instruction "mov eax, 1" - "cpuid \n\t" // get the CPU identification info again - "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23) - "cmpl $0, %%edx \n\t" // 0 = MMX not supported - "jz 0f \n\t" // non-zero = yes, MMX IS supported - - "movl $1, %%eax \n\t" // set return value to 1 - "jmp 1f \n\t" // DONE: have MMX support - - "0: \n\t" // .NOT_SUPPORTED: target label for jump instructions - "movl $0, %%eax \n\t" // set return value to 0 - "1: \n\t" // .RETURN: target label for jump instructions -#if defined(__x86_64__) - "popq %%rdx \n\t" // restore rdx - "popq %%rcx \n\t" // restore rcx - "popq %%rbx \n\t" // restore rbx -#else - "popl %%edx \n\t" // restore edx - "popl %%ecx \n\t" // restore ecx - "popl %%ebx \n\t" // restore ebx -#endif - -// "ret \n\t" // DONE: no MMX support - // (fall through to standard C "ret") - - : "=a" (result) // output list - - : // any variables used on input (none) - - // no clobber list -// , "%ebx", "%ecx", "%edx" // GRR: we handle these manually -// , "memory" // if write to a variable gcc thought was in a reg -// , "cc" // "condition codes" (flag bits) - ); - _mmx_supported = result; -#else - _mmx_supported = 0; -#endif /* PNG_MMX_CODE_SUPPORTED */ - - return _mmx_supported; -} -#endif diff --git a/src/3rdparty/libpng/pngget.c b/src/3rdparty/libpng/pngget.c deleted file mode 100644 index 38e4f9e..0000000 --- a/src/3rdparty/libpng/pngget.c +++ /dev/null @@ -1,943 +0,0 @@ - -/* pngget.c - retrieval of values from info struct - * - * Last changed in libpng 1.2.37 [June 4, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -png_uint_32 PNGAPI -png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->valid & flag); - - else - return(0); -} - -png_uint_32 PNGAPI -png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->rowbytes); - - else - return(0); -} - -#if defined(PNG_INFO_IMAGE_SUPPORTED) -png_bytepp PNGAPI -png_get_rows(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->row_pointers); - - else - return(0); -} -#endif - -#ifdef PNG_EASY_ACCESS_SUPPORTED -/* Easy access to info, added in libpng-0.99 */ -png_uint_32 PNGAPI -png_get_image_width(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->width; - - return (0); -} - -png_uint_32 PNGAPI -png_get_image_height(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->height; - - return (0); -} - -png_byte PNGAPI -png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->bit_depth; - - return (0); -} - -png_byte PNGAPI -png_get_color_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->color_type; - - return (0); -} - -png_byte PNGAPI -png_get_filter_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->filter_type; - - return (0); -} - -png_byte PNGAPI -png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->interlace_type; - - return (0); -} - -png_byte PNGAPI -png_get_compression_type(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->compression_type; - - return (0); -} - -png_uint_32 PNGAPI -png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#if defined(PNG_pHYs_SUPPORTED) - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); - - if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) - return (0); - - else - return (info_ptr->x_pixels_per_unit); - } -#else - return (0); -#endif - return (0); -} - -png_uint_32 PNGAPI -png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#if defined(PNG_pHYs_SUPPORTED) - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); - - if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) - return (0); - - else - return (info_ptr->y_pixels_per_unit); - } -#else - return (0); -#endif - return (0); -} - -png_uint_32 PNGAPI -png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#if defined(PNG_pHYs_SUPPORTED) - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); - - if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER || - info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) - return (0); - - else - return (info_ptr->x_pixels_per_unit); - } -#else - return (0); -#endif - return (0); -} - -#ifdef PNG_FLOATING_POINT_SUPPORTED -float PNGAPI -png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) - { - if (png_ptr != NULL && info_ptr != NULL) -#if defined(PNG_pHYs_SUPPORTED) - - if (info_ptr->valid & PNG_INFO_pHYs) - { - png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); - if (info_ptr->x_pixels_per_unit == 0) - return ((float)0.0); - else - return ((float)((float)info_ptr->y_pixels_per_unit - /(float)info_ptr->x_pixels_per_unit)); - } -#else - return (0.0); -#endif - return ((float)0.0); -} -#endif - -png_int_32 PNGAPI -png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) -#if defined(PNG_oFFs_SUPPORTED) - - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) - return (0); - - else - return (info_ptr->x_offset); - } -#else - return (0); -#endif - return (0); -} - -png_int_32 PNGAPI -png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - -#if defined(PNG_oFFs_SUPPORTED) - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) - return (0); - - else - return (info_ptr->y_offset); - } -#else - return (0); -#endif - return (0); -} - -png_int_32 PNGAPI -png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - -#if defined(PNG_oFFs_SUPPORTED) - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) - return (0); - - else - return (info_ptr->x_offset); - } -#else - return (0); -#endif - return (0); -} - -png_int_32 PNGAPI -png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - -#if defined(PNG_oFFs_SUPPORTED) - if (info_ptr->valid & PNG_INFO_oFFs) - { - png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); - - if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) - return (0); - - else - return (info_ptr->y_offset); - } -#else - return (0); -#endif - return (0); -} - -#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) -png_uint_32 PNGAPI -png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); -} - -png_uint_32 PNGAPI -png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); -} - -png_uint_32 PNGAPI -png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) -{ - return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) - *.0254 +.5)); -} - -float PNGAPI -png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) -{ - return ((float)png_get_x_offset_microns(png_ptr, info_ptr) - *.00003937); -} - -float PNGAPI -png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) -{ - return ((float)png_get_y_offset_microns(png_ptr, info_ptr) - *.00003937); -} - -#if defined(PNG_pHYs_SUPPORTED) -png_uint_32 PNGAPI -png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) -{ - png_uint_32 retval = 0; - - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", "pHYs"); - if (res_x != NULL) - { - *res_x = info_ptr->x_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - if (res_y != NULL) - { - *res_y = info_ptr->y_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - if (unit_type != NULL) - { - *unit_type = (int)info_ptr->phys_unit_type; - retval |= PNG_INFO_pHYs; - if (*unit_type == 1) - { - if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); - if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); - } - } - } - return (retval); -} -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ - -/* png_get_channels really belongs in here, too, but it's been around longer */ - -#endif /* PNG_EASY_ACCESS_SUPPORTED */ - -png_byte PNGAPI -png_get_channels(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->channels); - else - return (0); -} - -png_bytep PNGAPI -png_get_signature(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr != NULL && info_ptr != NULL) - return(info_ptr->signature); - else - return (NULL); -} - -#if defined(PNG_bKGD_SUPPORTED) -png_uint_32 PNGAPI -png_get_bKGD(png_structp png_ptr, png_infop info_ptr, - png_color_16p *background) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) - && background != NULL) - { - png_debug1(1, "in %s retrieval function", "bKGD"); - *background = &(info_ptr->background); - return (PNG_INFO_bKGD); - } - return (0); -} -#endif - -#if defined(PNG_cHRM_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cHRM(png_structp png_ptr, png_infop info_ptr, - double *white_x, double *white_y, double *red_x, double *red_y, - double *green_x, double *green_y, double *blue_x, double *blue_y) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - { - png_debug1(1, "in %s retrieval function", "cHRM"); - if (white_x != NULL) - *white_x = (double)info_ptr->x_white; - if (white_y != NULL) - *white_y = (double)info_ptr->y_white; - if (red_x != NULL) - *red_x = (double)info_ptr->x_red; - if (red_y != NULL) - *red_y = (double)info_ptr->y_red; - if (green_x != NULL) - *green_x = (double)info_ptr->x_green; - if (green_y != NULL) - *green_y = (double)info_ptr->y_green; - if (blue_x != NULL) - *blue_x = (double)info_ptr->x_blue; - if (blue_y != NULL) - *blue_y = (double)info_ptr->y_blue; - return (PNG_INFO_cHRM); - } - return (0); -} -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, - png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, - png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, - png_fixed_point *blue_x, png_fixed_point *blue_y) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - { - png_debug1(1, "in %s retrieval function", "cHRM"); - if (white_x != NULL) - *white_x = info_ptr->int_x_white; - if (white_y != NULL) - *white_y = info_ptr->int_y_white; - if (red_x != NULL) - *red_x = info_ptr->int_x_red; - if (red_y != NULL) - *red_y = info_ptr->int_y_red; - if (green_x != NULL) - *green_x = info_ptr->int_x_green; - if (green_y != NULL) - *green_y = info_ptr->int_y_green; - if (blue_x != NULL) - *blue_x = info_ptr->int_x_blue; - if (blue_y != NULL) - *blue_y = info_ptr->int_y_blue; - return (PNG_INFO_cHRM); - } - return (0); -} -#endif -#endif - -#if defined(PNG_gAMA_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && file_gamma != NULL) - { - png_debug1(1, "in %s retrieval function", "gAMA"); - *file_gamma = (double)info_ptr->gamma; - return (PNG_INFO_gAMA); - } - return (0); -} -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, - png_fixed_point *int_file_gamma) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && int_file_gamma != NULL) - { - png_debug1(1, "in %s retrieval function", "gAMA"); - *int_file_gamma = info_ptr->int_gamma; - return (PNG_INFO_gAMA); - } - return (0); -} -#endif -#endif - -#if defined(PNG_sRGB_SUPPORTED) -png_uint_32 PNGAPI -png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) - && file_srgb_intent != NULL) - { - png_debug1(1, "in %s retrieval function", "sRGB"); - *file_srgb_intent = (int)info_ptr->srgb_intent; - return (PNG_INFO_sRGB); - } - return (0); -} -#endif - -#if defined(PNG_iCCP_SUPPORTED) -png_uint_32 PNGAPI -png_get_iCCP(png_structp png_ptr, png_infop info_ptr, - png_charpp name, int *compression_type, - png_charpp profile, png_uint_32 *proflen) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) - && name != NULL && profile != NULL && proflen != NULL) - { - png_debug1(1, "in %s retrieval function", "iCCP"); - *name = info_ptr->iccp_name; - *profile = info_ptr->iccp_profile; - /* Compression_type is a dummy so the API won't have to change - * if we introduce multiple compression types later. - */ - *proflen = (int)info_ptr->iccp_proflen; - *compression_type = (int)info_ptr->iccp_compression; - return (PNG_INFO_iCCP); - } - return (0); -} -#endif - -#if defined(PNG_sPLT_SUPPORTED) -png_uint_32 PNGAPI -png_get_sPLT(png_structp png_ptr, png_infop info_ptr, - png_sPLT_tpp spalettes) -{ - if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) - { - *spalettes = info_ptr->splt_palettes; - return ((png_uint_32)info_ptr->splt_palettes_num); - } - return (0); -} -#endif - -#if defined(PNG_hIST_SUPPORTED) -png_uint_32 PNGAPI -png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) - && hist != NULL) - { - png_debug1(1, "in %s retrieval function", "hIST"); - *hist = info_ptr->hist; - return (PNG_INFO_hIST); - } - return (0); -} -#endif - -png_uint_32 PNGAPI -png_get_IHDR(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *width, png_uint_32 *height, int *bit_depth, - int *color_type, int *interlace_type, int *compression_type, - int *filter_type) - -{ - if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL && - bit_depth != NULL && color_type != NULL) - { - png_debug1(1, "in %s retrieval function", "IHDR"); - *width = info_ptr->width; - *height = info_ptr->height; - *bit_depth = info_ptr->bit_depth; - if (info_ptr->bit_depth < 1 || info_ptr->bit_depth > 16) - png_error(png_ptr, "Invalid bit depth"); - - *color_type = info_ptr->color_type; - - if (info_ptr->color_type > 6) - png_error(png_ptr, "Invalid color type"); - - if (compression_type != NULL) - *compression_type = info_ptr->compression_type; - - if (filter_type != NULL) - *filter_type = info_ptr->filter_type; - - if (interlace_type != NULL) - *interlace_type = info_ptr->interlace_type; - - /* Check for potential overflow of rowbytes */ - if (*width == 0 || *width > PNG_UINT_31_MAX) - png_error(png_ptr, "Invalid image width"); - - if (*height == 0 || *height > PNG_UINT_31_MAX) - png_error(png_ptr, "Invalid image height"); - - if (info_ptr->width > (PNG_UINT_32_MAX - >> 3) /* 8-byte RGBA pixels */ - - 64 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - { - png_warning(png_ptr, - "Width too large for libpng to process image data."); - } - - return (1); - } - return (0); -} - -#if defined(PNG_oFFs_SUPPORTED) -png_uint_32 PNGAPI -png_get_oFFs(png_structp png_ptr, png_infop info_ptr, - png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) - && offset_x != NULL && offset_y != NULL && unit_type != NULL) - { - png_debug1(1, "in %s retrieval function", "oFFs"); - *offset_x = info_ptr->x_offset; - *offset_y = info_ptr->y_offset; - *unit_type = (int)info_ptr->offset_unit_type; - return (PNG_INFO_oFFs); - } - return (0); -} -#endif - -#if defined(PNG_pCAL_SUPPORTED) -png_uint_32 PNGAPI -png_get_pCAL(png_structp png_ptr, png_infop info_ptr, - png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, - png_charp *units, png_charpp *params) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) - && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && - nparams != NULL && units != NULL && params != NULL) - { - png_debug1(1, "in %s retrieval function", "pCAL"); - *purpose = info_ptr->pcal_purpose; - *X0 = info_ptr->pcal_X0; - *X1 = info_ptr->pcal_X1; - *type = (int)info_ptr->pcal_type; - *nparams = (int)info_ptr->pcal_nparams; - *units = info_ptr->pcal_units; - *params = info_ptr->pcal_params; - return (PNG_INFO_pCAL); - } - return (0); -} -#endif - -#if defined(PNG_sCAL_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_sCAL(png_structp png_ptr, png_infop info_ptr, - int *unit, double *width, double *height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - *width = info_ptr->scal_pixel_width; - *height = info_ptr->scal_pixel_height; - return (PNG_INFO_sCAL); - } - return(0); -} -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, - int *unit, png_charpp width, png_charpp height) -{ - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) - { - *unit = info_ptr->scal_unit; - *width = info_ptr->scal_s_width; - *height = info_ptr->scal_s_height; - return (PNG_INFO_sCAL); - } - return(0); -} -#endif -#endif -#endif - -#if defined(PNG_pHYs_SUPPORTED) -png_uint_32 PNGAPI -png_get_pHYs(png_structp png_ptr, png_infop info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) -{ - png_uint_32 retval = 0; - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs)) - { - png_debug1(1, "in %s retrieval function", "pHYs"); - - if (res_x != NULL) - { - *res_x = info_ptr->x_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (res_y != NULL) - { - *res_y = info_ptr->y_pixels_per_unit; - retval |= PNG_INFO_pHYs; - } - - if (unit_type != NULL) - { - *unit_type = (int)info_ptr->phys_unit_type; - retval |= PNG_INFO_pHYs; - } - } - return (retval); -} -#endif - -png_uint_32 PNGAPI -png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, - int *num_palette) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) - && palette != NULL) - { - png_debug1(1, "in %s retrieval function", "PLTE"); - *palette = info_ptr->palette; - *num_palette = info_ptr->num_palette; - png_debug1(3, "num_palette = %d", *num_palette); - return (PNG_INFO_PLTE); - } - return (0); -} - -#if defined(PNG_sBIT_SUPPORTED) -png_uint_32 PNGAPI -png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) - && sig_bit != NULL) - { - png_debug1(1, "in %s retrieval function", "sBIT"); - *sig_bit = &(info_ptr->sig_bit); - return (PNG_INFO_sBIT); - } - return (0); -} -#endif - -#if defined(PNG_TEXT_SUPPORTED) -png_uint_32 PNGAPI -png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, - int *num_text) -{ - if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) - { - png_debug1(1, "in %s retrieval function", - (png_ptr->chunk_name[0] == '\0' ? "text" - : (png_const_charp)png_ptr->chunk_name)); - - if (text_ptr != NULL) - *text_ptr = info_ptr->text; - - if (num_text != NULL) - *num_text = info_ptr->num_text; - - return ((png_uint_32)info_ptr->num_text); - } - if (num_text != NULL) - *num_text = 0; - return(0); -} -#endif - -#if defined(PNG_tIME_SUPPORTED) -png_uint_32 PNGAPI -png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) - && mod_time != NULL) - { - png_debug1(1, "in %s retrieval function", "tIME"); - *mod_time = &(info_ptr->mod_time); - return (PNG_INFO_tIME); - } - return (0); -} -#endif - -#if defined(PNG_tRNS_SUPPORTED) -png_uint_32 PNGAPI -png_get_tRNS(png_structp png_ptr, png_infop info_ptr, - png_bytep *trans, int *num_trans, png_color_16p *trans_values) -{ - png_uint_32 retval = 0; - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - png_debug1(1, "in %s retrieval function", "tRNS"); - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (trans != NULL) - { - *trans = info_ptr->trans; - retval |= PNG_INFO_tRNS; - } - - if (trans_values != NULL) - *trans_values = &(info_ptr->trans_values); - } - else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ - { - if (trans_values != NULL) - { - *trans_values = &(info_ptr->trans_values); - retval |= PNG_INFO_tRNS; - } - - if (trans != NULL) - *trans = NULL; - } - if (num_trans != NULL) - { - *num_trans = info_ptr->num_trans; - retval |= PNG_INFO_tRNS; - } - } - return (retval); -} -#endif - -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) -png_uint_32 PNGAPI -png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, - png_unknown_chunkpp unknowns) -{ - if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) - { - *unknowns = info_ptr->unknown_chunks; - return ((png_uint_32)info_ptr->unknown_chunks_num); - } - return (0); -} -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -png_byte PNGAPI -png_get_rgb_to_gray_status (png_structp png_ptr) -{ - return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); -} -#endif - -#if defined(PNG_USER_CHUNKS_SUPPORTED) -png_voidp PNGAPI -png_get_user_chunk_ptr(png_structp png_ptr) -{ - return (png_ptr? png_ptr->user_chunk_ptr : NULL); -} -#endif - -#ifdef PNG_WRITE_SUPPORTED -png_uint_32 PNGAPI -png_get_compression_buffer_size(png_structp png_ptr) -{ - return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L); -} -#endif - -#ifdef PNG_ASSEMBLER_CODE_SUPPORTED -#ifndef PNG_1_0_X -/* This function was added to libpng 1.2.0 and should exist by default */ -png_uint_32 PNGAPI -png_get_asm_flags (png_structp png_ptr) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return (png_ptr? 0L: 0L); -} - -/* This function was added to libpng 1.2.0 and should exist by default */ -png_uint_32 PNGAPI -png_get_asm_flagmask (int flag_select) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - flag_select=flag_select; - return 0L; -} - - /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */ -/* This function was added to libpng 1.2.0 */ -png_uint_32 PNGAPI -png_get_mmx_flagmask (int flag_select, int *compilerID) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - flag_select=flag_select; - *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */ - return 0L; -} - -/* This function was added to libpng 1.2.0 */ -png_byte PNGAPI -png_get_mmx_bitdepth_threshold (png_structp png_ptr) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return (png_ptr? 0: 0); -} - -/* This function was added to libpng 1.2.0 */ -png_uint_32 PNGAPI -png_get_mmx_rowbytes_threshold (png_structp png_ptr) -{ - /* Obsolete, to be removed from libpng-1.4.0 */ - return (png_ptr? 0L: 0L); -} -#endif /* ?PNG_1_0_X */ -#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED -/* These functions were added to libpng 1.2.6 */ -png_uint_32 PNGAPI -png_get_user_width_max (png_structp png_ptr) -{ - return (png_ptr? png_ptr->user_width_max : 0); -} -png_uint_32 PNGAPI -png_get_user_height_max (png_structp png_ptr) -{ - return (png_ptr? png_ptr->user_height_max : 0); -} -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ - - -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/src/3rdparty/libpng/pngmem.c b/src/3rdparty/libpng/pngmem.c deleted file mode 100644 index e190cc3..0000000 --- a/src/3rdparty/libpng/pngmem.c +++ /dev/null @@ -1,620 +0,0 @@ - -/* pngmem.c - stub functions for memory allocation - * - * Last changed in libpng 1.2.37 [June 4, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all memory allocation. Users who - * need special memory handling are expected to supply replacement - * functions for png_malloc() and png_free(), and to use - * png_create_read_struct_2() and png_create_write_struct_2() to - * identify the replacement functions. - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -/* Borland DOS special memory handler */ -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* If you change this, be sure to change the one in png.h also */ - -/* Allocate memory for a png_struct. The malloc and memset can be replaced - by a single call to calloc() if this is thought to improve performance. */ -png_voidp /* PRIVATE */ -png_create_struct(int type) -{ -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); -} - -/* Alternate version of png_create_struct, for use with user-defined malloc. */ -png_voidp /* PRIVATE */ -png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - png_size_t size; - png_voidp struct_ptr; - - if (type == PNG_STRUCT_INFO) - size = png_sizeof(png_info); - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - else - return (png_get_copyright(NULL)); - -#ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size); - } - else -#endif /* PNG_USER_MEM_SUPPORTED */ - struct_ptr = (png_voidp)farmalloc(size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - return (struct_ptr); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) -{ -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, - png_voidp mem_ptr) -{ -#endif - if (struct_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - if (free_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - (*(free_fn))(png_ptr, struct_ptr); - return; - } -#endif /* PNG_USER_MEM_SUPPORTED */ - farfree (struct_ptr); - } -} - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - * - * Borland seems to have a problem in DOS mode for exactly 64K. - * It gives you a segment with an offset of 8 (perhaps to store its - * memory stuff). zlib doesn't like this at all, so we have to - * detect and deal with it. This code should not be needed in - * Windows or OS/2 modes, and only in 16 bit mode. This code has - * been updated by Alexander Lehmann for version 0.89 to waste less - * memory. - * - * Note that we can't use png_size_t for the "size" declaration, - * since on some systems a png_size_t is a 16-bit quantity, and as a - * result, we would be truncating potentially larger memory requests - * (which should cause a fatal error) and introducing major problems. - */ - -png_voidp PNGAPI -png_malloc(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - else - ret = (png_malloc_default(png_ptr, size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory!"); - return (ret); -} - -png_voidp PNGAPI -png_malloc_default(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { - png_warning(png_ptr, "Cannot Allocate > 64K"); - ret = NULL; - } - else -#endif - - if (size != (size_t)size) - ret = NULL; - else if (size == (png_uint_32)65536L) - { - if (png_ptr->offset_table == NULL) - { - /* Try to see if we need to do any of this fancy stuff */ - ret = farmalloc(size); - if (ret == NULL || ((png_size_t)ret & 0xffff)) - { - int num_blocks; - png_uint_32 total_size; - png_bytep table; - int i; - png_byte huge * hptr; - - if (ret != NULL) - { - farfree(ret); - ret = NULL; - } - - if (png_ptr->zlib_window_bits > 14) - num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); - else - num_blocks = 1; - if (png_ptr->zlib_mem_level >= 7) - num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); - else - num_blocks++; - - total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; - - table = farmalloc(total_size); - - if (table == NULL) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */ - else - png_warning(png_ptr, "Out Of Memory."); -#endif - return (NULL); - } - - if ((png_size_t)table & 0xfff0) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, - "Farmalloc didn't return normalized pointer"); - else - png_warning(png_ptr, - "Farmalloc didn't return normalized pointer"); -#endif - return (NULL); - } - - png_ptr->offset_table = table; - png_ptr->offset_table_ptr = farmalloc(num_blocks * - png_sizeof(png_bytep)); - - if (png_ptr->offset_table_ptr == NULL) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */ - else - png_warning(png_ptr, "Out Of memory."); -#endif - return (NULL); - } - - hptr = (png_byte huge *)table; - if ((png_size_t)hptr & 0xf) - { - hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); - hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ - } - for (i = 0; i < num_blocks; i++) - { - png_ptr->offset_table_ptr[i] = (png_bytep)hptr; - hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ - } - - png_ptr->offset_table_number = num_blocks; - png_ptr->offset_table_count = 0; - png_ptr->offset_table_count_free = 0; - } - } - - if (png_ptr->offset_table_count >= png_ptr->offset_table_number) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */ - else - png_warning(png_ptr, "Out of Memory."); -#endif - return (NULL); - } - - ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; - } - else - ret = farmalloc(size); - -#ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL) - { - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */ - else - png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */ - } -#endif - - return (ret); -} - -/* Free a pointer allocated by png_malloc(). In the default - * configuration, png_ptr is not used, but is passed in case it - * is needed. If ptr is NULL, return without taking any action. - */ -void PNGAPI -png_free(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->free_fn != NULL) - { - (*(png_ptr->free_fn))(png_ptr, ptr); - return; - } - else - png_free_default(png_ptr, ptr); -} - -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || ptr == NULL) - return; - - if (png_ptr->offset_table != NULL) - { - int i; - - for (i = 0; i < png_ptr->offset_table_count; i++) - { - if (ptr == png_ptr->offset_table_ptr[i]) - { - ptr = NULL; - png_ptr->offset_table_count_free++; - break; - } - } - if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) - { - farfree(png_ptr->offset_table); - farfree(png_ptr->offset_table_ptr); - png_ptr->offset_table = NULL; - png_ptr->offset_table_ptr = NULL; - } - } - - if (ptr != NULL) - { - farfree(ptr); - } -} - -#else /* Not the Borland DOS special memory handler */ - -/* Allocate memory for a png_struct or a png_info. The malloc and - memset can be replaced by a single call to calloc() if this is thought - to improve performance noticably. */ -png_voidp /* PRIVATE */ -png_create_struct(int type) -{ -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL)); -} - -/* Allocate memory for a png_struct or a png_info. The malloc and - memset can be replaced by a single call to calloc() if this is thought - to improve performance noticably. */ -png_voidp /* PRIVATE */ -png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - png_size_t size; - png_voidp struct_ptr; - - if (type == PNG_STRUCT_INFO) - size = png_sizeof(png_info); - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - else - return (NULL); - -#ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - return (struct_ptr); - } -#endif /* PNG_USER_MEM_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(__FLAT__) - struct_ptr = (png_voidp)farmalloc(size); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - struct_ptr = (png_voidp)halloc(size, 1); -# else - struct_ptr = (png_voidp)malloc(size); -# endif -#endif - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - - return (struct_ptr); -} - - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) -{ -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, - png_voidp mem_ptr) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - if (struct_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - if (free_fn != NULL) - { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - (*(free_fn))(png_ptr, struct_ptr); - return; - } -#endif /* PNG_USER_MEM_SUPPORTED */ -#if defined(__TURBOC__) && !defined(__FLAT__) - farfree(struct_ptr); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - hfree(struct_ptr); -# else - free(struct_ptr); -# endif -#endif - } -} - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - */ - - -png_voidp PNGAPI -png_malloc(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr == NULL || size == 0) - return (NULL); - - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); - else - ret = (png_malloc_default(png_ptr, size)); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory!"); - return (ret); -} - -png_voidp PNGAPI -png_malloc_default(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ret; -#endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -#ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { -#ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Cannot Allocate > 64K"); - else -#endif - return NULL; - } -#endif - - /* Check for overflow */ -#if defined(__TURBOC__) && !defined(__FLAT__) - if (size != (unsigned long)size) - ret = NULL; - else - ret = farmalloc(size); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - if (size != (unsigned long)size) - ret = NULL; - else - ret = halloc(size, 1); -# else - if (size != (size_t)size) - ret = NULL; - else - ret = malloc((size_t)size); -# endif -#endif - -#ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); -#endif - - return (ret); -} - -/* Free a pointer allocated by png_malloc(). If ptr is NULL, return - * without taking any action. - */ -void PNGAPI -png_free(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->free_fn != NULL) - { - (*(png_ptr->free_fn))(png_ptr, ptr); - return; - } - else - png_free_default(png_ptr, ptr); -} -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL || ptr == NULL) - return; - -#endif /* PNG_USER_MEM_SUPPORTED */ - -#if defined(__TURBOC__) && !defined(__FLAT__) - farfree(ptr); -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - hfree(ptr); -# else - free(ptr); -# endif -#endif -} - -#endif /* Not Borland DOS special memory handler */ - -#if defined(PNG_1_0_X) -# define png_malloc_warn png_malloc -#else -/* This function was added at libpng version 1.2.3. The png_malloc_warn() - * function will set up png_malloc() to issue a png_warning and return NULL - * instead of issuing a png_error, if it fails to allocate the requested - * memory. - */ -png_voidp PNGAPI -png_malloc_warn(png_structp png_ptr, png_uint_32 size) -{ - png_voidp ptr; - png_uint_32 save_flags; - if (png_ptr == NULL) - return (NULL); - - save_flags = png_ptr->flags; - png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); - png_ptr->flags=save_flags; - return(ptr); -} -#endif - -png_voidp PNGAPI -png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2, - png_uint_32 length) -{ - png_size_t size; - - size = (png_size_t)length; - if ((png_uint_32)size != length) - png_error(png_ptr, "Overflow in png_memcpy_check."); - - return(png_memcpy (s1, s2, size)); -} - -png_voidp PNGAPI -png_memset_check (png_structp png_ptr, png_voidp s1, int value, - png_uint_32 length) -{ - png_size_t size; - - size = (png_size_t)length; - if ((png_uint_32)size != length) - png_error(png_ptr, "Overflow in png_memset_check."); - - return (png_memset (s1, value, size)); - -} - -#ifdef PNG_USER_MEM_SUPPORTED -/* This function is called when the application wants to use another method - * of allocating and freeing memory. - */ -void PNGAPI -png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr - malloc_fn, png_free_ptr free_fn) -{ - if (png_ptr != NULL) - { - png_ptr->mem_ptr = mem_ptr; - png_ptr->malloc_fn = malloc_fn; - png_ptr->free_fn = free_fn; - } -} - -/* This function returns a pointer to the mem_ptr associated with the user - * functions. The application should free any memory associated with this - * pointer before png_write_destroy and png_read_destroy are called. - */ -png_voidp PNGAPI -png_get_mem_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - return ((png_voidp)png_ptr->mem_ptr); -} -#endif /* PNG_USER_MEM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/src/3rdparty/libpng/pngnow.png b/src/3rdparty/libpng/pngnow.png deleted file mode 100644 index 82793eb..0000000 Binary files a/src/3rdparty/libpng/pngnow.png and /dev/null differ diff --git a/src/3rdparty/libpng/pngpread.c b/src/3rdparty/libpng/pngpread.c deleted file mode 100644 index 7adb7b8..0000000 --- a/src/3rdparty/libpng/pngpread.c +++ /dev/null @@ -1,1727 +0,0 @@ - -/* pngpread.c - read a png file in push mode - * - * Last changed in libpng 1.2.38 [July 16, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - */ - -#define PNG_INTERNAL -#include "png.h" -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - -/* Push model modes */ -#define PNG_READ_SIG_MODE 0 -#define PNG_READ_CHUNK_MODE 1 -#define PNG_READ_IDAT_MODE 2 -#define PNG_SKIP_MODE 3 -#define PNG_READ_tEXt_MODE 4 -#define PNG_READ_zTXt_MODE 5 -#define PNG_READ_DONE_MODE 6 -#define PNG_READ_iTXt_MODE 7 -#define PNG_ERROR_MODE 8 - -void PNGAPI -png_process_data(png_structp png_ptr, png_infop info_ptr, - png_bytep buffer, png_size_t buffer_size) -{ - if (png_ptr == NULL || info_ptr == NULL) - return; - - png_push_restore_buffer(png_ptr, buffer, buffer_size); - - while (png_ptr->buffer_size) - { - png_process_some_data(png_ptr, info_ptr); - } -} - -/* What we do with the incoming data depends on what we were previously - * doing before we ran out of data... - */ -void /* PRIVATE */ -png_process_some_data(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr == NULL) - return; - - switch (png_ptr->process_mode) - { - case PNG_READ_SIG_MODE: - { - png_push_read_sig(png_ptr, info_ptr); - break; - } - - case PNG_READ_CHUNK_MODE: - { - png_push_read_chunk(png_ptr, info_ptr); - break; - } - - case PNG_READ_IDAT_MODE: - { - png_push_read_IDAT(png_ptr); - break; - } - -#if defined(PNG_READ_tEXt_SUPPORTED) - case PNG_READ_tEXt_MODE: - { - png_push_read_tEXt(png_ptr, info_ptr); - break; - } - -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - case PNG_READ_zTXt_MODE: - { - png_push_read_zTXt(png_ptr, info_ptr); - break; - } - -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - case PNG_READ_iTXt_MODE: - { - png_push_read_iTXt(png_ptr, info_ptr); - break; - } - -#endif - case PNG_SKIP_MODE: - { - png_push_crc_finish(png_ptr); - break; - } - - default: - { - png_ptr->buffer_size = 0; - break; - } - } -} - -/* Read any remaining signature bytes from the stream and compare them with - * the correct PNG signature. It is possible that this routine is called - * with bytes already read from the signature, either because they have been - * checked by the calling application, or because of multiple calls to this - * routine. - */ -void /* PRIVATE */ -png_push_read_sig(png_structp png_ptr, png_infop info_ptr) -{ - png_size_t num_checked = png_ptr->sig_bytes, - num_to_check = 8 - num_checked; - - if (png_ptr->buffer_size < num_to_check) - { - num_to_check = png_ptr->buffer_size; - } - - png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), - num_to_check); - png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); - - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) - { - if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) - png_error(png_ptr, "Not a PNG file"); - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - else - { - if (png_ptr->sig_bytes >= 8) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } - } -} - -void /* PRIVATE */ -png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IHDR; - PNG_CONST PNG_IDAT; - PNG_CONST PNG_IEND; - PNG_CONST PNG_PLTE; -#if defined(PNG_READ_bKGD_SUPPORTED) - PNG_CONST PNG_bKGD; -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) - PNG_CONST PNG_cHRM; -#endif -#if defined(PNG_READ_gAMA_SUPPORTED) - PNG_CONST PNG_gAMA; -#endif -#if defined(PNG_READ_hIST_SUPPORTED) - PNG_CONST PNG_hIST; -#endif -#if defined(PNG_READ_iCCP_SUPPORTED) - PNG_CONST PNG_iCCP; -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - PNG_CONST PNG_iTXt; -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) - PNG_CONST PNG_oFFs; -#endif -#if defined(PNG_READ_pCAL_SUPPORTED) - PNG_CONST PNG_pCAL; -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) - PNG_CONST PNG_pHYs; -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) - PNG_CONST PNG_sBIT; -#endif -#if defined(PNG_READ_sCAL_SUPPORTED) - PNG_CONST PNG_sCAL; -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) - PNG_CONST PNG_sRGB; -#endif -#if defined(PNG_READ_sPLT_SUPPORTED) - PNG_CONST PNG_sPLT; -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) - PNG_CONST PNG_tEXt; -#endif -#if defined(PNG_READ_tIME_SUPPORTED) - PNG_CONST PNG_tIME; -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) - PNG_CONST PNG_tRNS; -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - PNG_CONST PNG_zTXt; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - /* First we make sure we have enough data for the 4 byte chunk name - * and the 4 byte chunk length before proceeding with decoding the - * chunk data. To fully decode each of these chunks, we also make - * sure we have enough data in the buffer for the 4 byte CRC at the - * end of every chunk (except IDAT, which is handled separately). - */ - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) - { - png_byte chunk_length[4]; - - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - } - - if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; - - if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) - { - if (png_ptr->push_length != 13) - png_error(png_ptr, "Invalid IHDR length"); - - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); - - png_ptr->process_mode = PNG_READ_DONE_MODE; - png_push_have_end(png_ptr, info_ptr); - } - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_ptr->mode |= PNG_HAVE_IDAT; - - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); - - if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) - png_ptr->mode |= PNG_HAVE_PLTE; - - else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - } - } - -#endif - else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); - } - - else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - { - /* If we reach an IDAT chunk, this means we have read all of the - * header chunks, and we can start reading the image (or if this - * is called after the image has been read - we have an error). - */ - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - { - if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - if (png_ptr->push_length == 0) - return; - - if (png_ptr->mode & PNG_AFTER_IDAT) - png_error(png_ptr, "Too many IDAT's found"); - } - - png_ptr->idat_size = png_ptr->push_length; - png_ptr->mode |= PNG_HAVE_IDAT; - png_ptr->process_mode = PNG_READ_IDAT_MODE; - png_push_have_info(png_ptr, info_ptr); - png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; - png_ptr->zstream.next_out = png_ptr->row_buf; - return; - } - -#if defined(PNG_READ_gAMA_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_iCCP_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_sPLT_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_bKGD_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_hIST_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); - } -#endif - -#if defined(PNG_READ_pCAL_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_sCAL_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_tIME_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); - } - -#endif - else - { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); - } - - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; -} - -void /* PRIVATE */ -png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) -{ - png_ptr->process_mode = PNG_SKIP_MODE; - png_ptr->skip_length = skip; -} - -void /* PRIVATE */ -png_push_crc_finish(png_structp png_ptr) -{ - if (png_ptr->skip_length && png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size) - save_size = (png_size_t)png_ptr->skip_length; - else - save_size = png_ptr->save_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_ptr->skip_length -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (png_ptr->skip_length && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size) - save_size = (png_size_t)png_ptr->skip_length; - else - save_size = png_ptr->current_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_ptr->skip_length -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } - if (!png_ptr->skip_length) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_crc_finish(png_ptr, 0); - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - } -} - -void PNGAPI -png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) -{ - png_bytep ptr; - - if (png_ptr == NULL) - return; - - ptr = buffer; - if (png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (length < png_ptr->save_buffer_size) - save_size = length; - else - save_size = png_ptr->save_buffer_size; - - png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); - length -= save_size; - ptr += save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (length && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (length < png_ptr->current_buffer_size) - save_size = length; - - else - save_size = png_ptr->current_buffer_size; - - png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } -} - -void /* PRIVATE */ -png_push_save_buffer(png_structp png_ptr) -{ - if (png_ptr->save_buffer_size) - { - if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) - { - png_size_t i, istop; - png_bytep sp; - png_bytep dp; - - istop = png_ptr->save_buffer_size; - for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; - i < istop; i++, sp++, dp++) - { - *dp = *sp; - } - } - } - if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > - png_ptr->save_buffer_max) - { - png_size_t new_max; - png_bytep old_buffer; - - if (png_ptr->save_buffer_size > PNG_SIZE_MAX - - (png_ptr->current_buffer_size + 256)) - { - png_error(png_ptr, "Potential overflow of save_buffer"); - } - - new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; - old_buffer = png_ptr->save_buffer; - png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr, - (png_uint_32)new_max); - png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); - png_free(png_ptr, old_buffer); - png_ptr->save_buffer_max = new_max; - } - if (png_ptr->current_buffer_size) - { - png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, - png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); - png_ptr->save_buffer_size += png_ptr->current_buffer_size; - png_ptr->current_buffer_size = 0; - } - png_ptr->save_buffer_ptr = png_ptr->save_buffer; - png_ptr->buffer_size = 0; -} - -void /* PRIVATE */ -png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, - png_size_t buffer_length) -{ - png_ptr->current_buffer = buffer; - png_ptr->current_buffer_size = buffer_length; - png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; - png_ptr->current_buffer_ptr = png_ptr->current_buffer; -} - -void /* PRIVATE */ -png_push_read_IDAT(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) - { - png_byte chunk_length[4]; - - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); - png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; - - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - { - png_ptr->process_mode = PNG_READ_CHUNK_MODE; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - png_error(png_ptr, "Not enough compressed data"); - return; - } - - png_ptr->idat_size = png_ptr->push_length; - } - if (png_ptr->idat_size && png_ptr->save_buffer_size) - { - png_size_t save_size; - - if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) - { - save_size = (png_size_t)png_ptr->idat_size; - - /* Check for overflow */ - if ((png_uint_32)save_size != png_ptr->idat_size) - png_error(png_ptr, "save_size overflowed in pngpread"); - } - else - save_size = png_ptr->save_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); - - png_ptr->idat_size -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->save_buffer_size -= save_size; - png_ptr->save_buffer_ptr += save_size; - } - if (png_ptr->idat_size && png_ptr->current_buffer_size) - { - png_size_t save_size; - - if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) - { - save_size = (png_size_t)png_ptr->idat_size; - - /* Check for overflow */ - if ((png_uint_32)save_size != png_ptr->idat_size) - png_error(png_ptr, "save_size overflowed in pngpread"); - } - else - save_size = png_ptr->current_buffer_size; - - png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); - - png_ptr->idat_size -= save_size; - png_ptr->buffer_size -= save_size; - png_ptr->current_buffer_size -= save_size; - png_ptr->current_buffer_ptr += save_size; - } - if (!png_ptr->idat_size) - { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_crc_finish(png_ptr, 0); - png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; - png_ptr->mode |= PNG_AFTER_IDAT; - } -} - -void /* PRIVATE */ -png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, - png_size_t buffer_length) -{ - int ret; - - if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length) - png_error(png_ptr, "Extra compression data"); - - png_ptr->zstream.next_in = buffer; - png_ptr->zstream.avail_in = (uInt)buffer_length; - for (;;) - { - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK) - { - if (ret == Z_STREAM_END) - { - if (png_ptr->zstream.avail_in) - png_error(png_ptr, "Extra compressed data"); - - if (!(png_ptr->zstream.avail_out)) - { - png_push_process_row(png_ptr); - } - - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - else if (ret == Z_BUF_ERROR) - break; - - else - png_error(png_ptr, "Decompression Error"); - } - if (!(png_ptr->zstream.avail_out)) - { - if (( -#if defined(PNG_READ_INTERLACING_SUPPORTED) - png_ptr->interlaced && png_ptr->pass > 6) || - (!png_ptr->interlaced && -#endif - png_ptr->row_number == png_ptr->num_rows)) - { - if (png_ptr->zstream.avail_in) - png_warning(png_ptr, "Too much data in IDAT chunks"); - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - png_push_process_row(png_ptr); - png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; - png_ptr->zstream.next_out = png_ptr->row_buf; - } - - else - break; - } -} - -void /* PRIVATE */ -png_push_process_row(png_structp png_ptr) -{ - png_ptr->row_info.color_type = png_ptr->color_type; - png_ptr->row_info.width = png_ptr->iwidth; - png_ptr->row_info.channels = png_ptr->channels; - png_ptr->row_info.bit_depth = png_ptr->bit_depth; - png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; - - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - png_read_filter_row(png_ptr, &(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->prev_row + 1, - (int)(png_ptr->row_buf[0])); - - png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, - png_ptr->rowbytes + 1); - - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); - -#if defined(PNG_READ_INTERLACING_SUPPORTED) - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - if (png_ptr->pass < 6) -/* old interface (pre-1.0.9): - png_do_read_interlace(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); - */ - png_do_read_interlace(png_ptr); - - switch (png_ptr->pass) - { - case 0: - { - int i; - for (i = 0; i < 8 && png_ptr->pass == 0; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ - } - - if (png_ptr->pass == 2) /* Pass 1 might be empty */ - { - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - if (png_ptr->pass == 4 && png_ptr->height <= 4) - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - if (png_ptr->pass == 6 && png_ptr->height <= 4) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - case 1: - { - int i; - for (i = 0; i < 8 && png_ptr->pass == 1; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 2) /* Skip top 4 generated rows */ - { - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 2: - { - int i; - - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - for (i = 0; i < 4 && png_ptr->pass == 2; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 4) /* Pass 3 might be empty */ - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 3: - { - int i; - - for (i = 0; i < 4 && png_ptr->pass == 3; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 4) /* Skip top two generated rows */ - { - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - - break; - } - - case 4: - { - int i; - - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - for (i = 0; i < 2 && png_ptr->pass == 4; i++) - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 6) /* Pass 5 might be empty */ - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - - case 5: - { - int i; - - for (i = 0; i < 2 && png_ptr->pass == 5; i++) - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } - - if (png_ptr->pass == 6) /* Skip top generated row */ - { - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - - break; - } - case 6: - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - - if (png_ptr->pass != 6) - break; - - png_push_have_row(png_ptr, png_bytep_NULL); - png_read_push_finish_row(png_ptr); - } - } - } - else -#endif - { - png_push_have_row(png_ptr, png_ptr->row_buf + 1); - png_read_push_finish_row(png_ptr); - } -} - -void /* PRIVATE */ -png_read_push_finish_row(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; - - /* Height of interlace block. This is not currently used - if you need - * it, uncomment it here and in png.h - PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; - */ -#endif - - png_ptr->row_number++; - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#if defined(PNG_READ_INTERLACING_SUPPORTED) - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - png_memset_check(png_ptr, png_ptr->prev_row, 0, - png_ptr->rowbytes + 1); - do - { - png_ptr->pass++; - if ((png_ptr->pass == 1 && png_ptr->width < 5) || - (png_ptr->pass == 3 && png_ptr->width < 3) || - (png_ptr->pass == 5 && png_ptr->width < 2)) - png_ptr->pass++; - - if (png_ptr->pass > 7) - png_ptr->pass--; - - if (png_ptr->pass >= 7) - break; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; - - if (png_ptr->transformations & PNG_INTERLACE) - break; - - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - - } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); - } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -} - -#if defined(PNG_READ_tEXt_SUPPORTED) -void /* PRIVATE */ -png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 - length) -{ - if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) - { - png_error(png_ptr, "Out of place tEXt"); - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#ifdef PNG_MAX_MALLOC_64K - png_ptr->skip_length = 0; /* This may not be necessary */ - - if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ - { - png_warning(png_ptr, "tEXt chunk too large to fit in memory"); - png_ptr->skip_length = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_ptr->current_text = (png_charp)png_malloc(png_ptr, - (png_uint_32)(length + 1)); - png_ptr->current_text[length] = '\0'; - png_ptr->current_text_ptr = png_ptr->current_text; - png_ptr->current_text_size = (png_size_t)length; - png_ptr->current_text_left = (png_size_t)length; - png_ptr->process_mode = PNG_READ_tEXt_MODE; -} - -void /* PRIVATE */ -png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr->buffer_size && png_ptr->current_text_left) - { - png_size_t text_size; - - if (png_ptr->buffer_size < png_ptr->current_text_left) - text_size = png_ptr->buffer_size; - - else - text_size = png_ptr->current_text_left; - - png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); - png_ptr->current_text_left -= text_size; - png_ptr->current_text_ptr += text_size; - } - if (!(png_ptr->current_text_left)) - { - png_textp text_ptr; - png_charp text; - png_charp key; - int ret; - - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_crc_finish(png_ptr); - -#if defined(PNG_MAX_MALLOC_64K) - if (png_ptr->skip_length) - return; -#endif - - key = png_ptr->current_text; - - for (text = key; *text; text++) - /* Empty loop */ ; - - if (text < key + png_ptr->current_text_size) - text++; - - text_ptr = (png_textp)png_malloc(png_ptr, - (png_uint_32)png_sizeof(png_text)); - text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->key = key; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; -#endif - text_ptr->text = text; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, key); - png_free(png_ptr, text_ptr); - png_ptr->current_text = NULL; - - if (ret) - png_warning(png_ptr, "Insufficient memory to store text chunk."); - } -} -#endif - -#if defined(PNG_READ_zTXt_SUPPORTED) -void /* PRIVATE */ -png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 - length) -{ - if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) - { - png_error(png_ptr, "Out of place zTXt"); - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#ifdef PNG_MAX_MALLOC_64K - /* We can't handle zTXt chunks > 64K, since we don't have enough space - * to be able to store the uncompressed data. Actually, the threshold - * is probably around 32K, but it isn't as definite as 64K is. - */ - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "zTXt chunk too large to fit in memory"); - png_push_crc_skip(png_ptr, length); - return; - } -#endif - - png_ptr->current_text = (png_charp)png_malloc(png_ptr, - (png_uint_32)(length + 1)); - png_ptr->current_text[length] = '\0'; - png_ptr->current_text_ptr = png_ptr->current_text; - png_ptr->current_text_size = (png_size_t)length; - png_ptr->current_text_left = (png_size_t)length; - png_ptr->process_mode = PNG_READ_zTXt_MODE; -} - -void /* PRIVATE */ -png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr->buffer_size && png_ptr->current_text_left) - { - png_size_t text_size; - - if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left) - text_size = png_ptr->buffer_size; - - else - text_size = png_ptr->current_text_left; - - png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); - png_ptr->current_text_left -= text_size; - png_ptr->current_text_ptr += text_size; - } - if (!(png_ptr->current_text_left)) - { - png_textp text_ptr; - png_charp text; - png_charp key; - int ret; - png_size_t text_size, key_size; - - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_crc_finish(png_ptr); - - key = png_ptr->current_text; - - for (text = key; *text; text++) - /* Empty loop */ ; - - /* zTXt can't have zero text */ - if (text >= key + png_ptr->current_text_size) - { - png_ptr->current_text = NULL; - png_free(png_ptr, key); - return; - } - - text++; - - if (*text != PNG_TEXT_COMPRESSION_zTXt) /* Check compression byte */ - { - png_ptr->current_text = NULL; - png_free(png_ptr, key); - return; - } - - text++; - - png_ptr->zstream.next_in = (png_bytep )text; - png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size - - (text - key)); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - key_size = text - key; - text_size = 0; - text = NULL; - ret = Z_STREAM_END; - - while (png_ptr->zstream.avail_in) - { - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - png_ptr->current_text = NULL; - png_free(png_ptr, key); - png_free(png_ptr, text); - return; - } - if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END) - { - if (text == NULL) - { - text = (png_charp)png_malloc(png_ptr, - (png_uint_32)(png_ptr->zbuf_size - - png_ptr->zstream.avail_out + key_size + 1)); - - png_memcpy(text + key_size, png_ptr->zbuf, - png_ptr->zbuf_size - png_ptr->zstream.avail_out); - - png_memcpy(text, key, key_size); - - text_size = key_size + png_ptr->zbuf_size - - png_ptr->zstream.avail_out; - - *(text + text_size) = '\0'; - } - else - { - png_charp tmp; - - tmp = text; - text = (png_charp)png_malloc(png_ptr, text_size + - (png_uint_32)(png_ptr->zbuf_size - - png_ptr->zstream.avail_out + 1)); - - png_memcpy(text, tmp, text_size); - png_free(png_ptr, tmp); - - png_memcpy(text + text_size, png_ptr->zbuf, - png_ptr->zbuf_size - png_ptr->zstream.avail_out); - - text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; - *(text + text_size) = '\0'; - } - if (ret != Z_STREAM_END) - { - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - } - else - { - break; - } - - if (ret == Z_STREAM_END) - break; - } - - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - - if (ret != Z_STREAM_END) - { - png_ptr->current_text = NULL; - png_free(png_ptr, key); - png_free(png_ptr, text); - return; - } - - png_ptr->current_text = NULL; - png_free(png_ptr, key); - key = text; - text += key_size; - - text_ptr = (png_textp)png_malloc(png_ptr, - (png_uint_32)png_sizeof(png_text)); - text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; - text_ptr->key = key; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; -#endif - text_ptr->text = text; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, key); - png_free(png_ptr, text_ptr); - - if (ret) - png_warning(png_ptr, "Insufficient memory to store text chunk."); - } -} -#endif - -#if defined(PNG_READ_iTXt_SUPPORTED) -void /* PRIVATE */ -png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 - length) -{ - if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) - { - png_error(png_ptr, "Out of place iTXt"); - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#ifdef PNG_MAX_MALLOC_64K - png_ptr->skip_length = 0; /* This may not be necessary */ - - if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ - { - png_warning(png_ptr, "iTXt chunk too large to fit in memory"); - png_ptr->skip_length = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_ptr->current_text = (png_charp)png_malloc(png_ptr, - (png_uint_32)(length + 1)); - png_ptr->current_text[length] = '\0'; - png_ptr->current_text_ptr = png_ptr->current_text; - png_ptr->current_text_size = (png_size_t)length; - png_ptr->current_text_left = (png_size_t)length; - png_ptr->process_mode = PNG_READ_iTXt_MODE; -} - -void /* PRIVATE */ -png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) -{ - - if (png_ptr->buffer_size && png_ptr->current_text_left) - { - png_size_t text_size; - - if (png_ptr->buffer_size < png_ptr->current_text_left) - text_size = png_ptr->buffer_size; - - else - text_size = png_ptr->current_text_left; - - png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); - png_ptr->current_text_left -= text_size; - png_ptr->current_text_ptr += text_size; - } - if (!(png_ptr->current_text_left)) - { - png_textp text_ptr; - png_charp key; - int comp_flag; - png_charp lang; - png_charp lang_key; - png_charp text; - int ret; - - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - - png_push_crc_finish(png_ptr); - -#if defined(PNG_MAX_MALLOC_64K) - if (png_ptr->skip_length) - return; -#endif - - key = png_ptr->current_text; - - for (lang = key; *lang; lang++) - /* Empty loop */ ; - - if (lang < key + png_ptr->current_text_size - 3) - lang++; - - comp_flag = *lang++; - lang++; /* Skip comp_type, always zero */ - - for (lang_key = lang; *lang_key; lang_key++) - /* Empty loop */ ; - - lang_key++; /* Skip NUL separator */ - - text=lang_key; - - if (lang_key < key + png_ptr->current_text_size - 1) - { - for (; *text; text++) - /* Empty loop */ ; - } - - if (text < key + png_ptr->current_text_size) - text++; - - text_ptr = (png_textp)png_malloc(png_ptr, - (png_uint_32)png_sizeof(png_text)); - - text_ptr->compression = comp_flag + 2; - text_ptr->key = key; - text_ptr->lang = lang; - text_ptr->lang_key = lang_key; - text_ptr->text = text; - text_ptr->text_length = 0; - text_ptr->itxt_length = png_strlen(text); - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_ptr->current_text = NULL; - - png_free(png_ptr, text_ptr); - if (ret) - png_warning(png_ptr, "Insufficient memory to store iTXt chunk."); - } -} -#endif - -/* This function is called when we haven't found a handler for this - * chunk. If there isn't a problem with the chunk itself (ie a bad chunk - * name or a critical chunk), the chunk is (currently) silently ignored. - */ -void /* PRIVATE */ -png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 - length) -{ - png_uint_32 skip = 0; - - if (!(png_ptr->chunk_name[0] & 0x20)) - { -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - - info_ptr = info_ptr; /* To quiet some compiler warnings */ - } - -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) - { -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "unknown chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - png_memcpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof(png_ptr->unknown_chunk.name)); - png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name) - 1] - = '\0'; - - png_ptr->unknown_chunk.size = (png_size_t)length; - - if (length == 0) - png_ptr->unknown_chunk.data = NULL; - - else - { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, - (png_uint_32)length); - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); - } - -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) - if (png_ptr->read_user_chunk_fn != NULL) - { - /* Callback to user unknown chunk handler */ - int ret; - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); - - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - - if (ret == 0) - { - if (!(png_ptr->chunk_name[0] & 0x20)) - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) - png_chunk_error(png_ptr, "unknown critical chunk"); - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - } - } - - else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - - else -#endif - skip=length; - png_push_crc_skip(png_ptr, skip); -} - -void /* PRIVATE */ -png_push_have_info(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr->info_fn != NULL) - (*(png_ptr->info_fn))(png_ptr, info_ptr); -} - -void /* PRIVATE */ -png_push_have_end(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr->end_fn != NULL) - (*(png_ptr->end_fn))(png_ptr, info_ptr); -} - -void /* PRIVATE */ -png_push_have_row(png_structp png_ptr, png_bytep row) -{ - if (png_ptr->row_fn != NULL) - (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, - (int)png_ptr->pass); -} - -void PNGAPI -png_progressive_combine_row (png_structp png_ptr, - png_bytep old_row, png_bytep new_row) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST int FARDATA png_pass_dsp_mask[7] = - {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; -#endif - if (png_ptr == NULL) - return; - - if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */ - png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]); -} - -void PNGAPI -png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, - png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, - png_progressive_end_ptr end_fn) -{ - if (png_ptr == NULL) - return; - - png_ptr->info_fn = info_fn; - png_ptr->row_fn = row_fn; - png_ptr->end_fn = end_fn; - - png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); -} - -png_voidp PNGAPI -png_get_progressive_ptr(png_structp png_ptr) -{ - if (png_ptr == NULL) - return (NULL); - - return png_ptr->io_ptr; -} -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c deleted file mode 100644 index a4cbb3e..0000000 --- a/src/3rdparty/libpng/pngread.c +++ /dev/null @@ -1,1473 +0,0 @@ - -/* pngread.c - read a PNG file - * - * Last changed in libpng 1.2.37 [June 4, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains routines that an application calls directly to - * read a PNG file or stream. - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) - -/* Create a PNG structure for reading, and allocate any memory needed. */ -png_structp PNGAPI -png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn) -{ - -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); -} - -/* Alternate create PNG structure for reading, and allocate any memory needed. */ -png_structp PNGAPI -png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn) -{ -#endif /* PNG_USER_MEM_SUPPORTED */ - -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - - int i; - - png_debug(1, "in png_create_read_struct"); -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif - if (png_ptr == NULL) - return (NULL); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max=PNG_USER_WIDTH_MAX; - png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; -#endif - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_ptr->jmpbuf)) -#endif - { - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, - (png_free_ptr)free_fn, (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - return (NULL); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif - -#ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); -#endif - - png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - - if (user_png_ver) - { - i = 0; - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - else - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - - - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) - { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first digit. - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - char msg[80]; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "Application is running with png.c from libpng-%.20s", - png_libpng_ver); - png_warning(png_ptr, msg); -#endif -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "Incompatible libpng version in application and library"); - } - } - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - switch (inflateInit(&png_ptr->zstream)) - { - case Z_OK: /* Do nothing */ break; - case Z_MEM_ERROR: - case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; - case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; - default: png_error(png_ptr, "Unknown zlib error"); - } - - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); - -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then encounter - a png_error() will longjmp here. Since the jmpbuf is then meaningless we - abort instead of returning. */ -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) - PNG_ABORT(); - png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); -#else - if (setjmp(png_ptr->jmpbuf)) - PNG_ABORT(); -#endif -#endif - return (png_ptr); -} - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* Initialize PNG structure for reading, and allocate any memory needed. - This interface is deprecated in favour of the png_create_read_struct(), - and it will disappear as of libpng-1.3.0. */ -#undef png_read_init -void PNGAPI -png_read_init(png_structp png_ptr) -{ - /* We only come here via pre-1.0.7-compiled applications */ - png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0); -} - -void PNGAPI -png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, - png_size_t png_struct_size, png_size_t png_info_size) -{ - /* We only come here via pre-1.0.12-compiled applications */ - if (png_ptr == NULL) - return; -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - if (png_sizeof(png_struct) > png_struct_size || - png_sizeof(png_info) > png_info_size) - { - char msg[80]; - png_ptr->warning_fn = NULL; - if (user_png_ver) - { - png_snprintf(msg, 80, - "Application was compiled with png.h from libpng-%.20s", - user_png_ver); - png_warning(png_ptr, msg); - } - png_snprintf(msg, 80, - "Application is running with png.c from libpng-%.20s", - png_libpng_ver); - png_warning(png_ptr, msg); - } -#endif - if (png_sizeof(png_struct) > png_struct_size) - { - png_ptr->error_fn = NULL; -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "The png struct allocated by the application for reading is too small."); - } - if (png_sizeof(png_info) > png_info_size) - { - png_ptr->error_fn = NULL; -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_error(png_ptr, - "The info struct allocated by application for reading is too small."); - } - png_read_init_3(&png_ptr, user_png_ver, png_struct_size); -} -#endif /* PNG_1_0_X || PNG_1_2_X */ - -void PNGAPI -png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, - png_size_t png_struct_size) -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; /* to save current jump buffer */ -#endif - - int i = 0; - - png_structp png_ptr=*ptr_ptr; - - if (png_ptr == NULL) - return; - - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - { -#ifdef PNG_LEGACY_SUPPORTED - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; -#else - png_ptr->warning_fn = NULL; - png_warning(png_ptr, - "Application uses deprecated png_read_init() and should be recompiled."); - break; -#endif - } - } while (png_libpng_ver[i++]); - - png_debug(1, "in png_read_init_3"); - -#ifdef PNG_SETJMP_SUPPORTED - /* Save jump buffer and error functions */ - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); -#endif - - if (png_sizeof(png_struct) > png_struct_size) - { - png_destroy_struct(png_ptr); - *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); - png_ptr = *ptr_ptr; - } - - /* Reset all variables to 0 */ - png_memset(png_ptr, 0, png_sizeof(png_struct)); - -#ifdef PNG_SETJMP_SUPPORTED - /* Restore jump buffer */ - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif - - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max=PNG_USER_WIDTH_MAX; - png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; -#endif - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, - (png_uint_32)png_ptr->zbuf_size); - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - switch (inflateInit(&png_ptr->zstream)) - { - case Z_OK: /* Do nothing */ break; - case Z_MEM_ERROR: - case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break; - case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break; - default: png_error(png_ptr, "Unknown zlib error"); - } - - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL); -} - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the information before the actual image data. This has been - * changed in v0.90 to allow reading a file that already has the magic - * bytes read from the stream. You can tell libpng how many bytes have - * been read from the beginning of the stream (up to the maximum of 8) - * via png_set_sig_bytes(), and we will only check the remaining bytes - * here. The application can then have access to the signature bytes we - * read if it is determined that this isn't a valid PNG file. - */ -void PNGAPI -png_read_info(png_structp png_ptr, png_infop info_ptr) -{ - if (png_ptr == NULL || info_ptr == NULL) - return; - png_debug(1, "in png_read_info"); - /* If we haven't checked all of the PNG signature bytes, do so now. */ - if (png_ptr->sig_bytes < 8) - { - png_size_t num_checked = png_ptr->sig_bytes, - num_to_check = 8 - num_checked; - - png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); - png_ptr->sig_bytes = 8; - - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) - { - if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) - png_error(png_ptr, "Not a PNG file"); - else - png_error(png_ptr, "PNG file corrupted by ASCII conversion"); - } - if (num_checked < 3) - png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; - } - - for (;;) - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IHDR; - PNG_CONST PNG_IDAT; - PNG_CONST PNG_IEND; - PNG_CONST PNG_PLTE; -#if defined(PNG_READ_bKGD_SUPPORTED) - PNG_CONST PNG_bKGD; -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) - PNG_CONST PNG_cHRM; -#endif -#if defined(PNG_READ_gAMA_SUPPORTED) - PNG_CONST PNG_gAMA; -#endif -#if defined(PNG_READ_hIST_SUPPORTED) - PNG_CONST PNG_hIST; -#endif -#if defined(PNG_READ_iCCP_SUPPORTED) - PNG_CONST PNG_iCCP; -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - PNG_CONST PNG_iTXt; -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) - PNG_CONST PNG_oFFs; -#endif -#if defined(PNG_READ_pCAL_SUPPORTED) - PNG_CONST PNG_pCAL; -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) - PNG_CONST PNG_pHYs; -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) - PNG_CONST PNG_sBIT; -#endif -#if defined(PNG_READ_sCAL_SUPPORTED) - PNG_CONST PNG_sCAL; -#endif -#if defined(PNG_READ_sPLT_SUPPORTED) - PNG_CONST PNG_sPLT; -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) - PNG_CONST PNG_sRGB; -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) - PNG_CONST PNG_tEXt; -#endif -#if defined(PNG_READ_tIME_SUPPORTED) - PNG_CONST PNG_tIME; -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) - PNG_CONST PNG_tRNS; -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - PNG_CONST PNG_zTXt; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - png_uint_32 length = png_read_chunk_header(png_ptr); - PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; - - /* This should be a binary subdivision search or a hash for - * matching the chunk name rather than a linear search. - */ - if (!png_memcmp(chunk_name, png_IDAT, 4)) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; - - if (!png_memcmp(chunk_name, png_IHDR, 4)) - png_handle_IHDR(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IEND, 4)) - png_handle_IEND(png_ptr, info_ptr, length); -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, chunk_name)) - { - if (!png_memcmp(chunk_name, png_IDAT, 4)) - png_ptr->mode |= PNG_HAVE_IDAT; - png_handle_unknown(png_ptr, info_ptr, length); - if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_ptr->mode |= PNG_HAVE_PLTE; - else if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - break; - } - } -#endif - else if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_handle_PLTE(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - - png_ptr->idat_size = length; - png_ptr->mode |= PNG_HAVE_IDAT; - break; - } -#if defined(PNG_READ_bKGD_SUPPORTED) - else if (!png_memcmp(chunk_name, png_bKGD, 4)) - png_handle_bKGD(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) - else if (!png_memcmp(chunk_name, png_cHRM, 4)) - png_handle_cHRM(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_gAMA_SUPPORTED) - else if (!png_memcmp(chunk_name, png_gAMA, 4)) - png_handle_gAMA(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_hIST_SUPPORTED) - else if (!png_memcmp(chunk_name, png_hIST, 4)) - png_handle_hIST(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) - else if (!png_memcmp(chunk_name, png_oFFs, 4)) - png_handle_oFFs(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_pCAL_SUPPORTED) - else if (!png_memcmp(chunk_name, png_pCAL, 4)) - png_handle_pCAL(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sCAL_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sCAL, 4)) - png_handle_sCAL(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) - else if (!png_memcmp(chunk_name, png_pHYs, 4)) - png_handle_pHYs(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sBIT, 4)) - png_handle_sBIT(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sRGB, 4)) - png_handle_sRGB(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_iCCP_SUPPORTED) - else if (!png_memcmp(chunk_name, png_iCCP, 4)) - png_handle_iCCP(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sPLT_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sPLT, 4)) - png_handle_sPLT(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) - else if (!png_memcmp(chunk_name, png_tEXt, 4)) - png_handle_tEXt(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_tIME_SUPPORTED) - else if (!png_memcmp(chunk_name, png_tIME, 4)) - png_handle_tIME(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) - else if (!png_memcmp(chunk_name, png_tRNS, 4)) - png_handle_tRNS(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - else if (!png_memcmp(chunk_name, png_zTXt, 4)) - png_handle_zTXt(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - else if (!png_memcmp(chunk_name, png_iTXt, 4)) - png_handle_iTXt(png_ptr, info_ptr, length); -#endif - else - png_handle_unknown(png_ptr, info_ptr, length); - } -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -/* Optional call to update the users info_ptr structure */ -void PNGAPI -png_read_update_info(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_update_info"); - if (png_ptr == NULL) - return; - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); - else - png_warning(png_ptr, - "Ignoring extra png_read_update_info() call; row buffer not reallocated"); - png_read_transform_info(png_ptr, info_ptr); -} - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Initialize palette, background, etc, after transformations - * are set, but before any reading takes place. This allows - * the user to obtain a gamma-corrected palette, for example. - * If the user doesn't call this, we will do it ourselves. - */ -void PNGAPI -png_start_read_image(png_structp png_ptr) -{ - png_debug(1, "in png_start_read_image"); - if (png_ptr == NULL) - return; - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -void PNGAPI -png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) -{ -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; - PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, - 0xff}; - PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; -#endif - int ret; - if (png_ptr == NULL) - return; - png_debug2(1, "in png_read_row (row %lu, pass %d)", - png_ptr->row_number, png_ptr->pass); - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - png_read_start_row(png_ptr); - if (png_ptr->row_number == 0 && png_ptr->pass == 0) - { - /* Check for transforms that have been set but were defined out */ -#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) - png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) - png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) - png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) - png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) - png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined."); -#endif -#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined."); -#endif - } - -#if defined(PNG_READ_INTERLACING_SUPPORTED) - /* If interlaced and we do not need a new row, combine row and return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) - { - switch (png_ptr->pass) - { - case 0: - if (png_ptr->row_number & 0x07) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 2: - if ((png_ptr->row_number & 0x07) != 4) - { - if (dsp_row != NULL && (png_ptr->row_number & 4)) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 3: - if ((png_ptr->row_number & 3) || png_ptr->width < 3) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 4: - if ((png_ptr->row_number & 3) != 2) - { - if (dsp_row != NULL && (png_ptr->row_number & 2)) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 5: - if ((png_ptr->row_number & 1) || png_ptr->width < 2) - { - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - png_read_finish_row(png_ptr); - return; - } - break; - case 6: - if (!(png_ptr->row_number & 1)) - { - png_read_finish_row(png_ptr); - return; - } - break; - } - } -#endif - - if (!(png_ptr->mode & PNG_HAVE_IDAT)) - png_error(png_ptr, "Invalid attempt to read row data"); - - png_ptr->zstream.next_out = png_ptr->row_buf; - png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; - do - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_crc_finish(png_ptr, 0); - - png_ptr->idat_size = png_read_chunk_header(png_ptr); - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_error(png_ptr, "Not enough image data"); - } - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - png_crc_read(png_ptr, png_ptr->zbuf, - (png_size_t)png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret == Z_STREAM_END) - { - if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_error(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression error"); - - } while (png_ptr->zstream.avail_out); - - png_ptr->row_info.color_type = png_ptr->color_type; - png_ptr->row_info.width = png_ptr->iwidth; - png_ptr->row_info.channels = png_ptr->channels; - png_ptr->row_info.bit_depth = png_ptr->bit_depth; - png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - if (png_ptr->row_buf[0]) - png_read_filter_row(png_ptr, &(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->prev_row + 1, - (int)(png_ptr->row_buf[0])); - - png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, - png_ptr->rowbytes + 1); - -#if defined(PNG_MNG_FEATURES_SUPPORTED) - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) - { - /* Intrapixel differencing */ - png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); - } -#endif - - - if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) - png_do_read_transformations(png_ptr); - -#if defined(PNG_READ_INTERLACING_SUPPORTED) - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && - (png_ptr->transformations & PNG_INTERLACE)) - { - if (png_ptr->pass < 6) - /* Old interface (pre-1.0.9): - * png_do_read_interlace(&(png_ptr->row_info), - * png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); - */ - png_do_read_interlace(png_ptr); - - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, - png_pass_dsp_mask[png_ptr->pass]); - if (row != NULL) - png_combine_row(png_ptr, row, - png_pass_mask[png_ptr->pass]); - } - else -#endif - { - if (row != NULL) - png_combine_row(png_ptr, row, 0xff); - if (dsp_row != NULL) - png_combine_row(png_ptr, dsp_row, 0xff); - } - png_read_finish_row(png_ptr); - - if (png_ptr->read_row_fn != NULL) - (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read one or more rows of image data. If the image is interlaced, - * and png_set_interlace_handling() has been called, the rows need to - * contain the contents of the rows from the previous pass. If the - * image has alpha or transparency, and png_handle_alpha()[*] has been - * called, the rows contents must be initialized to the contents of the - * screen. - * - * "row" holds the actual image, and pixels are placed in it - * as they arrive. If the image is displayed after each pass, it will - * appear to "sparkle" in. "display_row" can be used to display a - * "chunky" progressive image, with finer detail added as it becomes - * available. If you do not want this "chunky" display, you may pass - * NULL for display_row. If you do not want the sparkle display, and - * you have not called png_handle_alpha(), you may pass NULL for rows. - * If you have called png_handle_alpha(), and the image has either an - * alpha channel or a transparency chunk, you must provide a buffer for - * rows. In this case, you do not have to provide a display_row buffer - * also, but you may. If the image is not interlaced, or if you have - * not called png_set_interlace_handling(), the display_row buffer will - * be ignored, so pass NULL to it. - * - * [*] png_handle_alpha() does not exist yet, as of this version of libpng - */ - -void PNGAPI -png_read_rows(png_structp png_ptr, png_bytepp row, - png_bytepp display_row, png_uint_32 num_rows) -{ - png_uint_32 i; - png_bytepp rp; - png_bytepp dp; - - png_debug(1, "in png_read_rows"); - if (png_ptr == NULL) - return; - rp = row; - dp = display_row; - if (rp != NULL && dp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep rptr = *rp++; - png_bytep dptr = *dp++; - - png_read_row(png_ptr, rptr, dptr); - } - else if (rp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep rptr = *rp; - png_read_row(png_ptr, rptr, png_bytep_NULL); - rp++; - } - else if (dp != NULL) - for (i = 0; i < num_rows; i++) - { - png_bytep dptr = *dp; - png_read_row(png_ptr, png_bytep_NULL, dptr); - dp++; - } -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the entire image. If the image has an alpha channel or a tRNS - * chunk, and you have called png_handle_alpha()[*], you will need to - * initialize the image to the current image that PNG will be overlaying. - * We set the num_rows again here, in case it was incorrectly set in - * png_read_start_row() by a call to png_read_update_info() or - * png_start_read_image() if png_set_interlace_handling() wasn't called - * prior to either of these functions like it should have been. You can - * only call this function once. If you desire to have an image for - * each pass of a interlaced image, use png_read_rows() instead. - * - * [*] png_handle_alpha() does not exist yet, as of this version of libpng - */ -void PNGAPI -png_read_image(png_structp png_ptr, png_bytepp image) -{ - png_uint_32 i, image_height; - int pass, j; - png_bytepp rp; - - png_debug(1, "in png_read_image"); - if (png_ptr == NULL) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - pass = png_set_interlace_handling(png_ptr); -#else - if (png_ptr->interlaced) - png_error(png_ptr, - "Cannot read interlaced image -- interlace handler disabled."); - pass = 1; -#endif - - - image_height=png_ptr->height; - png_ptr->num_rows = image_height; /* Make sure this is set correctly */ - - for (j = 0; j < pass; j++) - { - rp = image; - for (i = 0; i < image_height; i++) - { - png_read_row(png_ptr, *rp, png_bytep_NULL); - rp++; - } - } -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -/* Read the end of the PNG file. Will not read past the end of the - * file, will verify the end is accurate, and will read any comments - * or time information at the end of the file, if info is not NULL. - */ -void PNGAPI -png_read_end(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_end"); - if (png_ptr == NULL) - return; - png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ - - do - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IHDR; - PNG_CONST PNG_IDAT; - PNG_CONST PNG_IEND; - PNG_CONST PNG_PLTE; -#if defined(PNG_READ_bKGD_SUPPORTED) - PNG_CONST PNG_bKGD; -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) - PNG_CONST PNG_cHRM; -#endif -#if defined(PNG_READ_gAMA_SUPPORTED) - PNG_CONST PNG_gAMA; -#endif -#if defined(PNG_READ_hIST_SUPPORTED) - PNG_CONST PNG_hIST; -#endif -#if defined(PNG_READ_iCCP_SUPPORTED) - PNG_CONST PNG_iCCP; -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - PNG_CONST PNG_iTXt; -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) - PNG_CONST PNG_oFFs; -#endif -#if defined(PNG_READ_pCAL_SUPPORTED) - PNG_CONST PNG_pCAL; -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) - PNG_CONST PNG_pHYs; -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) - PNG_CONST PNG_sBIT; -#endif -#if defined(PNG_READ_sCAL_SUPPORTED) - PNG_CONST PNG_sCAL; -#endif -#if defined(PNG_READ_sPLT_SUPPORTED) - PNG_CONST PNG_sPLT; -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) - PNG_CONST PNG_sRGB; -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) - PNG_CONST PNG_tEXt; -#endif -#if defined(PNG_READ_tIME_SUPPORTED) - PNG_CONST PNG_tIME; -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) - PNG_CONST PNG_tRNS; -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - PNG_CONST PNG_zTXt; -#endif -#endif /* PNG_USE_LOCAL_ARRAYS */ - png_uint_32 length = png_read_chunk_header(png_ptr); - PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; - - if (!png_memcmp(chunk_name, png_IHDR, 4)) - png_handle_IHDR(png_ptr, info_ptr, length); - else if (!png_memcmp(chunk_name, png_IEND, 4)) - png_handle_IEND(png_ptr, info_ptr, length); -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_handle_as_unknown(png_ptr, chunk_name)) - { - if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - png_error(png_ptr, "Too many IDAT's found"); - } - png_handle_unknown(png_ptr, info_ptr, length); - if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_ptr->mode |= PNG_HAVE_PLTE; - } -#endif - else if (!png_memcmp(chunk_name, png_IDAT, 4)) - { - /* Zero length IDATs are legal after the last IDAT has been - * read, but not after other chunks have been read. - */ - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - png_error(png_ptr, "Too many IDAT's found"); - png_crc_finish(png_ptr, length); - } - else if (!png_memcmp(chunk_name, png_PLTE, 4)) - png_handle_PLTE(png_ptr, info_ptr, length); -#if defined(PNG_READ_bKGD_SUPPORTED) - else if (!png_memcmp(chunk_name, png_bKGD, 4)) - png_handle_bKGD(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_cHRM_SUPPORTED) - else if (!png_memcmp(chunk_name, png_cHRM, 4)) - png_handle_cHRM(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_gAMA_SUPPORTED) - else if (!png_memcmp(chunk_name, png_gAMA, 4)) - png_handle_gAMA(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_hIST_SUPPORTED) - else if (!png_memcmp(chunk_name, png_hIST, 4)) - png_handle_hIST(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_oFFs_SUPPORTED) - else if (!png_memcmp(chunk_name, png_oFFs, 4)) - png_handle_oFFs(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_pCAL_SUPPORTED) - else if (!png_memcmp(chunk_name, png_pCAL, 4)) - png_handle_pCAL(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sCAL_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sCAL, 4)) - png_handle_sCAL(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_pHYs_SUPPORTED) - else if (!png_memcmp(chunk_name, png_pHYs, 4)) - png_handle_pHYs(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sBIT_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sBIT, 4)) - png_handle_sBIT(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sRGB_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sRGB, 4)) - png_handle_sRGB(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_iCCP_SUPPORTED) - else if (!png_memcmp(chunk_name, png_iCCP, 4)) - png_handle_iCCP(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_sPLT_SUPPORTED) - else if (!png_memcmp(chunk_name, png_sPLT, 4)) - png_handle_sPLT(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_tEXt_SUPPORTED) - else if (!png_memcmp(chunk_name, png_tEXt, 4)) - png_handle_tEXt(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_tIME_SUPPORTED) - else if (!png_memcmp(chunk_name, png_tIME, 4)) - png_handle_tIME(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_tRNS_SUPPORTED) - else if (!png_memcmp(chunk_name, png_tRNS, 4)) - png_handle_tRNS(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) - else if (!png_memcmp(chunk_name, png_zTXt, 4)) - png_handle_zTXt(png_ptr, info_ptr, length); -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) - else if (!png_memcmp(chunk_name, png_iTXt, 4)) - png_handle_iTXt(png_ptr, info_ptr, length); -#endif - else - png_handle_unknown(png_ptr, info_ptr, length); - } while (!(png_ptr->mode & PNG_HAVE_IEND)); -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -/* Free all memory used by the read */ -void PNGAPI -png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, - png_infopp end_info_ptr_ptr) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL, end_info_ptr = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; -#endif - - png_debug(1, "in png_destroy_read_struct"); - if (png_ptr_ptr != NULL) - png_ptr = *png_ptr_ptr; - if (png_ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (end_info_ptr_ptr != NULL) - end_info_ptr = *end_info_ptr_ptr; - - png_read_destroy(png_ptr, info_ptr, end_info_ptr); - - if (info_ptr != NULL) - { -#if defined(PNG_TEXT_SUPPORTED) - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); -#endif - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } - - if (end_info_ptr != NULL) - { -#if defined(PNG_READ_TEXT_SUPPORTED) - png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); -#endif -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)end_info_ptr); -#endif - *end_info_ptr_ptr = NULL; - } - - if (png_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - *png_ptr_ptr = NULL; - } -} - -/* Free all memory used by the read (old method) */ -void /* PRIVATE */ -png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr) -{ -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; -#endif - png_error_ptr error_fn; - png_error_ptr warning_fn; - png_voidp error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn; -#endif - - png_debug(1, "in png_read_destroy"); - if (info_ptr != NULL) - png_info_destroy(png_ptr, info_ptr); - - if (end_info_ptr != NULL) - png_info_destroy(png_ptr, end_info_ptr); - - png_free(png_ptr, png_ptr->zbuf); - png_free(png_ptr, png_ptr->big_row_buf); - png_free(png_ptr, png_ptr->prev_row); - png_free(png_ptr, png_ptr->chunkdata); -#if defined(PNG_READ_DITHER_SUPPORTED) - png_free(png_ptr, png_ptr->palette_lookup); - png_free(png_ptr, png_ptr->dither_index); -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) - png_free(png_ptr, png_ptr->gamma_table); -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - png_free(png_ptr, png_ptr->gamma_from_1); - png_free(png_ptr, png_ptr->gamma_to_1); -#endif -#ifdef PNG_FREE_ME_SUPPORTED - if (png_ptr->free_me & PNG_FREE_PLTE) - png_zfree(png_ptr, png_ptr->palette); - png_ptr->free_me &= ~PNG_FREE_PLTE; -#else - if (png_ptr->flags & PNG_FLAG_FREE_PLTE) - png_zfree(png_ptr, png_ptr->palette); - png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; -#endif -#if defined(PNG_tRNS_SUPPORTED) || \ - defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) -#ifdef PNG_FREE_ME_SUPPORTED - if (png_ptr->free_me & PNG_FREE_TRNS) - png_free(png_ptr, png_ptr->trans); - png_ptr->free_me &= ~PNG_FREE_TRNS; -#else - if (png_ptr->flags & PNG_FLAG_FREE_TRNS) - png_free(png_ptr, png_ptr->trans); - png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; -#endif -#endif -#if defined(PNG_READ_hIST_SUPPORTED) -#ifdef PNG_FREE_ME_SUPPORTED - if (png_ptr->free_me & PNG_FREE_HIST) - png_free(png_ptr, png_ptr->hist); - png_ptr->free_me &= ~PNG_FREE_HIST; -#else - if (png_ptr->flags & PNG_FLAG_FREE_HIST) - png_free(png_ptr, png_ptr->hist); - png_ptr->flags &= ~PNG_FLAG_FREE_HIST; -#endif -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (png_ptr->gamma_16_table != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_table[i]); - } - png_free(png_ptr, png_ptr->gamma_16_table); - } -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_from_1 != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_from_1[i]); - } - png_free(png_ptr, png_ptr->gamma_16_from_1); - } - if (png_ptr->gamma_16_to_1 != NULL) - { - int i; - int istop = (1 << (8 - png_ptr->gamma_shift)); - for (i = 0; i < istop; i++) - { - png_free(png_ptr, png_ptr->gamma_16_to_1[i]); - } - png_free(png_ptr, png_ptr->gamma_16_to_1); - } -#endif -#endif -#if defined(PNG_TIME_RFC1123_SUPPORTED) - png_free(png_ptr, png_ptr->time_buffer); -#endif - - inflateEnd(&png_ptr->zstream); -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED - png_free(png_ptr, png_ptr->save_buffer); -#endif - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -#ifdef PNG_TEXT_SUPPORTED - png_free(png_ptr, png_ptr->current_text); -#endif /* PNG_TEXT_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - - /* Save the important info out of the png_struct, in case it is - * being used again. - */ -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); -#endif - - error_fn = png_ptr->error_fn; - warning_fn = png_ptr->warning_fn; - error_ptr = png_ptr->error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; -#endif - - png_memset(png_ptr, 0, png_sizeof(png_struct)); - - png_ptr->error_fn = error_fn; - png_ptr->warning_fn = warning_fn; - png_ptr->error_ptr = error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr->free_fn = free_fn; -#endif - -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); -#endif - -} - -void PNGAPI -png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->read_row_fn = read_row_fn; -} - - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -#if defined(PNG_INFO_IMAGE_SUPPORTED) -void PNGAPI -png_read_png(png_structp png_ptr, png_infop info_ptr, - int transforms, - voidp params) -{ - int row; - - if (png_ptr == NULL) - return; -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) - /* Invert the alpha channel from opacity to transparency - */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif - - /* png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). - */ - png_read_info(png_ptr, info_ptr); - if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) - png_error(png_ptr, "Image is too high to process with png_read_png()"); - - /* -------------- image transformations start here ------------------- */ - -#if defined(PNG_READ_16_TO_8_SUPPORTED) - /* Tell libpng to strip 16 bit/color files down to 8 bits per color. - */ - if (transforms & PNG_TRANSFORM_STRIP_16) - png_set_strip_16(png_ptr); -#endif - -#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - /* Strip alpha bytes from the input data without combining with - * the background (not recommended). - */ - if (transforms & PNG_TRANSFORM_STRIP_ALPHA) - png_set_strip_alpha(png_ptr); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) - /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). - */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). - */ - if (transforms & PNG_TRANSFORM_PACKSWAP) - png_set_packswap(png_ptr); -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) - /* Expand paletted colors into true RGB triplets - * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel - * Expand paletted or RGB images with transparency to full alpha - * channels so the data will be available as RGBA quartets. - */ - if (transforms & PNG_TRANSFORM_EXPAND) - if ((png_ptr->bit_depth < 8) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || - (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) - png_set_expand(png_ptr); -#endif - - /* We don't handle background color or gamma transformation or dithering. - */ - -#if defined(PNG_READ_INVERT_SUPPORTED) - /* Invert monochrome files to have 0 as white and 1 as black - */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) - png_set_invert_mono(png_ptr); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) - /* If you want to shift the pixel values from the range [0,255] or - * [0,65535] to the original [0,7] or [0,31], or whatever range the - * colors were originally in: - */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) - { - png_color_8p sig_bit; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - png_set_shift(png_ptr, sig_bit); - } -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) - /* Flip the RGB pixels to BGR (or RGBA to BGRA) - */ - if (transforms & PNG_TRANSFORM_BGR) - png_set_bgr(png_ptr); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) - /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) - */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) - png_set_swap_alpha(png_ptr); -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) - /* Swap bytes of 16 bit files to least significant byte first - */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) - png_set_swap(png_ptr); -#endif - - /* We don't handle adding filler bytes */ - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (i.e., you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - /* -------------- image transformations end here ------------------- */ - -#ifdef PNG_FREE_ME_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); -#endif - if (info_ptr->row_pointers == NULL) - { - info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, - info_ptr->height * png_sizeof(png_bytep)); - png_memset(info_ptr->row_pointers, 0, info_ptr->height - * png_sizeof(png_bytep)); -#ifdef PNG_FREE_ME_SUPPORTED - info_ptr->free_me |= PNG_FREE_ROWS; -#endif - for (row = 0; row < (int)info_ptr->height; row++) - info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, - png_get_rowbytes(png_ptr, info_ptr)); - } - - png_read_image(png_ptr, info_ptr->row_pointers); - info_ptr->valid |= PNG_INFO_IDAT; - - /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); - - transforms = transforms; /* Quiet compiler warnings */ - params = params; - -} -#endif /* PNG_INFO_IMAGE_SUPPORTED */ -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ diff --git a/src/3rdparty/libpng/pngrio.c b/src/3rdparty/libpng/pngrio.c deleted file mode 100644 index 2267bca..0000000 --- a/src/3rdparty/libpng/pngrio.c +++ /dev/null @@ -1,177 +0,0 @@ - -/* pngrio.c - functions for data input - * - * Last changed in libpng 1.2.37 [June 4, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file provides a location for all input. Users who need - * special handling are expected to write a function that has the same - * arguments as this and performs a similar function, but that possibly - * has a different input method. Note that you shouldn't change this - * function, but rather write a replacement function and then make - * libpng use it at run time with png_set_read_fn(...). - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) - -/* Read the data from whatever input you are using. The default routine - * reads from a file pointer. Note that this routine sometimes gets called - * with very small lengths, so you should implement some kind of simple - * buffering if you are using unbuffered reads. This should never be asked - * to read more then 64K on a 16 bit machine. - */ -void /* PRIVATE */ -png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_debug1(4, "reading %d bytes", (int)length); - if (png_ptr->read_data_fn != NULL) - (*(png_ptr->read_data_fn))(png_ptr, data, length); - else - png_error(png_ptr, "Call to NULL read function"); -} - -#if !defined(PNG_NO_STDIO) -/* This is the function that does the actual reading of data. If you are - * not reading from a standard C stream, you should create a replacement - * read_data function and use it at run time with png_set_read_fn(), rather - * than changing the library. - */ -#ifndef USE_FAR_KEYWORD -void PNGAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - - if (png_ptr == NULL) - return; - /* fread() returns 0 on error, so it is OK to store this in a png_size_t - * instead of an int, which is what fread() actually returns. - */ -#if defined(_WIN32_WCE) - if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) - check = 0; -#else - check = (png_size_t)fread(data, (png_size_t)1, length, - (png_FILE_p)png_ptr->io_ptr); -#endif - - if (check != length) - png_error(png_ptr, "Read Error"); -} -#else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void PNGAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - int check; - png_byte *n_data; - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - /* Check if data really is near. If so, use usual code. */ - n_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)n_data == data) - { -#if defined(_WIN32_WCE) - if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) - check = 0; -#else - check = fread(n_data, 1, length, io_ptr); -#endif - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); -#if defined(_WIN32_WCE) - if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) ) - err = 0; -#else - err = fread(buf, (png_size_t)1, read, io_ptr); -#endif - png_memcpy(data, buf, read); /* copy far buffer to near buffer */ - if (err != read) - break; - else - check += err; - data += read; - remaining -= read; - } - while (remaining != 0); - } - if ((png_uint_32)check != (png_uint_32)length) - png_error(png_ptr, "read Error"); -} -#endif -#endif - -/* This function allows the application to supply a new input function - * for libpng if standard C streams aren't being used. - * - * This function takes as its arguments: - * png_ptr - pointer to a png input data structure - * io_ptr - pointer to user supplied structure containing info about - * the input functions. May be NULL. - * read_data_fn - pointer to a new input function that takes as its - * arguments a pointer to a png_struct, a pointer to - * a location where input data can be stored, and a 32-bit - * unsigned int that is the number of bytes to be read. - * To exit and output any fatal error messages the new write - * function should call png_error(png_ptr, "Error msg"). - * May be NULL, in which case libpng's default function will - * be used. - */ -void PNGAPI -png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, - png_rw_ptr read_data_fn) -{ - if (png_ptr == NULL) - return; - png_ptr->io_ptr = io_ptr; - -#if !defined(PNG_NO_STDIO) - if (read_data_fn != NULL) - png_ptr->read_data_fn = read_data_fn; - else - png_ptr->read_data_fn = png_default_read_data; -#else - png_ptr->read_data_fn = read_data_fn; -#endif - - /* It is an error to write to a read device */ - if (png_ptr->write_data_fn != NULL) - { - png_ptr->write_data_fn = NULL; - png_warning(png_ptr, - "It's an error to set both read_data_fn and write_data_fn in the "); - png_warning(png_ptr, - "same structure. Resetting write_data_fn to NULL."); - } - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_ptr->output_flush_fn = NULL; -#endif -} -#endif /* PNG_READ_SUPPORTED */ diff --git a/src/3rdparty/libpng/pngrtran.c b/src/3rdparty/libpng/pngrtran.c deleted file mode 100644 index d7e6b4a..0000000 --- a/src/3rdparty/libpng/pngrtran.c +++ /dev/null @@ -1,4381 +0,0 @@ - -/* pngrtran.c - transforms the data in a row for PNG readers - * - * Last changed in libpng 1.2.38 [July 16, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains functions optionally called by an application - * in order to tell libpng how to handle data when reading a PNG. - * Transformations that are used in both reading and writing are - * in pngtrans.c. - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) - -/* Set the action on getting a CRC error for an ancillary or critical chunk. */ -void PNGAPI -png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) -{ - png_debug(1, "in png_set_crc_action"); - /* Tell libpng how we react to CRC errors in critical chunks */ - if (png_ptr == NULL) - return; - switch (crit_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | - PNG_FLAG_CRC_CRITICAL_IGNORE; - break; - - case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ - png_warning(png_ptr, - "Can't discard critical data on CRC error."); - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; - break; - } - - switch (ancil_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | - PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; - break; - } -} - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - defined(PNG_FLOATING_POINT_SUPPORTED) -/* Handle alpha and tRNS via a background color */ -void PNGAPI -png_set_background(png_structp png_ptr, - png_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma) -{ - png_debug(1, "in png_set_background"); - if (png_ptr == NULL) - return; - if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) - { - png_warning(png_ptr, "Application must supply a known background gamma"); - return; - } - - png_ptr->transformations |= PNG_BACKGROUND; - png_memcpy(&(png_ptr->background), background_color, - png_sizeof(png_color_16)); - png_ptr->background_gamma = (float)background_gamma; - png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); -} -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) -/* Strip 16 bit depth files to 8 bit depth */ -void PNGAPI -png_set_strip_16(png_structp png_ptr) -{ - png_debug(1, "in png_set_strip_16"); - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_16_TO_8; -} -#endif - -#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -void PNGAPI -png_set_strip_alpha(png_structp png_ptr) -{ - png_debug(1, "in png_set_strip_alpha"); - if (png_ptr == NULL) - return; - png_ptr->flags |= PNG_FLAG_STRIP_ALPHA; -} -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) -/* Dither file to 8 bit. Supply a palette, the current number - * of elements in the palette, the maximum number of elements - * allowed, and a histogram if possible. If the current number - * of colors is greater then the maximum number, the palette will be - * modified to fit in the maximum number. "full_dither" indicates - * whether we need a dithering cube set up for RGB images, or if we - * simply are reducing the number of colors in a paletted image. - */ - -typedef struct png_dsort_struct -{ - struct png_dsort_struct FAR * next; - png_byte left; - png_byte right; -} png_dsort; -typedef png_dsort FAR * png_dsortp; -typedef png_dsort FAR * FAR * png_dsortpp; - -void PNGAPI -png_set_dither(png_structp png_ptr, png_colorp palette, - int num_palette, int maximum_colors, png_uint_16p histogram, - int full_dither) -{ - png_debug(1, "in png_set_dither"); - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_DITHER; - - if (!full_dither) - { - int i; - - png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - for (i = 0; i < num_palette; i++) - png_ptr->dither_index[i] = (png_byte)i; - } - - if (num_palette > maximum_colors) - { - if (histogram != NULL) - { - /* This is easy enough, just throw out the least used colors. - * Perhaps not the best solution, but good enough. - */ - - int i; - - /* Initialize an array to sort colors */ - png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - - /* Initialize the dither_sort array */ - for (i = 0; i < num_palette; i++) - png_ptr->dither_sort[i] = (png_byte)i; - - /* Find the least used palette entries by starting a - * bubble sort, and running it until we have sorted - * out enough colors. Note that we don't care about - * sorting all the colors, just finding which are - * least used. - */ - - for (i = num_palette - 1; i >= maximum_colors; i--) - { - int done; /* To stop early if the list is pre-sorted */ - int j; - - done = 1; - for (j = 0; j < i; j++) - { - if (histogram[png_ptr->dither_sort[j]] - < histogram[png_ptr->dither_sort[j + 1]]) - { - png_byte t; - - t = png_ptr->dither_sort[j]; - png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1]; - png_ptr->dither_sort[j + 1] = t; - done = 0; - } - } - if (done) - break; - } - - /* Swap the palette around, and set up a table, if necessary */ - if (full_dither) - { - int j = num_palette; - - /* Put all the useful colors within the max, but don't - * move the others. - */ - for (i = 0; i < maximum_colors; i++) - { - if ((int)png_ptr->dither_sort[i] >= maximum_colors) - { - do - j--; - while ((int)png_ptr->dither_sort[j] >= maximum_colors); - palette[i] = palette[j]; - } - } - } - else - { - int j = num_palette; - - /* Move all the used colors inside the max limit, and - * develop a translation table. - */ - for (i = 0; i < maximum_colors; i++) - { - /* Only move the colors we need to */ - if ((int)png_ptr->dither_sort[i] >= maximum_colors) - { - png_color tmp_color; - - do - j--; - while ((int)png_ptr->dither_sort[j] >= maximum_colors); - - tmp_color = palette[j]; - palette[j] = palette[i]; - palette[i] = tmp_color; - /* Indicate where the color went */ - png_ptr->dither_index[j] = (png_byte)i; - png_ptr->dither_index[i] = (png_byte)j; - } - } - - /* Find closest color for those colors we are not using */ - for (i = 0; i < num_palette; i++) - { - if ((int)png_ptr->dither_index[i] >= maximum_colors) - { - int min_d, k, min_k, d_index; - - /* Find the closest color to one we threw out */ - d_index = png_ptr->dither_index[i]; - min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); - for (k = 1, min_k = 0; k < maximum_colors; k++) - { - int d; - - d = PNG_COLOR_DIST(palette[d_index], palette[k]); - - if (d < min_d) - { - min_d = d; - min_k = k; - } - } - /* Point to closest color */ - png_ptr->dither_index[i] = (png_byte)min_k; - } - } - } - png_free(png_ptr, png_ptr->dither_sort); - png_ptr->dither_sort = NULL; - } - else - { - /* This is much harder to do simply (and quickly). Perhaps - * we need to go through a median cut routine, but those - * don't always behave themselves with only a few colors - * as input. So we will just find the closest two colors, - * and throw out one of them (chosen somewhat randomly). - * [We don't understand this at all, so if someone wants to - * work on improving it, be our guest - AED, GRP] - */ - int i; - int max_d; - int num_new_palette; - png_dsortp t; - png_dsortpp hash; - - t = NULL; - - /* Initialize palette index arrays */ - png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); - - /* Initialize the sort array */ - for (i = 0; i < num_palette; i++) - { - png_ptr->index_to_palette[i] = (png_byte)i; - png_ptr->palette_to_index[i] = (png_byte)i; - } - - hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 * - png_sizeof(png_dsortp))); - png_memset(hash, 0, 769 * png_sizeof(png_dsortp)); - - num_new_palette = num_palette; - - /* Initial wild guess at how far apart the farthest pixel - * pair we will be eliminating will be. Larger - * numbers mean more areas will be allocated, Smaller - * numbers run the risk of not saving enough data, and - * having to do this all over again. - * - * I have not done extensive checking on this number. - */ - max_d = 96; - - while (num_new_palette > maximum_colors) - { - for (i = 0; i < num_new_palette - 1; i++) - { - int j; - - for (j = i + 1; j < num_new_palette; j++) - { - int d; - - d = PNG_COLOR_DIST(palette[i], palette[j]); - - if (d <= max_d) - { - - t = (png_dsortp)png_malloc_warn(png_ptr, - (png_uint_32)(png_sizeof(png_dsort))); - if (t == NULL) - break; - t->next = hash[d]; - t->left = (png_byte)i; - t->right = (png_byte)j; - hash[d] = t; - } - } - if (t == NULL) - break; - } - - if (t != NULL) - for (i = 0; i <= max_d; i++) - { - if (hash[i] != NULL) - { - png_dsortp p; - - for (p = hash[i]; p; p = p->next) - { - if ((int)png_ptr->index_to_palette[p->left] - < num_new_palette && - (int)png_ptr->index_to_palette[p->right] - < num_new_palette) - { - int j, next_j; - - if (num_new_palette & 0x01) - { - j = p->left; - next_j = p->right; - } - else - { - j = p->right; - next_j = p->left; - } - - num_new_palette--; - palette[png_ptr->index_to_palette[j]] - = palette[num_new_palette]; - if (!full_dither) - { - int k; - - for (k = 0; k < num_palette; k++) - { - if (png_ptr->dither_index[k] == - png_ptr->index_to_palette[j]) - png_ptr->dither_index[k] = - png_ptr->index_to_palette[next_j]; - if ((int)png_ptr->dither_index[k] == - num_new_palette) - png_ptr->dither_index[k] = - png_ptr->index_to_palette[j]; - } - } - - png_ptr->index_to_palette[png_ptr->palette_to_index - [num_new_palette]] = png_ptr->index_to_palette[j]; - png_ptr->palette_to_index[png_ptr->index_to_palette[j]] - = png_ptr->palette_to_index[num_new_palette]; - - png_ptr->index_to_palette[j] = (png_byte)num_new_palette; - png_ptr->palette_to_index[num_new_palette] = (png_byte)j; - } - if (num_new_palette <= maximum_colors) - break; - } - if (num_new_palette <= maximum_colors) - break; - } - } - - for (i = 0; i < 769; i++) - { - if (hash[i] != NULL) - { - png_dsortp p = hash[i]; - while (p) - { - t = p->next; - png_free(png_ptr, p); - p = t; - } - } - hash[i] = 0; - } - max_d += 96; - } - png_free(png_ptr, hash); - png_free(png_ptr, png_ptr->palette_to_index); - png_free(png_ptr, png_ptr->index_to_palette); - png_ptr->palette_to_index = NULL; - png_ptr->index_to_palette = NULL; - } - num_palette = maximum_colors; - } - if (png_ptr->palette == NULL) - { - png_ptr->palette = palette; - } - png_ptr->num_palette = (png_uint_16)num_palette; - - if (full_dither) - { - int i; - png_bytep distance; - int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS + - PNG_DITHER_BLUE_BITS; - int num_red = (1 << PNG_DITHER_RED_BITS); - int num_green = (1 << PNG_DITHER_GREEN_BITS); - int num_blue = (1 << PNG_DITHER_BLUE_BITS); - png_size_t num_entries = ((png_size_t)1 << total_bits); - png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr, - (png_uint_32)(num_entries * png_sizeof(png_byte))); - png_memset(png_ptr->palette_lookup, 0, num_entries * - png_sizeof(png_byte)); - - distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * - png_sizeof(png_byte))); - - png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); - - for (i = 0; i < num_palette; i++) - { - int ir, ig, ib; - int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS)); - int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS)); - int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS)); - - for (ir = 0; ir < num_red; ir++) - { - /* int dr = abs(ir - r); */ - int dr = ((ir > r) ? ir - r : r - ir); - int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS)); - - for (ig = 0; ig < num_green; ig++) - { - /* int dg = abs(ig - g); */ - int dg = ((ig > g) ? ig - g : g - ig); - int dt = dr + dg; - int dm = ((dr > dg) ? dr : dg); - int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS); - - for (ib = 0; ib < num_blue; ib++) - { - int d_index = index_g | ib; - /* int db = abs(ib - b); */ - int db = ((ib > b) ? ib - b : b - ib); - int dmax = ((dm > db) ? dm : db); - int d = dmax + dt + db; - - if (d < (int)distance[d_index]) - { - distance[d_index] = (png_byte)d; - png_ptr->palette_lookup[d_index] = (png_byte)i; - } - } - } - } - } - - png_free(png_ptr, distance); - } -} -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) -/* Transform the image from the file_gamma to the screen_gamma. We - * only do transformations on images where the file_gamma and screen_gamma - * are not close reciprocals, otherwise it slows things down slightly, and - * also needlessly introduces small errors. - * - * We will turn off gamma transformation later if no semitransparent entries - * are present in the tRNS array for palette images. We can't do it here - * because we don't necessarily have the tRNS chunk yet. - */ -void PNGAPI -png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) -{ - png_debug(1, "in png_set_gamma"); - if (png_ptr == NULL) - return; - if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) - png_ptr->transformations |= PNG_GAMMA; - png_ptr->gamma = (float)file_gamma; - png_ptr->screen_gamma = (float)scrn_gamma; -} -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) -/* Expand paletted images to RGB, expand grayscale images of - * less than 8-bit depth to 8-bit depth, and expand tRNS chunks - * to alpha channels. - */ -void PNGAPI -png_set_expand(png_structp png_ptr) -{ - png_debug(1, "in png_set_expand"); - if (png_ptr == NULL) - return; - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} - -/* GRR 19990627: the following three functions currently are identical - * to png_set_expand(). However, it is entirely reasonable that someone - * might wish to expand an indexed image to RGB but *not* expand a single, - * fully transparent palette entry to a full alpha channel--perhaps instead - * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace - * the transparent color with a particular RGB value, or drop tRNS entirely. - * IOW, a future version of the library may make the transformations flag - * a bit more fine-grained, with separate bits for each of these three - * functions. - * - * More to the point, these functions make it obvious what libpng will be - * doing, whereas "expand" can (and does) mean any number of things. - * - * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified - * to expand only the sample depth but not to expand the tRNS to alpha. - */ - -/* Expand paletted images to RGB. */ -void PNGAPI -png_set_palette_to_rgb(png_structp png_ptr) -{ - png_debug(1, "in png_set_palette_to_rgb"); - if (png_ptr == NULL) - return; - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} - -#if !defined(PNG_1_0_X) -/* Expand grayscale images of less than 8-bit depth to 8 bits. */ -void PNGAPI -png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) -{ - png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); - if (png_ptr == NULL) - return; - png_ptr->transformations |= PNG_EXPAND; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} -#endif - -#if defined(PNG_1_0_X) || defined(PNG_1_2_X) -/* Expand grayscale images of less than 8-bit depth to 8 bits. */ -/* Deprecated as of libpng-1.2.9 */ -void PNGAPI -png_set_gray_1_2_4_to_8(png_structp png_ptr) -{ - png_debug(1, "in png_set_gray_1_2_4_to_8"); - if (png_ptr == NULL) - return; - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); -} -#endif - - -/* Expand tRNS chunks to alpha channels. */ -void PNGAPI -png_set_tRNS_to_alpha(png_structp png_ptr) -{ - png_debug(1, "in png_set_tRNS_to_alpha"); - png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} -#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) -void PNGAPI -png_set_gray_to_rgb(png_structp png_ptr) -{ - png_debug(1, "in png_set_gray_to_rgb"); - png_ptr->transformations |= PNG_GRAY_TO_RGB; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; -} -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -#if defined(PNG_FLOATING_POINT_SUPPORTED) -/* Convert a RGB image to a grayscale of the same width. This allows us, - * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. - */ - -void PNGAPI -png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, - double green) -{ - int red_fixed = (int)((float)red*100000.0 + 0.5); - int green_fixed = (int)((float)green*100000.0 + 0.5); - if (png_ptr == NULL) - return; - png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); -} -#endif - -void PNGAPI -png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, - png_fixed_point red, png_fixed_point green) -{ - png_debug(1, "in png_set_rgb_to_gray"); - if (png_ptr == NULL) - return; - switch(error_action) - { - case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY; - break; - - case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; - break; - - case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; - } - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#if defined(PNG_READ_EXPAND_SUPPORTED) - png_ptr->transformations |= PNG_EXPAND; -#else - { - png_warning(png_ptr, - "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED."); - png_ptr->transformations &= ~PNG_RGB_TO_GRAY; - } -#endif - { - png_uint_16 red_int, green_int; - if (red < 0 || green < 0) - { - red_int = 6968; /* .212671 * 32768 + .5 */ - green_int = 23434; /* .715160 * 32768 + .5 */ - } - else if (red + green < 100000L) - { - red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); - green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); - } - else - { - png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); - red_int = 6968; - green_int = 23434; - } - png_ptr->rgb_to_gray_red_coeff = red_int; - png_ptr->rgb_to_gray_green_coeff = green_int; - png_ptr->rgb_to_gray_blue_coeff = - (png_uint_16)(32768 - red_int - green_int); - } -} -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ - defined(PNG_LEGACY_SUPPORTED) || \ - defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -void PNGAPI -png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr - read_user_transform_fn) -{ - png_debug(1, "in png_set_read_user_transform_fn"); - if (png_ptr == NULL) - return; -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - png_ptr->transformations |= PNG_USER_TRANSFORM; - png_ptr->read_user_transform_fn = read_user_transform_fn; -#endif -#ifdef PNG_LEGACY_SUPPORTED - if (read_user_transform_fn) - png_warning(png_ptr, - "This version of libpng does not support user transforms"); -#endif -} -#endif - -/* Initialize everything needed for the read. This includes modifying - * the palette. - */ -void /* PRIVATE */ -png_init_read_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_init_read_transformations"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (png_ptr != NULL) -#endif - { -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \ - || defined(PNG_READ_GAMMA_SUPPORTED) - int color_type = png_ptr->color_type; -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) - /* Detect gray background and attempt to enable optimization - * for gray --> RGB case - * - * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or - * RGB_ALPHA (in which case need_expand is superfluous anyway), the - * background color might actually be gray yet not be flagged as such. - * This is not a problem for the current code, which uses - * PNG_BACKGROUND_IS_GRAY only to decide when to do the - * png_do_gray_to_rgb() transformation. - */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - !(color_type & PNG_COLOR_MASK_COLOR)) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - } else if ((png_ptr->transformations & PNG_BACKGROUND) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_GRAY_TO_RGB) && - png_ptr->background.red == png_ptr->background.green && - png_ptr->background.red == png_ptr->background.blue) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - png_ptr->background.gray = png_ptr->background.red; - } -#endif - - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND)) - { - if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ - { - /* Expand background and tRNS chunks */ - switch (png_ptr->bit_depth) - { - case 1: - png_ptr->background.gray *= (png_uint_16)0xff; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_values.gray *= (png_uint_16)0xff; - png_ptr->trans_values.red = png_ptr->trans_values.green - = png_ptr->trans_values.blue = png_ptr->trans_values.gray; - } - break; - - case 2: - png_ptr->background.gray *= (png_uint_16)0x55; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_values.gray *= (png_uint_16)0x55; - png_ptr->trans_values.red = png_ptr->trans_values.green - = png_ptr->trans_values.blue = png_ptr->trans_values.gray; - } - break; - - case 4: - png_ptr->background.gray *= (png_uint_16)0x11; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) - { - png_ptr->trans_values.gray *= (png_uint_16)0x11; - png_ptr->trans_values.red = png_ptr->trans_values.green - = png_ptr->trans_values.blue = png_ptr->trans_values.gray; - } - break; - - case 8: - - case 16: - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - break; - } - } - else if (color_type == PNG_COLOR_TYPE_PALETTE) - { - png_ptr->background.red = - png_ptr->palette[png_ptr->background.index].red; - png_ptr->background.green = - png_ptr->palette[png_ptr->background.index].green; - png_ptr->background.blue = - png_ptr->palette[png_ptr->background.index].blue; - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_ALPHA) - { -#if defined(PNG_READ_EXPAND_SUPPORTED) - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) -#endif - { - /* Invert the alpha channel (in tRNS) unless the pixels are - * going to be expanded, in which case leave it for later - */ - int i, istop; - istop=(int)png_ptr->num_trans; - for (i=0; itrans[i] = (png_byte)(255 - png_ptr->trans[i]); - } - } -#endif - - } - } -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - png_ptr->background_1 = png_ptr->background; -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) - - if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) - && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0) - < PNG_GAMMA_THRESHOLD)) - { - int i, k; - k=0; - for (i=0; inum_trans; i++) - { - if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff) - k=1; /* Partial transparency is present */ - } - if (k == 0) - png_ptr->transformations &= ~PNG_GAMMA; - } - - if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) && - png_ptr->gamma != 0.0) - { - png_build_gamma_table(png_ptr); -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->transformations & PNG_BACKGROUND) - { - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - /* Could skip if no transparency */ - png_color back, back_1; - png_colorp palette = png_ptr->palette; - int num_palette = png_ptr->num_palette; - int i; - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) - { - back.red = png_ptr->gamma_table[png_ptr->background.red]; - back.green = png_ptr->gamma_table[png_ptr->background.green]; - back.blue = png_ptr->gamma_table[png_ptr->background.blue]; - - back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; - back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; - back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; - } - else - { - double g, gs; - - switch (png_ptr->background_gamma_type) - { - case PNG_BACKGROUND_GAMMA_SCREEN: - g = (png_ptr->screen_gamma); - gs = 1.0; - break; - - case PNG_BACKGROUND_GAMMA_FILE: - g = 1.0 / (png_ptr->gamma); - gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - break; - - case PNG_BACKGROUND_GAMMA_UNIQUE: - g = 1.0 / (png_ptr->background_gamma); - gs = 1.0 / (png_ptr->background_gamma * - png_ptr->screen_gamma); - break; - default: - g = 1.0; /* back_1 */ - gs = 1.0; /* back */ - } - - if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) - { - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - } - else - { - back.red = (png_byte)(pow( - (double)png_ptr->background.red/255, gs) * 255.0 + .5); - back.green = (png_byte)(pow( - (double)png_ptr->background.green/255, gs) * 255.0 + .5); - back.blue = (png_byte)(pow( - (double)png_ptr->background.blue/255, gs) * 255.0 + .5); - } - - back_1.red = (png_byte)(pow( - (double)png_ptr->background.red/255, g) * 255.0 + .5); - back_1.green = (png_byte)(pow( - (double)png_ptr->background.green/255, g) * 255.0 + .5); - back_1.blue = (png_byte)(pow( - (double)png_ptr->background.blue/255, g) * 255.0 + .5); - } - for (i = 0; i < num_palette; i++) - { - if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff) - { - if (png_ptr->trans[i] == 0) - { - palette[i] = back; - } - else /* if (png_ptr->trans[i] != 0xff) */ - { - png_byte v, w; - - v = png_ptr->gamma_to_1[palette[i].red]; - png_composite(w, v, png_ptr->trans[i], back_1.red); - palette[i].red = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].green]; - png_composite(w, v, png_ptr->trans[i], back_1.green); - palette[i].green = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].blue]; - png_composite(w, v, png_ptr->trans[i], back_1.blue); - palette[i].blue = png_ptr->gamma_from_1[w]; - } - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - /* Prevent the transformations being done again, and make sure - * that the now spurious alpha channel is stripped - the code - * has just reduced background composition and gamma correction - * to a simple alpha channel strip. - */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations &= ~PNG_GAMMA; - png_ptr->transformations |= PNG_STRIP_ALPHA; - } - /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ - else - /* color_type != PNG_COLOR_TYPE_PALETTE */ - { - double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1); - double g = 1.0; - double gs = 1.0; - - switch (png_ptr->background_gamma_type) - { - case PNG_BACKGROUND_GAMMA_SCREEN: - g = (png_ptr->screen_gamma); - gs = 1.0; - break; - - case PNG_BACKGROUND_GAMMA_FILE: - g = 1.0 / (png_ptr->gamma); - gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - break; - - case PNG_BACKGROUND_GAMMA_UNIQUE: - g = 1.0 / (png_ptr->background_gamma); - gs = 1.0 / (png_ptr->background_gamma * - png_ptr->screen_gamma); - break; - } - - png_ptr->background_1.gray = (png_uint_16)(pow( - (double)png_ptr->background.gray / m, g) * m + .5); - png_ptr->background.gray = (png_uint_16)(pow( - (double)png_ptr->background.gray / m, gs) * m + .5); - - if ((png_ptr->background.red != png_ptr->background.green) || - (png_ptr->background.red != png_ptr->background.blue) || - (png_ptr->background.red != png_ptr->background.gray)) - { - /* RGB or RGBA with color background */ - png_ptr->background_1.red = (png_uint_16)(pow( - (double)png_ptr->background.red / m, g) * m + .5); - png_ptr->background_1.green = (png_uint_16)(pow( - (double)png_ptr->background.green / m, g) * m + .5); - png_ptr->background_1.blue = (png_uint_16)(pow( - (double)png_ptr->background.blue / m, g) * m + .5); - png_ptr->background.red = (png_uint_16)(pow( - (double)png_ptr->background.red / m, gs) * m + .5); - png_ptr->background.green = (png_uint_16)(pow( - (double)png_ptr->background.green / m, gs) * m + .5); - png_ptr->background.blue = (png_uint_16)(pow( - (double)png_ptr->background.blue / m, gs) * m + .5); - } - else - { - /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ - png_ptr->background_1.red = png_ptr->background_1.green - = png_ptr->background_1.blue = png_ptr->background_1.gray; - png_ptr->background.red = png_ptr->background.green - = png_ptr->background.blue = png_ptr->background.gray; - } - } - } - else - /* Transformation does not include PNG_BACKGROUND */ -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - png_colorp palette = png_ptr->palette; - int num_palette = png_ptr->num_palette; - int i; - - for (i = 0; i < num_palette; i++) - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - - /* Done the gamma correction. */ - png_ptr->transformations &= ~PNG_GAMMA; - } - } -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - else -#endif -#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - /* No GAMMA transformation */ - if ((png_ptr->transformations & PNG_BACKGROUND) && - (color_type == PNG_COLOR_TYPE_PALETTE)) - { - int i; - int istop = (int)png_ptr->num_trans; - png_color back; - png_colorp palette = png_ptr->palette; - - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - - for (i = 0; i < istop; i++) - { - if (png_ptr->trans[i] == 0) - { - palette[i] = back; - } - else if (png_ptr->trans[i] != 0xff) - { - /* The png_composite() macro is defined in png.h */ - png_composite(palette[i].red, palette[i].red, - png_ptr->trans[i], back.red); - png_composite(palette[i].green, palette[i].green, - png_ptr->trans[i], back.green); - png_composite(palette[i].blue, palette[i].blue, - png_ptr->trans[i], back.blue); - } - } - - /* Handled alpha, still need to strip the channel. */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations |= PNG_STRIP_ALPHA; - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - -#if defined(PNG_READ_SHIFT_SUPPORTED) - if ((png_ptr->transformations & PNG_SHIFT) && - (color_type == PNG_COLOR_TYPE_PALETTE)) - { - png_uint_16 i; - png_uint_16 istop = png_ptr->num_palette; - int sr = 8 - png_ptr->sig_bit.red; - int sg = 8 - png_ptr->sig_bit.green; - int sb = 8 - png_ptr->sig_bit.blue; - - if (sr < 0 || sr > 8) - sr = 0; - if (sg < 0 || sg > 8) - sg = 0; - if (sb < 0 || sb > 8) - sb = 0; - for (i = 0; i < istop; i++) - { - png_ptr->palette[i].red >>= sr; - png_ptr->palette[i].green >>= sg; - png_ptr->palette[i].blue >>= sb; - } - } -#endif /* PNG_READ_SHIFT_SUPPORTED */ - } -#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ - && !defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr) - return; -#endif -} - -/* Modify the info structure to reflect the transformations. The - * info should be updated so a PNG file could be written with it, - * assuming the transformations result in valid PNG data. - */ -void /* PRIVATE */ -png_read_transform_info(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_read_transform_info"); -#if defined(PNG_READ_EXPAND_SUPPORTED) - if (png_ptr->transformations & PNG_EXPAND) - { - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - else - info_ptr->color_type = PNG_COLOR_TYPE_RGB; - info_ptr->bit_depth = 8; - info_ptr->num_trans = 0; - } - else - { - if (png_ptr->num_trans) - { - if (png_ptr->transformations & PNG_EXPAND_tRNS) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; - } - if (info_ptr->bit_depth < 8) - info_ptr->bit_depth = 8; - info_ptr->num_trans = 0; - } - } -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->transformations & PNG_BACKGROUND) - { - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; - info_ptr->num_trans = 0; - info_ptr->background = png_ptr->background; - } -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (png_ptr->transformations & PNG_GAMMA) - { -#ifdef PNG_FLOATING_POINT_SUPPORTED - info_ptr->gamma = png_ptr->gamma; -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - info_ptr->int_gamma = png_ptr->int_gamma; -#endif - } -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) - if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) - info_ptr->bit_depth = 8; -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - info_ptr->color_type |= PNG_COLOR_MASK_COLOR; -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) - if (png_ptr->transformations & PNG_DITHER) - { - if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && - png_ptr->palette_lookup && info_ptr->bit_depth == 8) - { - info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; - } - } -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) - if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) - info_ptr->bit_depth = 8; -#endif - - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) - info_ptr->channels = 3; - else - info_ptr->channels = 1; - -#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; -#endif - - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) - info_ptr->channels++; - -#if defined(PNG_READ_FILLER_SUPPORTED) - /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ - if ((png_ptr->transformations & PNG_FILLER) && - ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) - { - info_ptr->channels++; - /* If adding a true alpha channel not just filler */ -#if !defined(PNG_1_0_X) - if (png_ptr->transformations & PNG_ADD_ALPHA) - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; -#endif - } -#endif - -#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ -defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (info_ptr->bit_depth < png_ptr->user_transform_depth) - info_ptr->bit_depth = png_ptr->user_transform_depth; - if (info_ptr->channels < png_ptr->user_transform_channels) - info_ptr->channels = png_ptr->user_transform_channels; - } -#endif - - info_ptr->pixel_depth = (png_byte)(info_ptr->channels * - info_ptr->bit_depth); - - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); - -#if !defined(PNG_READ_EXPAND_SUPPORTED) - if (png_ptr) - return; -#endif -} - -/* Transform the row. The order of transformations is significant, - * and is very touchy. If you add a transformation, take care to - * decide how it fits in with the other transformations here. - */ -void /* PRIVATE */ -png_do_read_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_do_read_transformations"); - if (png_ptr->row_buf == NULL) - { -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - char msg[50]; - - png_snprintf2(msg, 50, - "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number, - png_ptr->pass); - png_error(png_ptr, msg); -#else - png_error(png_ptr, "NULL row buffer"); -#endif - } -#ifdef PNG_WARN_UNINITIALIZED_ROW - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - /* Application has failed to call either png_read_start_image() - * or png_read_update_info() after setting transforms that expand - * pixels. This check added to libpng-1.2.19 - */ -#if (PNG_WARN_UNINITIALIZED_ROW==1) - png_error(png_ptr, "Uninitialized row"); -#else - png_warning(png_ptr, "Uninitialized row"); -#endif -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) - { - png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette, png_ptr->trans, png_ptr->num_trans); - } - else - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_values)); - else - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - NULL); - } - } -#endif - -#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) - if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA) - png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)); -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - { - int rgb_error = - png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1); - if (rgb_error) - { - png_ptr->rgb_to_gray_status=1; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_WARN) - png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_ERR) - png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - } - } -#endif - -/* From Andreas Dilger e-mail to png-implement, 26 March 1998: - * - * In most cases, the "simple transparency" should be done prior to doing - * gray-to-RGB, or you will have to test 3x as many bytes to check if a - * pixel is transparent. You would also need to make sure that the - * transparency information is upgraded to RGB. - * - * To summarize, the current flow is: - * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite - * with background "in place" if transparent, - * convert to RGB if necessary - * - Gray + alpha -> composite with gray background and remove alpha bytes, - * convert to RGB if necessary - * - * To support RGB backgrounds for gray images we need: - * - Gray + simple transparency -> convert to RGB + simple transparency, - * compare 3 or 6 bytes and composite with - * background "in place" if transparent - * (3x compare/pixel compared to doing - * composite with gray bkgrnd) - * - Gray + alpha -> convert to RGB + alpha, composite with background and - * remove alpha bytes (3x float - * operations/pixel compared with composite - * on gray background) - * - * Greg's change will do this. The reason it wasn't done before is for - * performance, as this increases the per-pixel operations. If we would check - * in advance if the background was gray or RGB, and position the gray-to-RGB - * transform appropriately, then it would save a lot of work/time. - */ - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) - /* If gray -> RGB, do so now only if background is non-gray; else do later - * for performance reasons - */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - if ((png_ptr->transformations & PNG_BACKGROUND) && - ((png_ptr->num_trans != 0 ) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) - png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_values), &(png_ptr->background) -#if defined(PNG_READ_GAMMA_SUPPORTED) - , &(png_ptr->background_1), - png_ptr->gamma_table, png_ptr->gamma_from_1, - png_ptr->gamma_to_1, png_ptr->gamma_16_table, - png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, - png_ptr->gamma_shift -#endif -); -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) - if ((png_ptr->transformations & PNG_GAMMA) && -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - !((png_ptr->transformations & PNG_BACKGROUND) && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && -#endif - (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->gamma_table, png_ptr->gamma_16_table, - png_ptr->gamma_shift); -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) - if (png_ptr->transformations & PNG_16_TO_8) - png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) - if (png_ptr->transformations & PNG_DITHER) - { - png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->dither_index); - if (png_ptr->row_info.rowbytes == (png_uint_32)0) - png_error(png_ptr, "png_do_dither returned rowbytes=0"); - } -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) - png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) - png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) - /* If gray -> RGB, do so now only if we did not do so above */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) - png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - (png_uint_32)png_ptr->filler, png_ptr->flags); -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (png_ptr->read_user_transform_fn != NULL) - (*(png_ptr->read_user_transform_fn)) /* User read transform function */ - (png_ptr, /* png_ptr */ - &(png_ptr->row_info), /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_uint_32 rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if (png_ptr->user_transform_depth) - png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; - if (png_ptr->user_transform_channels) - png_ptr->row_info.channels = png_ptr->user_transform_channels; -#endif - png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * - png_ptr->row_info.channels); - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - } -#endif - -} - -#if defined(PNG_READ_PACK_SUPPORTED) -/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, - * without changing the actual values. Thus, if you had a row with - * a bit depth of 1, you would end up with bytes that only contained - * the numbers 0 or 1. If you would rather they contain 0 and 255, use - * png_do_shift() after this. - */ -void /* PRIVATE */ -png_do_unpack(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_unpack"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (row != NULL && row_info != NULL && row_info->bit_depth < 8) -#else - if (row_info->bit_depth < 8) -#endif - { - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - switch (row_info->bit_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x01); - if (shift == 7) - { - shift = 0; - sp--; - } - else - shift++; - - dp--; - } - break; - } - - case 2: - { - - png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x03); - if (shift == 6) - { - shift = 0; - sp--; - } - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x0f); - if (shift == 4) - { - shift = 0; - sp--; - } - else - shift = 4; - - dp--; - } - break; - } - } - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_width * row_info->channels; - } -} -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) -/* Reverse the effects of png_do_shift. This routine merely shifts the - * pixels back to their significant bits values. Thus, if you have - * a row of bit depth 8, but only 5 are significant, this will shift - * the values back to 0 through 31. - */ -void /* PRIVATE */ -png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits) -{ - png_debug(1, "in png_do_unshift"); - if ( -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && sig_bits != NULL && -#endif - row_info->color_type != PNG_COLOR_TYPE_PALETTE) - { - int shift[4]; - int channels = 0; - int c; - png_uint_16 value = 0; - png_uint_32 row_width = row_info->width; - - if (row_info->color_type & PNG_COLOR_MASK_COLOR) - { - shift[channels++] = row_info->bit_depth - sig_bits->red; - shift[channels++] = row_info->bit_depth - sig_bits->green; - shift[channels++] = row_info->bit_depth - sig_bits->blue; - } - else - { - shift[channels++] = row_info->bit_depth - sig_bits->gray; - } - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - shift[channels++] = row_info->bit_depth - sig_bits->alpha; - } - - for (c = 0; c < channels; c++) - { - if (shift[c] <= 0) - shift[c] = 0; - else - value = 1; - } - - if (!value) - return; - - switch (row_info->bit_depth) - { - case 2: - { - png_bytep bp; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - - for (bp = row, i = 0; i < istop; i++) - { - *bp >>= 1; - *bp++ &= 0x55; - } - break; - } - - case 4: - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | - (png_byte)((int)0xf >> shift[0])); - - for (i = 0; i < istop; i++) - { - *bp >>= shift[0]; - *bp++ &= mask; - } - break; - } - - case 8: - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = row_width * channels; - - for (i = 0; i < istop; i++) - { - *bp++ >>= shift[i%channels]; - } - break; - } - - case 16: - { - png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = channels * row_width; - - for (i = 0; i < istop; i++) - { - value = (png_uint_16)((*bp << 8) + *(bp + 1)); - value >>= shift[i%channels]; - *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); - } - break; - } - } - } -} -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) -/* Chop rows of bit depth 16 down to 8 */ -void /* PRIVATE */ -png_do_chop(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_chop"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (row != NULL && row_info != NULL && row_info->bit_depth == 16) -#else - if (row_info->bit_depth == 16) -#endif - { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - png_uint_32 istop = row_info->width * row_info->channels; - - for (i = 0; i> 8)) >> 8; - * - * Approximate calculation with shift/add instead of multiply/divide: - * *dp = ((((png_uint_32)(*sp) << 8) | - * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; - * - * What we actually do to avoid extra shifting and conversion: - */ - - *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); -#else - /* Simply discard the low order byte */ - *dp = *sp; -#endif - } - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_info->width * row_info->channels; - } -} -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) -void /* PRIVATE */ -png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_swap_alpha"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (row != NULL && row_info != NULL) -#endif - { - png_uint_32 row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This converts from RGBA to ARGB */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } - } - /* This converts from RRGGBBAA to AARRGGBB */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This converts from GA to AG */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } - } - /* This converts from GGAA to AAGG */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; - } - } - } - } -} -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) -void /* PRIVATE */ -png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_invert_alpha"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (row != NULL && row_info != NULL) -#endif - { - png_uint_32 row_width = row_info->width; - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - /* This inverts the alpha channel in RGBA */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - -/* This does nothing: - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - We can replace it with: -*/ - sp-=3; - dp=sp; - } - } - /* This inverts the alpha channel in RRGGBBAA */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = (png_byte)(255 - *(--sp)); - -/* This does nothing: - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - We can replace it with: -*/ - sp-=6; - dp=sp; - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This inverts the alpha channel in GA */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = *(--sp); - } - } - /* This inverts the alpha channel in GGAA */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - *(--dp) = (png_byte)(255 - *(--sp)); - *(--dp) = (png_byte)(255 - *(--sp)); -/* - *(--dp) = *(--sp); - *(--dp) = *(--sp); -*/ - sp-=2; - dp=sp; - } - } - } - } -} -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) -/* Add filler channel if we have RGB color */ -void /* PRIVATE */ -png_do_read_filler(png_row_infop row_info, png_bytep row, - png_uint_32 filler, png_uint_32 flags) -{ - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - png_byte hi_filler = (png_byte)((filler>>8) & 0xff); - png_byte lo_filler = (png_byte)(filler & 0xff); - - png_debug(1, "in png_do_read_filler"); - if ( -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - if (row_info->bit_depth == 8) - { - /* This changes the data from G to GX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 1; i < row_width; i++) - { - *(--dp) = lo_filler; - *(--dp) = *(--sp); - } - *(--dp) = lo_filler; - row_info->channels = 2; - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - /* This changes the data from G to XG */ - else - { - png_bytep sp = row + (png_size_t)row_width; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = lo_filler; - } - row_info->channels = 2; - row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; - } - } - else if (row_info->bit_depth == 16) - { - /* This changes the data from GG to GGXX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width * 2; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 1; i < row_width; i++) - { - *(--dp) = hi_filler; - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = hi_filler; - *(--dp) = lo_filler; - row_info->channels = 2; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - /* This changes the data from GG to XXGG */ - else - { - png_bytep sp = row + (png_size_t)row_width * 2; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = hi_filler; - *(--dp) = lo_filler; - } - row_info->channels = 2; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - } - } /* COLOR_TYPE == GRAY */ - else if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - if (row_info->bit_depth == 8) - { - /* This changes the data from RGB to RGBX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 1; i < row_width; i++) - { - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = lo_filler; - row_info->channels = 4; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - /* This changes the data from RGB to XRGB */ - else - { - png_bytep sp = row + (png_size_t)row_width * 3; - png_bytep dp = sp + (png_size_t)row_width; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = lo_filler; - } - row_info->channels = 4; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - } - } - else if (row_info->bit_depth == 16) - { - /* This changes the data from RRGGBB to RRGGBBXX */ - if (flags & PNG_FLAG_FILLER_AFTER) - { - png_bytep sp = row + (png_size_t)row_width * 6; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 1; i < row_width; i++) - { - *(--dp) = hi_filler; - *(--dp) = lo_filler; - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - } - *(--dp) = hi_filler; - *(--dp) = lo_filler; - row_info->channels = 4; - row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; - } - /* This changes the data from RRGGBB to XXRRGGBB */ - else - { - png_bytep sp = row + (png_size_t)row_width * 6; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = hi_filler; - *(--dp) = lo_filler; - } - row_info->channels = 4; - row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; - } - } - } /* COLOR_TYPE == RGB */ -} -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) -/* Expand grayscale files to RGB, with or without alpha */ -void /* PRIVATE */ -png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) -{ - png_uint_32 i; - png_uint_32 row_width = row_info->width; - - png_debug(1, "in png_do_gray_to_rgb"); - if (row_info->bit_depth >= 8 && -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - !(row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - if (row_info->bit_depth == 8) - { - png_bytep sp = row + (png_size_t)row_width - 1; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(dp--) = *sp; - *(dp--) = *sp; - *(dp--) = *(sp--); - } - } - else - { - png_bytep sp = row + (png_size_t)row_width * 2 - 1; - png_bytep dp = sp + (png_size_t)row_width * 4; - for (i = 0; i < row_width; i++) - { - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *(sp--); - *(dp--) = *(sp--); - } - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (row_info->bit_depth == 8) - { - png_bytep sp = row + (png_size_t)row_width * 2 - 1; - png_bytep dp = sp + (png_size_t)row_width * 2; - for (i = 0; i < row_width; i++) - { - *(dp--) = *(sp--); - *(dp--) = *sp; - *(dp--) = *sp; - *(dp--) = *(sp--); - } - } - else - { - png_bytep sp = row + (png_size_t)row_width * 4 - 1; - png_bytep dp = sp + (png_size_t)row_width * 4; - for (i = 0; i < row_width; i++) - { - *(dp--) = *(sp--); - *(dp--) = *(sp--); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *sp; - *(dp--) = *(sp - 1); - *(dp--) = *(sp--); - *(dp--) = *(sp--); - } - } - } - row_info->channels += (png_byte)2; - row_info->color_type |= PNG_COLOR_MASK_COLOR; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } -} -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -/* Reduce RGB files to grayscale, with or without alpha - * using the equation given in Poynton's ColorFAQ at - * (THIS LINK IS DEAD June 2008) - * New link: - * - * Charles Poynton poynton at poynton.com - * - * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B - * - * We approximate this with - * - * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - * - * which can be expressed with integers as - * - * Y = (6969 * R + 23434 * G + 2365 * B)/32768 - * - * The calculation is to be done in a linear colorspace. - * - * Other integer coefficents can be used via png_set_rgb_to_gray(). - */ -int /* PRIVATE */ -png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) - -{ - png_uint_32 i; - - png_uint_32 row_width = row_info->width; - int rgb_error = 0; - - png_debug(1, "in png_do_rgb_to_gray"); - if ( -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; - png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; - png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - - for (i = 0; i < row_width; i++) - { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - if (red != green || red != blue) - { - rgb_error |= 1; - *(dp++) = png_ptr->gamma_from_1[ - (rc*red + gc*green + bc*blue)>>15]; - } - else - *(dp++) = *(sp - 1); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - if (red != green || red != blue) - { - rgb_error |= 1; - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - } - else - *(dp++) = *(sp - 1); - } - } - } - - else /* RGB bit_depth == 16 */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - - if (red == green && red == blue) - w = red; - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> - png_ptr->gamma_shift][red>>8]; - png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> - png_ptr->gamma_shift][blue>>8]; - png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 - + bc*blue_1)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - - red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - - if (red != green || red != blue) - rgb_error |= 1; - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - } - } - } - } - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - if (red != green || red != blue) - rgb_error |= 1; - *(dp++) = png_ptr->gamma_from_1 - [(rc*red + gc*green + bc*blue)>>15]; - *(dp++) = *(sp++); /* alpha */ - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - if (red != green || red != blue) - rgb_error |= 1; - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = *(sp++); /* alpha */ - } - } - } - else /* RGBA bit_depth == 16 */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; - - if (red == green && red == blue) - w = red; - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> - png_ptr->gamma_shift][red>>8]; - png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> - png_ptr->gamma_shift][blue>>8]; - png_uint_16 gray16 = (png_uint_16)((rc * red_1 - + gc * green_1 + bc * blue_1)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - *(dp++) = *(sp++); /* alpha */ - *(dp++) = *(sp++); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; - green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; - blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; - if (red != green || red != blue) - rgb_error |= 1; - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - *(dp++) = *(sp++); /* alpha */ - *(dp++) = *(sp++); - } - } - } - } - row_info->channels -= (png_byte)2; - row_info->color_type &= ~PNG_COLOR_MASK_COLOR; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - return rgb_error; -} -#endif - -/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth - * large of png_color. This lets grayscale images be treated as - * paletted. Most useful for gamma correction and simplification - * of code. - */ -void PNGAPI -png_build_grayscale_palette(int bit_depth, png_colorp palette) -{ - int num_palette; - int color_inc; - int i; - int v; - - png_debug(1, "in png_do_build_grayscale_palette"); - if (palette == NULL) - return; - - switch (bit_depth) - { - case 1: - num_palette = 2; - color_inc = 0xff; - break; - - case 2: - num_palette = 4; - color_inc = 0x55; - break; - - case 4: - num_palette = 16; - color_inc = 0x11; - break; - - case 8: - num_palette = 256; - color_inc = 1; - break; - - default: - num_palette = 0; - color_inc = 0; - break; - } - - for (i = 0, v = 0; i < num_palette; i++, v += color_inc) - { - palette[i].red = (png_byte)v; - palette[i].green = (png_byte)v; - palette[i].blue = (png_byte)v; - } -} - -/* This function is currently unused. Do we really need it? */ -#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED) -void /* PRIVATE */ -png_correct_palette(png_structp png_ptr, png_colorp palette, - int num_palette) -{ - png_debug(1, "in png_correct_palette"); -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) - if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND)) - { - png_color back, back_1; - - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) - { - back.red = png_ptr->gamma_table[png_ptr->background.red]; - back.green = png_ptr->gamma_table[png_ptr->background.green]; - back.blue = png_ptr->gamma_table[png_ptr->background.blue]; - - back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; - back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; - back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; - } - else - { - double g; - - g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma); - - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN || - fabs(g - 1.0) < PNG_GAMMA_THRESHOLD) - { - back.red = png_ptr->background.red; - back.green = png_ptr->background.green; - back.blue = png_ptr->background.blue; - } - else - { - back.red = - (png_byte)(pow((double)png_ptr->background.red/255, g) * - 255.0 + 0.5); - back.green = - (png_byte)(pow((double)png_ptr->background.green/255, g) * - 255.0 + 0.5); - back.blue = - (png_byte)(pow((double)png_ptr->background.blue/255, g) * - 255.0 + 0.5); - } - - g = 1.0 / png_ptr->background_gamma; - - back_1.red = - (png_byte)(pow((double)png_ptr->background.red/255, g) * - 255.0 + 0.5); - back_1.green = - (png_byte)(pow((double)png_ptr->background.green/255, g) * - 255.0 + 0.5); - back_1.blue = - (png_byte)(pow((double)png_ptr->background.blue/255, g) * - 255.0 + 0.5); - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_uint_32 i; - - for (i = 0; i < (png_uint_32)num_palette; i++) - { - if (i < png_ptr->num_trans && png_ptr->trans[i] == 0) - { - palette[i] = back; - } - else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff) - { - png_byte v, w; - - v = png_ptr->gamma_to_1[png_ptr->palette[i].red]; - png_composite(w, v, png_ptr->trans[i], back_1.red); - palette[i].red = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[png_ptr->palette[i].green]; - png_composite(w, v, png_ptr->trans[i], back_1.green); - palette[i].green = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[png_ptr->palette[i].blue]; - png_composite(w, v, png_ptr->trans[i], back_1.blue); - palette[i].blue = png_ptr->gamma_from_1[w]; - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - } - else - { - int i; - - for (i = 0; i < num_palette; i++) - { - if (palette[i].red == (png_byte)png_ptr->trans_values.gray) - { - palette[i] = back; - } - else - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } - } - } - else -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (png_ptr->transformations & PNG_GAMMA) - { - int i; - - for (i = 0; i < num_palette; i++) - { - palette[i].red = png_ptr->gamma_table[palette[i].red]; - palette[i].green = png_ptr->gamma_table[palette[i].green]; - palette[i].blue = png_ptr->gamma_table[palette[i].blue]; - } - } -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - else -#endif -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->transformations & PNG_BACKGROUND) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_color back; - - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - - for (i = 0; i < (int)png_ptr->num_trans; i++) - { - if (png_ptr->trans[i] == 0) - { - palette[i].red = back.red; - palette[i].green = back.green; - palette[i].blue = back.blue; - } - else if (png_ptr->trans[i] != 0xff) - { - png_composite(palette[i].red, png_ptr->palette[i].red, - png_ptr->trans[i], back.red); - png_composite(palette[i].green, png_ptr->palette[i].green, - png_ptr->trans[i], back.green); - png_composite(palette[i].blue, png_ptr->palette[i].blue, - png_ptr->trans[i], back.blue); - } - } - } - else /* Assume grayscale palette (what else could it be?) */ - { - int i; - - for (i = 0; i < num_palette; i++) - { - if (i == (png_byte)png_ptr->trans_values.gray) - { - palette[i].red = (png_byte)png_ptr->background.red; - palette[i].green = (png_byte)png_ptr->background.green; - palette[i].blue = (png_byte)png_ptr->background.blue; - } - } - } - } -#endif -} -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) -/* Replace any alpha or transparency with the supplied background color. - * "background" is already in the screen gamma, while "background_1" is - * at a gamma of 1.0. Paletted files have already been taken care of. - */ -void /* PRIVATE */ -png_do_background(png_row_infop row_info, png_bytep row, - png_color_16p trans_values, png_color_16p background -#if defined(PNG_READ_GAMMA_SUPPORTED) - , png_color_16p background_1, - png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, - png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, - png_uint_16pp gamma_16_to_1, int gamma_shift -#endif - ) -{ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - int shift; - - png_debug(1, "in png_do_background"); - if (background != NULL && -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || - (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values))) - { - switch (row_info->color_type) - { - case PNG_COLOR_TYPE_GRAY: - { - switch (row_info->bit_depth) - { - case 1: - { - sp = row; - shift = 7; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x01) - == trans_values->gray) - { - *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - if (!shift) - { - shift = 7; - sp++; - } - else - shift--; - } - break; - } - - case 2: - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_table != NULL) - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_values->gray) - { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - else - { - png_byte p = (png_byte)((*sp >> shift) & 0x03); - png_byte g = (png_byte)((gamma_table [p | (p << 2) | - (p << 4) | (p << 6)] >> 6) & 0x03); - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); - } - if (!shift) - { - shift = 6; - sp++; - } - else - shift -= 2; - } - } - else -#endif - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_values->gray) - { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - if (!shift) - { - shift = 6; - sp++; - } - else - shift -= 2; - } - } - break; - } - - case 4: - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_table != NULL) - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_values->gray) - { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - else - { - png_byte p = (png_byte)((*sp >> shift) & 0x0f); - png_byte g = (png_byte)((gamma_table[p | - (p << 4)] >> 4) & 0x0f); - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); - } - if (!shift) - { - shift = 4; - sp++; - } - else - shift -= 4; - } - } - else -#endif - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_values->gray) - { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); - } - if (!shift) - { - shift = 4; - sp++; - } - else - shift -= 4; - } - } - break; - } - - case 8: - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - if (*sp == trans_values->gray) - { - *sp = (png_byte)background->gray; - } - else - { - *sp = gamma_table[*sp]; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - if (*sp == trans_values->gray) - { - *sp = (png_byte)background->gray; - } - } - } - break; - } - - case 16: - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 v; - - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_values->gray) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); - } - else - { - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 v; - - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_values->gray) - { - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); - } - } - } - break; - } - } - break; - } - - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == trans_values->red && - *(sp + 1) == trans_values->green && - *(sp + 2) == trans_values->blue) - { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; - } - else - { - *sp = gamma_table[*sp]; - *(sp + 1) = gamma_table[*(sp + 1)]; - *(sp + 2) = gamma_table[*(sp + 2)]; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == trans_values->red && - *(sp + 1) == trans_values->green && - *(sp + 2) == trans_values->blue) - { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); - if (r == trans_values->red && g == trans_values->green && - b == trans_values->blue) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((background->red >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->red & 0xff); - *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(sp + 3) = (png_byte)(background->green & 0xff); - *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(sp + 5) = (png_byte)(background->blue & 0xff); - } - else - { - png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1)); - png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); - - if (r == trans_values->red && g == trans_values->green && - b == trans_values->blue) - { - *sp = (png_byte)((background->red >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->red & 0xff); - *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(sp + 3) = (png_byte)(background->green & 0xff); - *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(sp + 5) = (png_byte)(background->blue & 0xff); - } - } - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) - { - png_uint_16 a = *(sp + 1); - - if (a == 0xff) - { - *dp = gamma_table[*sp]; - } - else if (a == 0) - { - /* Background is already in screen gamma */ - *dp = (png_byte)background->gray; - } - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, background_1->gray); - *dp = gamma_from_1[w]; - } - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) - { - png_byte a = *(sp + 1); - - if (a == 0xff) - { - *dp = *sp; - } -#if defined(PNG_READ_GAMMA_SUPPORTED) - else if (a == 0) - { - *dp = (png_byte)background->gray; - } - else - { - png_composite(*dp, *sp, a, background_1->gray); - } -#else - *dp = (png_byte)background->gray; -#endif - } - } - } - else /* if (png_ptr->bit_depth == 16) */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) - { - png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - } -#if defined(PNG_READ_GAMMA_SUPPORTED) - else if (a == 0) -#else - else -#endif - { - /* Background is already in screen gamma */ - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); - } -#if defined(PNG_READ_GAMMA_SUPPORTED) - else - { - png_uint_16 g, v, w; - - g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(v, g, a, background_1->gray); - w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; - *dp = (png_byte)((w >> 8) & 0xff); - *(dp + 1) = (png_byte)(w & 0xff); - } -#endif - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) - { - png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); - if (a == (png_uint_16)0xffff) - { - png_memcpy(dp, sp, 2); - } -#if defined(PNG_READ_GAMMA_SUPPORTED) - else if (a == 0) -#else - else -#endif - { - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); - } -#if defined(PNG_READ_GAMMA_SUPPORTED) - else - { - png_uint_16 g, v; - - g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, background_1->gray); - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - } -#endif - } - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) - { - png_byte a = *(sp + 3); - - if (a == 0xff) - { - *dp = gamma_table[*sp]; - *(dp + 1) = gamma_table[*(sp + 1)]; - *(dp + 2) = gamma_table[*(sp + 2)]; - } - else if (a == 0) - { - /* Background is already in screen gamma */ - *dp = (png_byte)background->red; - *(dp + 1) = (png_byte)background->green; - *(dp + 2) = (png_byte)background->blue; - } - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, background_1->red); - *dp = gamma_from_1[w]; - v = gamma_to_1[*(sp + 1)]; - png_composite(w, v, a, background_1->green); - *(dp + 1) = gamma_from_1[w]; - v = gamma_to_1[*(sp + 2)]; - png_composite(w, v, a, background_1->blue); - *(dp + 2) = gamma_from_1[w]; - } - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) - { - png_byte a = *(sp + 3); - - if (a == 0xff) - { - *dp = *sp; - *(dp + 1) = *(sp + 1); - *(dp + 2) = *(sp + 2); - } - else if (a == 0) - { - *dp = (png_byte)background->red; - *(dp + 1) = (png_byte)background->green; - *(dp + 2) = (png_byte)background->blue; - } - else - { - png_composite(*dp, *sp, a, background->red); - png_composite(*(dp + 1), *(sp + 1), a, - background->green); - png_composite(*(dp + 2), *(sp + 2), a, - background->blue); - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(dp + 2) = (png_byte)((v >> 8) & 0xff); - *(dp + 3) = (png_byte)(v & 0xff); - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(dp + 4) = (png_byte)((v >> 8) & 0xff); - *(dp + 5) = (png_byte)(v & 0xff); - } - else if (a == 0) - { - /* Background is already in screen gamma */ - *dp = (png_byte)((background->red >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->red & 0xff); - *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(dp + 3) = (png_byte)(background->green & 0xff); - *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(dp + 5) = (png_byte)(background->blue & 0xff); - } - else - { - png_uint_16 v, w, x; - - v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(w, v, a, background_1->red); - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *dp = (png_byte)((x >> 8) & 0xff); - *(dp + 1) = (png_byte)(x & 0xff); - v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; - png_composite_16(w, v, a, background_1->green); - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *(dp + 2) = (png_byte)((x >> 8) & 0xff); - *(dp + 3) = (png_byte)(x & 0xff); - v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; - png_composite_16(w, v, a, background_1->blue); - x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; - *(dp + 4) = (png_byte)((x >> 8) & 0xff); - *(dp + 5) = (png_byte)(x & 0xff); - } - } - } - else -#endif - { - sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - if (a == (png_uint_16)0xffff) - { - png_memcpy(dp, sp, 6); - } - else if (a == 0) - { - *dp = (png_byte)((background->red >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->red & 0xff); - *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(dp + 3) = (png_byte)(background->green & 0xff); - *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(dp + 5) = (png_byte)(background->blue & 0xff); - } - else - { - png_uint_16 v; - - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - png_composite_16(v, r, a, background->red); - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); - png_composite_16(v, g, a, background->green); - *(dp + 2) = (png_byte)((v >> 8) & 0xff); - *(dp + 3) = (png_byte)(v & 0xff); - png_composite_16(v, b, a, background->blue); - *(dp + 4) = (png_byte)((v >> 8) & 0xff); - *(dp + 5) = (png_byte)(v & 0xff); - } - } - } - } - break; - } - } - - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; - row_info->channels--; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - } -} -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) -/* Gamma correct the image, avoiding the alpha channel. Make sure - * you do this after you deal with the transparency issue on grayscale - * or RGB images. If your bit depth is 8, use gamma_table, if it - * is 16, use gamma_16_table and gamma_shift. Build these with - * build_gamma_table(). - */ -void /* PRIVATE */ -png_do_gamma(png_row_infop row_info, png_bytep row, - png_bytep gamma_table, png_uint_16pp gamma_16_table, - int gamma_shift) -{ - png_bytep sp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_gamma"); - if ( -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - ((row_info->bit_depth <= 8 && gamma_table != NULL) || - (row_info->bit_depth == 16 && gamma_16_table != NULL))) - { - switch (row_info->color_type) - { - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - } - } - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v; - - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - *sp = gamma_table[*sp]; - sp++; - sp++; - } - } - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 4; - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp += 2; - } - } - else /* if (row_info->bit_depth == 16) */ - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 4; - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY: - { - if (row_info->bit_depth == 2) - { - sp = row; - for (i = 0; i < row_width; i += 4) - { - int a = *sp & 0xc0; - int b = *sp & 0x30; - int c = *sp & 0x0c; - int d = *sp & 0x03; - - *sp = (png_byte)( - ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| - ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| - ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| - ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); - sp++; - } - } - - if (row_info->bit_depth == 4) - { - sp = row; - for (i = 0; i < row_width; i += 2) - { - int msb = *sp & 0xf0; - int lsb = *sp & 0x0f; - - *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) - | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); - sp++; - } - } - - else if (row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++) - { - *sp = gamma_table[*sp]; - sp++; - } - } - - else if (row_info->bit_depth == 16) - { - sp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - sp += 2; - } - } - break; - } - } - } -} -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) -/* Expands a palette row to an RGB or RGBA row depending - * upon whether you supply trans and num_trans. - */ -void /* PRIVATE */ -png_do_expand_palette(png_row_infop row_info, png_bytep row, - png_colorp palette, png_bytep trans, int num_trans) -{ - int shift, value; - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_expand_palette"); - if ( -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - row_info->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (row_info->bit_depth < 8) - { - switch (row_info->bit_depth) - { - case 1: - { - sp = row + (png_size_t)((row_width - 1) >> 3); - dp = row + (png_size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - if ((*sp >> shift) & 0x01) - *dp = 1; - else - *dp = 0; - if (shift == 7) - { - shift = 0; - sp--; - } - else - shift++; - - dp--; - } - break; - } - - case 2: - { - sp = row + (png_size_t)((row_width - 1) >> 2); - dp = row + (png_size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)value; - if (shift == 6) - { - shift = 0; - sp--; - } - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - sp = row + (png_size_t)((row_width - 1) >> 1); - dp = row + (png_size_t)row_width - 1; - shift = (int)((row_width & 0x01) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)value; - if (shift == 4) - { - shift = 0; - sp--; - } - else - shift += 4; - - dp--; - } - break; - } - } - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - switch (row_info->bit_depth) - { - case 8: - { - if (trans != NULL) - { - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width << 2) - 1; - - for (i = 0; i < row_width; i++) - { - if ((int)(*sp) >= num_trans) - *dp-- = 0xff; - else - *dp-- = trans[*sp]; - *dp-- = palette[*sp].blue; - *dp-- = palette[*sp].green; - *dp-- = palette[*sp].red; - sp--; - } - row_info->bit_depth = 8; - row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; - row_info->color_type = 6; - row_info->channels = 4; - } - else - { - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width * 3) - 1; - - for (i = 0; i < row_width; i++) - { - *dp-- = palette[*sp].blue; - *dp-- = palette[*sp].green; - *dp-- = palette[*sp].red; - sp--; - } - - row_info->bit_depth = 8; - row_info->pixel_depth = 24; - row_info->rowbytes = row_width * 3; - row_info->color_type = 2; - row_info->channels = 3; - } - break; - } - } - } -} - -/* If the bit depth < 8, it is expanded to 8. Also, if the already - * expanded transparency value is supplied, an alpha channel is built. - */ -void /* PRIVATE */ -png_do_expand(png_row_infop row_info, png_bytep row, - png_color_16p trans_value) -{ - int shift, value; - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_expand"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (row != NULL && row_info != NULL) -#endif - { - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) - { - png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); - - if (row_info->bit_depth < 8) - { - switch (row_info->bit_depth) - { - case 1: - { - gray = (png_uint_16)((gray&0x01)*0xff); - sp = row + (png_size_t)((row_width - 1) >> 3); - dp = row + (png_size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - if ((*sp >> shift) & 0x01) - *dp = 0xff; - else - *dp = 0; - if (shift == 7) - { - shift = 0; - sp--; - } - else - shift++; - - dp--; - } - break; - } - - case 2: - { - gray = (png_uint_16)((gray&0x03)*0x55); - sp = row + (png_size_t)((row_width - 1) >> 2); - dp = row + (png_size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)(value | (value << 2) | (value << 4) | - (value << 6)); - if (shift == 6) - { - shift = 0; - sp--; - } - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - gray = (png_uint_16)((gray&0x0f)*0x11); - sp = row + (png_size_t)((row_width - 1) >> 1); - dp = row + (png_size_t)row_width - 1; - shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)(value | (value << 4)); - if (shift == 4) - { - shift = 0; - sp--; - } - else - shift = 4; - - dp--; - } - break; - } - } - - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } - - if (trans_value != NULL) - { - if (row_info->bit_depth == 8) - { - gray = gray & 0xff; - sp = row + (png_size_t)row_width - 1; - dp = row + (png_size_t)(row_width << 1) - 1; - for (i = 0; i < row_width; i++) - { - if (*sp == gray) - *dp-- = 0; - else - *dp-- = 0xff; - *dp-- = *sp--; - } - } - - else if (row_info->bit_depth == 16) - { - png_byte gray_high = (gray >> 8) & 0xff; - png_byte gray_low = gray & 0xff; - sp = row + row_info->rowbytes - 1; - dp = row + (row_info->rowbytes << 1) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 1) == gray_high && *(sp) == gray_low) - { - *dp-- = 0; - *dp-- = 0; - } - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - *dp-- = *sp--; - *dp-- = *sp--; - } - } - - row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - row_info->channels = 2; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_width); - } - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) - { - if (row_info->bit_depth == 8) - { - png_byte red = trans_value->red & 0xff; - png_byte green = trans_value->green & 0xff; - png_byte blue = trans_value->blue & 0xff; - sp = row + (png_size_t)row_info->rowbytes - 1; - dp = row + (png_size_t)(row_width << 2) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) - *dp-- = 0; - else - *dp-- = 0xff; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - else if (row_info->bit_depth == 16) - { - png_byte red_high = (trans_value->red >> 8) & 0xff; - png_byte green_high = (trans_value->green >> 8) & 0xff; - png_byte blue_high = (trans_value->blue >> 8) & 0xff; - png_byte red_low = trans_value->red & 0xff; - png_byte green_low = trans_value->green & 0xff; - png_byte blue_low = trans_value->blue & 0xff; - sp = row + row_info->rowbytes - 1; - dp = row + (png_size_t)(row_width << 3) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 5) == red_high && - *(sp - 4) == red_low && - *(sp - 3) == green_high && - *(sp - 2) == green_low && - *(sp - 1) == blue_high && - *(sp ) == blue_low) - { - *dp-- = 0; - *dp-- = 0; - } - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - row_info->channels = 4; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - } -} -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) -void /* PRIVATE */ -png_do_dither(png_row_infop row_info, png_bytep row, - png_bytep palette_lookup, png_bytep dither_lookup) -{ - png_bytep sp, dp; - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - png_debug(1, "in png_do_dither"); -#if defined(PNG_USELESS_TESTS_SUPPORTED) - if (row != NULL && row_info != NULL) -#endif - { - if (row_info->color_type == PNG_COLOR_TYPE_RGB && - palette_lookup && row_info->bit_depth == 8) - { - int r, g, b, p; - sp = row; - dp = row; - for (i = 0; i < row_width; i++) - { - r = *sp++; - g = *sp++; - b = *sp++; - - /* This looks real messy, but the compiler will reduce - * it down to a reasonable formula. For example, with - * 5 bits per color, we get: - * p = (((r >> 3) & 0x1f) << 10) | - * (((g >> 3) & 0x1f) << 5) | - * ((b >> 3) & 0x1f); - */ - p = (((r >> (8 - PNG_DITHER_RED_BITS)) & - ((1 << PNG_DITHER_RED_BITS) - 1)) << - (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | - (((g >> (8 - PNG_DITHER_GREEN_BITS)) & - ((1 << PNG_DITHER_GREEN_BITS) - 1)) << - (PNG_DITHER_BLUE_BITS)) | - ((b >> (8 - PNG_DITHER_BLUE_BITS)) & - ((1 << PNG_DITHER_BLUE_BITS) - 1)); - - *dp++ = palette_lookup[p]; - } - row_info->color_type = PNG_COLOR_TYPE_PALETTE; - row_info->channels = 1; - row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && - palette_lookup != NULL && row_info->bit_depth == 8) - { - int r, g, b, p; - sp = row; - dp = row; - for (i = 0; i < row_width; i++) - { - r = *sp++; - g = *sp++; - b = *sp++; - sp++; - - p = (((r >> (8 - PNG_DITHER_RED_BITS)) & - ((1 << PNG_DITHER_RED_BITS) - 1)) << - (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | - (((g >> (8 - PNG_DITHER_GREEN_BITS)) & - ((1 << PNG_DITHER_GREEN_BITS) - 1)) << - (PNG_DITHER_BLUE_BITS)) | - ((b >> (8 - PNG_DITHER_BLUE_BITS)) & - ((1 << PNG_DITHER_BLUE_BITS) - 1)); - - *dp++ = palette_lookup[p]; - } - row_info->color_type = PNG_COLOR_TYPE_PALETTE; - row_info->channels = 1; - row_info->pixel_depth = row_info->bit_depth; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } - else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && - dither_lookup && row_info->bit_depth == 8) - { - sp = row; - for (i = 0; i < row_width; i++, sp++) - { - *sp = dither_lookup[*sp]; - } - } - } -} -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -#if defined(PNG_READ_GAMMA_SUPPORTED) -static PNG_CONST int png_gamma_shift[] = - {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00}; - -/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit - * tables, we don't make a full table if we are reducing to 8-bit in - * the future. Note also how the gamma_16 tables are segmented so that - * we don't need to allocate > 64K chunks for a full 16-bit table. - */ -void /* PRIVATE */ -png_build_gamma_table(png_structp png_ptr) -{ - png_debug(1, "in png_build_gamma_table"); - - if (png_ptr->bit_depth <= 8) - { - int i; - double g; - - if (png_ptr->screen_gamma > .000001) - g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - - else - g = 1.0; - - png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr, - (png_uint_32)256); - - for (i = 0; i < 256; i++) - { - png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0, - g) * 255.0 + .5); - } - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) - { - - g = 1.0 / (png_ptr->gamma); - - png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr, - (png_uint_32)256); - - for (i = 0; i < 256; i++) - { - png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0, - g) * 255.0 + .5); - } - - - png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, - (png_uint_32)256); - - if (png_ptr->screen_gamma > 0.000001) - g = 1.0 / png_ptr->screen_gamma; - - else - g = png_ptr->gamma; /* Probably doing rgb_to_gray */ - - for (i = 0; i < 256; i++) - { - png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0, - g) * 255.0 + .5); - - } - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ - } - else - { - double g; - int i, j, shift, num; - int sig_bit; - png_uint_32 ig; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - { - sig_bit = (int)png_ptr->sig_bit.red; - - if ((int)png_ptr->sig_bit.green > sig_bit) - sig_bit = png_ptr->sig_bit.green; - - if ((int)png_ptr->sig_bit.blue > sig_bit) - sig_bit = png_ptr->sig_bit.blue; - } - else - { - sig_bit = (int)png_ptr->sig_bit.gray; - } - - if (sig_bit > 0) - shift = 16 - sig_bit; - - else - shift = 0; - - if (png_ptr->transformations & PNG_16_TO_8) - { - if (shift < (16 - PNG_MAX_GAMMA_8)) - shift = (16 - PNG_MAX_GAMMA_8); - } - - if (shift > 8) - shift = 8; - - if (shift < 0) - shift = 0; - - png_ptr->gamma_shift = (png_byte)shift; - - num = (1 << (8 - shift)); - - if (png_ptr->screen_gamma > .000001) - g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); - else - g = 1.0; - - png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr, - (png_uint_32)(num * png_sizeof(png_uint_16p))); - png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p)); - - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) - { - double fin, fout; - png_uint_32 last, max; - - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - } - - g = 1.0 / g; - last = 0; - for (i = 0; i < 256; i++) - { - fout = ((double)i + 0.5) / 256.0; - fin = pow(fout, g); - max = (png_uint_32)(fin * (double)((png_uint_32)num << 8)); - while (last <= max) - { - png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] - [(int)(last >> (8 - shift))] = (png_uint_16)( - (png_uint_16)i | ((png_uint_16)i << 8)); - last++; - } - } - while (last < ((png_uint_32)num << 8)) - { - png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] - [(int)(last >> (8 - shift))] = (png_uint_16)65535L; - last++; - } - } - else - { - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - - ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); - - for (j = 0; j < 256; j++) - { - png_ptr->gamma_16_table[i][j] = - (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / - 65535.0, g) * 65535.0 + .5); - } - } - } - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) - { - - g = 1.0 / (png_ptr->gamma); - - png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr, - (png_uint_32)(num * png_sizeof(png_uint_16p ))); - png_memset(png_ptr->gamma_16_to_1, 0, num * png_sizeof(png_uint_16p)); - - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - - ig = (((png_uint_32)i * - (png_uint_32)png_gamma_shift[shift]) >> 4); - for (j = 0; j < 256; j++) - { - png_ptr->gamma_16_to_1[i][j] = - (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / - 65535.0, g) * 65535.0 + .5); - } - } - - if (png_ptr->screen_gamma > 0.000001) - g = 1.0 / png_ptr->screen_gamma; - - else - g = png_ptr->gamma; /* Probably doing rgb_to_gray */ - - png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr, - (png_uint_32)(num * png_sizeof(png_uint_16p))); - png_memset(png_ptr->gamma_16_from_1, 0, - num * png_sizeof(png_uint_16p)); - - for (i = 0; i < num; i++) - { - png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(256 * png_sizeof(png_uint_16))); - - ig = (((png_uint_32)i * - (png_uint_32)png_gamma_shift[shift]) >> 4); - - for (j = 0; j < 256; j++) - { - png_ptr->gamma_16_from_1[i][j] = - (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / - 65535.0, g) * 65535.0 + .5); - } - } - } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ - } -} -#endif -/* To do: install integer version of png_build_gamma_table here */ -#endif - -#if defined(PNG_MNG_FEATURES_SUPPORTED) -/* Undoes intrapixel differencing */ -void /* PRIVATE */ -png_do_read_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_intrapixel"); - if ( -#if defined(PNG_USELESS_TESTS_SUPPORTED) - row != NULL && row_info != NULL && -#endif - (row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff); - *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff); - } - } - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp+1) = (png_byte)(red & 0xff); - *(rp+4) = (png_byte)((blue >> 8) & 0xff); - *(rp+5) = (png_byte)(blue & 0xff); - } - } - } -} -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c deleted file mode 100644 index f656dfb..0000000 --- a/src/3rdparty/libpng/pngrutil.c +++ /dev/null @@ -1,3252 +0,0 @@ - -/* pngrutil.c - utilities to read a PNG file - * - * Last changed in libpng 1.2.38 [July 16, 2009] - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This code is released under the libpng license. - * For conditions of distribution and use, see the disclaimer - * and license in png.h - * - * This file contains routines that are only called from within - * libpng itself during the course of reading an image. - */ - -#define PNG_INTERNAL -#include "png.h" -#if defined(PNG_READ_SUPPORTED) - -#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500) -# define WIN32_WCE_OLD -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -# if defined(WIN32_WCE_OLD) -/* The strtod() function is not supported on WindowsCE */ -__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr, char **endptr) -{ - double result = 0; - int len; - wchar_t *str, *end; - - len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0); - str = (wchar_t *)png_malloc(png_ptr, len * png_sizeof(wchar_t)); - if ( NULL != str ) - { - MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len); - result = wcstod(str, &end); - len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL); - *endptr = (char *)nptr + (png_strlen(nptr) - len + 1); - png_free(png_ptr, str); - } - return result; -} -# else -# define png_strtod(p,a,b) strtod(a,b) -# endif -#endif - -png_uint_32 PNGAPI -png_get_uint_31(png_structp png_ptr, png_bytep buf) -{ -#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED - png_uint_32 i = png_get_uint_32(buf); -#else - /* Avoid an extra function call by inlining the result. */ - png_uint_32 i = ((png_uint_32)(*buf) << 24) + - ((png_uint_32)(*(buf + 1)) << 16) + - ((png_uint_32)(*(buf + 2)) << 8) + - (png_uint_32)(*(buf + 3)); -#endif - if (i > PNG_UINT_31_MAX) - png_error(png_ptr, "PNG unsigned integer out of range."); - return (i); -} -#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED -/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ -png_uint_32 PNGAPI -png_get_uint_32(png_bytep buf) -{ - png_uint_32 i = ((png_uint_32)(*buf) << 24) + - ((png_uint_32)(*(buf + 1)) << 16) + - ((png_uint_32)(*(buf + 2)) << 8) + - (png_uint_32)(*(buf + 3)); - - return (i); -} - -/* Grab a signed 32-bit integer from a buffer in big-endian format. The - * data is stored in the PNG file in two's complement format, and it is - * assumed that the machine format for signed integers is the same. - */ -png_int_32 PNGAPI -png_get_int_32(png_bytep buf) -{ - png_int_32 i = ((png_int_32)(*buf) << 24) + - ((png_int_32)(*(buf + 1)) << 16) + - ((png_int_32)(*(buf + 2)) << 8) + - (png_int_32)(*(buf + 3)); - - return (i); -} - -/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ -png_uint_16 PNGAPI -png_get_uint_16(png_bytep buf) -{ - png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) + - (png_uint_16)(*(buf + 1))); - - return (i); -} -#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */ - -/* Read the chunk header (length + type name). - * Put the type name into png_ptr->chunk_name, and return the length. - */ -png_uint_32 /* PRIVATE */ -png_read_chunk_header(png_structp png_ptr) -{ - png_byte buf[8]; - png_uint_32 length; - - /* Read the length and the chunk name */ - png_read_data(png_ptr, buf, 8); - length = png_get_uint_31(png_ptr, buf); - - /* Put the chunk name into png_ptr->chunk_name */ - png_memcpy(png_ptr->chunk_name, buf + 4, 4); - - png_debug2(0, "Reading %s chunk, length = %lu", - png_ptr->chunk_name, length); - - /* Reset the crc and run it over the chunk name */ - png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); - - /* Check to see if chunk name is valid */ - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - - return length; -} - -/* Read data, and (optionally) run it through the CRC. */ -void /* PRIVATE */ -png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) -{ - if (png_ptr == NULL) - return; - png_read_data(png_ptr, buf, length); - png_calculate_crc(png_ptr, buf, length); -} - -/* Optionally skip data and then check the CRC. Depending on whether we - * are reading a ancillary or critical chunk, and how the program has set - * things up, we may calculate the CRC on the data and print a message. - * Returns '1' if there was a CRC error, '0' otherwise. - */ -int /* PRIVATE */ -png_crc_finish(png_structp png_ptr, png_uint_32 skip) -{ - png_size_t i; - png_size_t istop = png_ptr->zbuf_size; - - for (i = (png_size_t)skip; i > istop; i -= istop) - { - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - } - if (i) - { - png_crc_read(png_ptr, png_ptr->zbuf, i); - } - - if (png_crc_error(png_ptr)) - { - if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ - !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || - (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) - { - png_chunk_warning(png_ptr, "CRC error"); - } - else - { - png_chunk_error(png_ptr, "CRC error"); - } - return (1); - } - - return (0); -} - -/* Compare the CRC stored in the PNG file with that calculated by libpng from - * the data it has read thus far. - */ -int /* PRIVATE */ -png_crc_error(png_structp png_ptr) -{ - png_byte crc_bytes[4]; - png_uint_32 crc; - int need_crc = 1; - - if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - - png_read_data(png_ptr, crc_bytes, 4); - - if (need_crc) - { - crc = png_get_uint_32(crc_bytes); - return ((int)(crc != png_ptr->crc)); - } - else - return (0); -} - -#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ - defined(PNG_READ_iCCP_SUPPORTED) -/* - * Decompress trailing data in a chunk. The assumption is that chunkdata - * points at an allocated area holding the contents of a chunk with a - * trailing compressed part. What we get back is an allocated area - * holding the original prefix part and an uncompressed version of the - * trailing part (the malloc area passed in is freed). - */ -void /* PRIVATE */ -png_decompress_chunk(png_structp png_ptr, int comp_type, - png_size_t chunklength, - png_size_t prefix_size, png_size_t *newlength) -{ - static PNG_CONST char msg[] = "Error decoding compressed text"; - png_charp text; - png_size_t text_size; - - if (comp_type == PNG_COMPRESSION_TYPE_BASE) - { - int ret = Z_OK; - png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size); - png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - text_size = 0; - text = NULL; - - while (png_ptr->zstream.avail_in) - { - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - if (png_ptr->zstream.msg != NULL) - png_warning(png_ptr, png_ptr->zstream.msg); - else - png_warning(png_ptr, msg); - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - - if (text == NULL) - { - text_size = prefix_size + png_sizeof(msg) + 1; - text = (png_charp)png_malloc_warn(png_ptr, text_size); - if (text == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_error(png_ptr, "Not enough memory to decompress chunk"); - } - png_memcpy(text, png_ptr->chunkdata, prefix_size); - } - - text[text_size - 1] = 0x00; - - /* Copy what we can of the error message into the text chunk */ - text_size = (png_size_t)(chunklength - - (text - png_ptr->chunkdata) - 1); - if (text_size > png_sizeof(msg)) - text_size = png_sizeof(msg); - png_memcpy(text + prefix_size, msg, text_size); - break; - } - if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) - { - if (text == NULL) - { - text_size = prefix_size + - png_ptr->zbuf_size - png_ptr->zstream.avail_out; - text = (png_charp)png_malloc_warn(png_ptr, text_size + 1); - if (text == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_error(png_ptr, - "Not enough memory to decompress chunk."); - } - png_memcpy(text + prefix_size, png_ptr->zbuf, - text_size - prefix_size); - png_memcpy(text, png_ptr->chunkdata, prefix_size); - *(text + text_size) = 0x00; - } - else - { - png_charp tmp; - - tmp = text; - text = (png_charp)png_malloc_warn(png_ptr, - (png_uint_32)(text_size + - png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1)); - if (text == NULL) - { - png_free(png_ptr, tmp); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_error(png_ptr, - "Not enough memory to decompress chunk.."); - } - png_memcpy(text, tmp, text_size); - png_free(png_ptr, tmp); - png_memcpy(text + text_size, png_ptr->zbuf, - (png_ptr->zbuf_size - png_ptr->zstream.avail_out)); - text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; - *(text + text_size) = 0x00; - } - if (ret == Z_STREAM_END) - break; - else - { - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - } - } - if (ret != Z_STREAM_END) - { -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - char umsg[52]; - - if (ret == Z_BUF_ERROR) - png_snprintf(umsg, 52, - "Buffer error in compressed datastream in %s chunk", - png_ptr->chunk_name); - - else if (ret == Z_DATA_ERROR) - png_snprintf(umsg, 52, - "Data error in compressed datastream in %s chunk", - png_ptr->chunk_name); - - else - png_snprintf(umsg, 52, - "Incomplete compressed datastream in %s chunk", - png_ptr->chunk_name); - - png_warning(png_ptr, umsg); -#else - png_warning(png_ptr, - "Incomplete compressed datastream in chunk other than IDAT"); -#endif - text_size = prefix_size; - if (text == NULL) - { - text = (png_charp)png_malloc_warn(png_ptr, text_size+1); - if (text == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_error(png_ptr, "Not enough memory for text."); - } - png_memcpy(text, png_ptr->chunkdata, prefix_size); - } - *(text + text_size) = 0x00; - } - - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - *newlength=text_size; - } - else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ - { -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - char umsg[50]; - - png_snprintf(umsg, 50, "Unknown zTXt compression type %d", comp_type); - png_warning(png_ptr, umsg); -#else - png_warning(png_ptr, "Unknown zTXt compression type"); -#endif - - *(png_ptr->chunkdata + prefix_size) = 0x00; - *newlength = prefix_size; - } -} -#endif - -/* Read and check the IDHR chunk */ -void /* PRIVATE */ -png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[13]; - png_uint_32 width, height; - int bit_depth, color_type, compression_type, filter_type; - int interlace_type; - - png_debug(1, "in png_handle_IHDR"); - - if (png_ptr->mode & PNG_HAVE_IHDR) - png_error(png_ptr, "Out of place IHDR"); - - /* Check the length */ - if (length != 13) - png_error(png_ptr, "Invalid IHDR chunk"); - - png_ptr->mode |= PNG_HAVE_IHDR; - - png_crc_read(png_ptr, buf, 13); - png_crc_finish(png_ptr, 0); - - width = png_get_uint_31(png_ptr, buf); - height = png_get_uint_31(png_ptr, buf + 4); - bit_depth = buf[8]; - color_type = buf[9]; - compression_type = buf[10]; - filter_type = buf[11]; - interlace_type = buf[12]; - - /* Set internal variables */ - png_ptr->width = width; - png_ptr->height = height; - png_ptr->bit_depth = (png_byte)bit_depth; - png_ptr->interlaced = (png_byte)interlace_type; - png_ptr->color_type = (png_byte)color_type; -#if defined(PNG_MNG_FEATURES_SUPPORTED) - png_ptr->filter_type = (png_byte)filter_type; -#endif - png_ptr->compression_type = (png_byte)compression_type; - - /* Find number of channels */ - switch (png_ptr->color_type) - { - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_PALETTE: - png_ptr->channels = 1; - break; - - case PNG_COLOR_TYPE_RGB: - png_ptr->channels = 3; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - png_ptr->channels = 2; - break; - - case PNG_COLOR_TYPE_RGB_ALPHA: - png_ptr->channels = 4; - break; - } - - /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * - png_ptr->channels); - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); - png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); - png_debug1(3, "channels = %d", png_ptr->channels); - png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes); - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, - color_type, interlace_type, compression_type, filter_type); -} - -/* Read and check the palette */ -void /* PRIVATE */ -png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_color palette[PNG_MAX_PALETTE_LENGTH]; - int num, i; -#ifndef PNG_NO_POINTER_INDEXING - png_colorp pal_ptr; -#endif - - png_debug(1, "in png_handle_PLTE"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before PLTE"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid PLTE after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - png_error(png_ptr, "Duplicate PLTE chunk"); - - png_ptr->mode |= PNG_HAVE_PLTE; - - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) - { - png_warning(png_ptr, - "Ignoring PLTE chunk in grayscale PNG"); - png_crc_finish(png_ptr, length); - return; - } -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_crc_finish(png_ptr, length); - return; - } -#endif - - if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) - { - if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_warning(png_ptr, "Invalid palette chunk"); - png_crc_finish(png_ptr, length); - return; - } - - else - { - png_error(png_ptr, "Invalid palette chunk"); - } - } - - num = (int)length / 3; - -#ifndef PNG_NO_POINTER_INDEXING - for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) - { - png_byte buf[3]; - - png_crc_read(png_ptr, buf, 3); - pal_ptr->red = buf[0]; - pal_ptr->green = buf[1]; - pal_ptr->blue = buf[2]; - } -#else - for (i = 0; i < num; i++) - { - png_byte buf[3]; - - png_crc_read(png_ptr, buf, 3); - /* Don't depend upon png_color being any order */ - palette[i].red = buf[0]; - palette[i].green = buf[1]; - palette[i].blue = buf[2]; - } -#endif - - /* If we actually NEED the PLTE chunk (ie for a paletted image), we do - * whatever the normal CRC configuration tells us. However, if we - * have an RGB image, the PLTE can be considered ancillary, so - * we will act as though it is. - */ -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#endif - { - png_crc_finish(png_ptr, 0); - } -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ - { - /* If we don't want to use the data from an ancillary chunk, - we have two options: an error abort, or a warning and we - ignore the data in this chunk (which should be OK, since - it's considered ancillary for a RGB or RGBA image). */ - if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) - { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - { - png_chunk_error(png_ptr, "CRC error"); - } - else - { - png_chunk_warning(png_ptr, "CRC error"); - return; - } - } - /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { - png_chunk_warning(png_ptr, "CRC error"); - } - } -#endif - - png_set_PLTE(png_ptr, info_ptr, palette, num); - -#if defined(PNG_READ_tRNS_SUPPORTED) - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - if (png_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); - png_ptr->num_trans = (png_uint_16)num; - } - if (info_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); - info_ptr->num_trans = (png_uint_16)num; - } - } - } -#endif - -} - -void /* PRIVATE */ -png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_debug(1, "in png_handle_IEND"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) - { - png_error(png_ptr, "No image in file"); - } - - png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); - - if (length != 0) - { - png_warning(png_ptr, "Incorrect IEND chunk length"); - } - png_crc_finish(png_ptr, length); - - info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ -} - -#if defined(PNG_READ_gAMA_SUPPORTED) -void /* PRIVATE */ -png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_fixed_point igamma; -#ifdef PNG_FLOATING_POINT_SUPPORTED - float file_gamma; -#endif - png_byte buf[4]; - - png_debug(1, "in png_handle_gAMA"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before gAMA"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid gAMA after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place gAMA chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) -#if defined(PNG_READ_sRGB_SUPPORTED) - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) - { - png_warning(png_ptr, "Duplicate gAMA chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 4) - { - png_warning(png_ptr, "Incorrect gAMA chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 4); - if (png_crc_finish(png_ptr, 0)) - return; - - igamma = (png_fixed_point)png_get_uint_32(buf); - /* Check for zero gamma */ - if (igamma == 0) - { - png_warning(png_ptr, - "Ignoring gAMA chunk with gamma=0"); - return; - } - -#if defined(PNG_READ_sRGB_SUPPORTED) - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifndef PNG_NO_CONSOLE_IO - fprintf(stderr, "gamma = (%d/100000)", (int)igamma); -#endif - return; - } -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - file_gamma = (float)igamma / (float)100000.0; -# ifdef PNG_READ_GAMMA_SUPPORTED - png_ptr->gamma = file_gamma; -# endif - png_set_gAMA(png_ptr, info_ptr, file_gamma); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_gAMA_fixed(png_ptr, info_ptr, igamma); -#endif -} -#endif - -#if defined(PNG_READ_sBIT_SUPPORTED) -void /* PRIVATE */ -png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_size_t truelen; - png_byte buf[4]; - - png_debug(1, "in png_handle_sBIT"); - - buf[0] = buf[1] = buf[2] = buf[3] = 0; - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sBIT"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sBIT after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - { - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sBIT chunk"); - } - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) - { - png_warning(png_ptr, "Duplicate sBIT chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - truelen = 3; - else - truelen = (png_size_t)png_ptr->channels; - - if (length != truelen || length > 4) - { - png_warning(png_ptr, "Incorrect sBIT chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) - return; - - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - { - png_ptr->sig_bit.red = buf[0]; - png_ptr->sig_bit.green = buf[1]; - png_ptr->sig_bit.blue = buf[2]; - png_ptr->sig_bit.alpha = buf[3]; - } - else - { - png_ptr->sig_bit.gray = buf[0]; - png_ptr->sig_bit.red = buf[0]; - png_ptr->sig_bit.green = buf[0]; - png_ptr->sig_bit.blue = buf[0]; - png_ptr->sig_bit.alpha = buf[1]; - } - png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); -} -#endif - -#if defined(PNG_READ_cHRM_SUPPORTED) -void /* PRIVATE */ -png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[32]; -#ifdef PNG_FLOATING_POINT_SUPPORTED - float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; -#endif - png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, - int_y_green, int_x_blue, int_y_blue; - - png_uint_32 uint_x, uint_y; - - png_debug(1, "in png_handle_cHRM"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before cHRM"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid cHRM after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Missing PLTE before cHRM"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) -#if defined(PNG_READ_sRGB_SUPPORTED) - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) - { - png_warning(png_ptr, "Duplicate cHRM chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 32) - { - png_warning(png_ptr, "Incorrect cHRM chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 32); - if (png_crc_finish(png_ptr, 0)) - return; - - uint_x = png_get_uint_32(buf); - uint_y = png_get_uint_32(buf + 4); - int_x_white = (png_fixed_point)uint_x; - int_y_white = (png_fixed_point)uint_y; - - uint_x = png_get_uint_32(buf + 8); - uint_y = png_get_uint_32(buf + 12); - int_x_red = (png_fixed_point)uint_x; - int_y_red = (png_fixed_point)uint_y; - - uint_x = png_get_uint_32(buf + 16); - uint_y = png_get_uint_32(buf + 20); - int_x_green = (png_fixed_point)uint_x; - int_y_green = (png_fixed_point)uint_y; - - uint_x = png_get_uint_32(buf + 24); - uint_y = png_get_uint_32(buf + 28); - int_x_blue = (png_fixed_point)uint_x; - int_y_blue = (png_fixed_point)uint_y; - -#ifdef PNG_FLOATING_POINT_SUPPORTED - white_x = (float)int_x_white / (float)100000.0; - white_y = (float)int_y_white / (float)100000.0; - red_x = (float)int_x_red / (float)100000.0; - red_y = (float)int_y_red / (float)100000.0; - green_x = (float)int_x_green / (float)100000.0; - green_y = (float)int_y_green / (float)100000.0; - blue_x = (float)int_x_blue / (float)100000.0; - blue_y = (float)int_y_blue / (float)100000.0; -#endif - -#if defined(PNG_READ_sRGB_SUPPORTED) - if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) - { - if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); -#ifndef PNG_NO_CONSOLE_IO -#ifdef PNG_FLOATING_POINT_SUPPORTED - fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n", - white_x, white_y, red_x, red_y); - fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n", - green_x, green_y, blue_x, blue_y); -#else - fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", - int_x_white, int_y_white, int_x_red, int_y_red); - fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n", - int_x_green, int_y_green, int_x_blue, int_y_blue); -#endif -#endif /* PNG_NO_CONSOLE_IO */ - } - return; - } -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_cHRM(png_ptr, info_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_cHRM_fixed(png_ptr, info_ptr, - int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, - int_y_green, int_x_blue, int_y_blue); -#endif -} -#endif - -#if defined(PNG_READ_sRGB_SUPPORTED) -void /* PRIVATE */ -png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - int intent; - png_byte buf[1]; - - png_debug(1, "in png_handle_sRGB"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sRGB"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sRGB after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sRGB chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - { - png_warning(png_ptr, "Duplicate sRGB chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 1) - { - png_warning(png_ptr, "Incorrect sRGB chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 1); - if (png_crc_finish(png_ptr, 0)) - return; - - intent = buf[0]; - /* Check for bad intent */ - if (intent >= PNG_sRGB_INTENT_LAST) - { - png_warning(png_ptr, "Unknown sRGB intent"); - return; - } - -#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) - { - png_fixed_point igamma; -#ifdef PNG_FIXED_POINT_SUPPORTED - igamma=info_ptr->int_gamma; -#else -# ifdef PNG_FLOATING_POINT_SUPPORTED - igamma=(png_fixed_point)(info_ptr->gamma * 100000.); -# endif -#endif - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifndef PNG_NO_CONSOLE_IO -# ifdef PNG_FIXED_POINT_SUPPORTED - fprintf(stderr, "incorrect gamma=(%d/100000)\n", - (int)png_ptr->int_gamma); -# else -# ifdef PNG_FLOATING_POINT_SUPPORTED - fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma); -# endif -# endif -#endif - } - } -#endif /* PNG_READ_gAMA_SUPPORTED */ - -#ifdef PNG_READ_cHRM_SUPPORTED -#ifdef PNG_FIXED_POINT_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); - } -#endif /* PNG_FIXED_POINT_SUPPORTED */ -#endif /* PNG_READ_cHRM_SUPPORTED */ - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); -} -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#if defined(PNG_READ_iCCP_SUPPORTED) -void /* PRIVATE */ -png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ -{ - png_byte compression_type; - png_bytep pC; - png_charp profile; - png_uint_32 skip = 0; - png_uint_32 profile_size, profile_length; - png_size_t slength, prefix_length, data_length; - - png_debug(1, "in png_handle_iCCP"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iCCP"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid iCCP after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place iCCP chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) - { - png_warning(png_ptr, "Duplicate iCCP chunk"); - png_crc_finish(png_ptr, length); - return; - } - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "iCCP chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (profile = png_ptr->chunkdata; *profile; profile++) - /* Empty loop to find end of name */ ; - - ++profile; - - /* There should be at least one zero (the compression type byte) - * following the separator, and we should be on it - */ - if ( profile >= png_ptr->chunkdata + slength - 1) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Malformed iCCP chunk"); - return; - } - - /* Compression_type should always be zero */ - compression_type = *profile++; - if (compression_type) - { - png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); - compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 - wrote nonzero) */ - } - - prefix_length = profile - png_ptr->chunkdata; - png_decompress_chunk(png_ptr, compression_type, - slength, prefix_length, &data_length); - - profile_length = data_length - prefix_length; - - if ( prefix_length > data_length || profile_length < 4) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Profile size field missing from iCCP chunk"); - return; - } - - /* Check the profile_size recorded in the first 32 bits of the ICC profile */ - pC = (png_bytep)(png_ptr->chunkdata + prefix_length); - profile_size = ((*(pC ))<<24) | - ((*(pC + 1))<<16) | - ((*(pC + 2))<< 8) | - ((*(pC + 3)) ); - - if (profile_size < profile_length) - profile_length = profile_size; - - if (profile_size > profile_length) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Ignoring truncated iCCP profile."); - return; - } - - png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, - compression_type, png_ptr->chunkdata + prefix_length, profile_length); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -} -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#if defined(PNG_READ_sPLT_SUPPORTED) -void /* PRIVATE */ -png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ -{ - png_bytep entry_start; - png_sPLT_t new_palette; -#ifdef PNG_NO_POINTER_INDEXING - png_sPLT_entryp pp; -#endif - int data_length, entry_size, i; - png_uint_32 skip = 0; - png_size_t slength; - - png_debug(1, "in png_handle_sPLT"); - - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sPLT"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sPLT after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "sPLT chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; entry_start++) - /* Empty loop to find end of name */ ; - ++entry_start; - - /* A sample depth should follow the separator, and we should be on it */ - if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "malformed sPLT chunk"); - return; - } - - new_palette.depth = *entry_start++; - entry_size = (new_palette.depth == 8 ? 6 : 10); - data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata)); - - /* Integrity-check the data length */ - if (data_length % entry_size) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "sPLT chunk has bad length"); - return; - } - - new_palette.nentries = (png_int_32) ( data_length / entry_size); - if ((png_uint_32) new_palette.nentries > - (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry))) - { - png_warning(png_ptr, "sPLT chunk too long"); - return; - } - new_palette.entries = (png_sPLT_entryp)png_malloc_warn( - png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); - if (new_palette.entries == NULL) - { - png_warning(png_ptr, "sPLT chunk requires too much memory"); - return; - } - -#ifndef PNG_NO_POINTER_INDEXING - for (i = 0; i < new_palette.nentries; i++) - { - png_sPLT_entryp pp = new_palette.entries + i; - - if (new_palette.depth == 8) - { - pp->red = *entry_start++; - pp->green = *entry_start++; - pp->blue = *entry_start++; - pp->alpha = *entry_start++; - } - else - { - pp->red = png_get_uint_16(entry_start); entry_start += 2; - pp->green = png_get_uint_16(entry_start); entry_start += 2; - pp->blue = png_get_uint_16(entry_start); entry_start += 2; - pp->alpha = png_get_uint_16(entry_start); entry_start += 2; - } - pp->frequency = png_get_uint_16(entry_start); entry_start += 2; - } -#else - pp = new_palette.entries; - for (i = 0; i < new_palette.nentries; i++) - { - - if (new_palette.depth == 8) - { - pp[i].red = *entry_start++; - pp[i].green = *entry_start++; - pp[i].blue = *entry_start++; - pp[i].alpha = *entry_start++; - } - else - { - pp[i].red = png_get_uint_16(entry_start); entry_start += 2; - pp[i].green = png_get_uint_16(entry_start); entry_start += 2; - pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; - pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; - } - pp->frequency = png_get_uint_16(entry_start); entry_start += 2; - } -#endif - - /* Discard all chunk data except the name and stash that */ - new_palette.name = png_ptr->chunkdata; - - png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, new_palette.entries); -} -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#if defined(PNG_READ_tRNS_SUPPORTED) -void /* PRIVATE */ -png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; - - png_debug(1, "in png_handle_tRNS"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tRNS"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid tRNS after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - png_warning(png_ptr, "Duplicate tRNS chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - png_byte buf[2]; - - if (length != 2) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 2); - png_ptr->num_trans = 1; - png_ptr->trans_values.gray = png_get_uint_16(buf); - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_byte buf[6]; - - if (length != 6) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - png_crc_read(png_ptr, buf, (png_size_t)length); - png_ptr->num_trans = 1; - png_ptr->trans_values.red = png_get_uint_16(buf); - png_ptr->trans_values.green = png_get_uint_16(buf + 2); - png_ptr->trans_values.blue = png_get_uint_16(buf + 4); - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - /* Should be an error, but we can cope with it. */ - png_warning(png_ptr, "Missing PLTE before tRNS"); - } - if (length > (png_uint_32)png_ptr->num_palette || - length > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); - png_crc_finish(png_ptr, length); - return; - } - if (length == 0) - { - png_warning(png_ptr, "Zero length tRNS chunk"); - png_crc_finish(png_ptr, length); - return; - } - png_crc_read(png_ptr, readbuf, (png_size_t)length); - png_ptr->num_trans = (png_uint_16)length; - } - else - { - png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_crc_finish(png_ptr, 0)) - { - png_ptr->num_trans = 0; - return; - } - - png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, - &(png_ptr->trans_values)); -} -#endif - -#if defined(PNG_READ_bKGD_SUPPORTED) -void /* PRIVATE */ -png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_size_t truelen; - png_byte buf[6]; - - png_debug(1, "in png_handle_bKGD"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before bKGD"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid bKGD after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - { - png_warning(png_ptr, "Missing PLTE before bKGD"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) - { - png_warning(png_ptr, "Duplicate bKGD chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - truelen = 1; - else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) - truelen = 6; - else - truelen = 2; - - if (length != truelen) - { - png_warning(png_ptr, "Incorrect bKGD chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) - return; - - /* We convert the index value into RGB components so that we can allow - * arbitrary RGB values for background when we have transparency, and - * so it is easy to determine the RGB values of the background color - * from the info_ptr struct. */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - png_ptr->background.index = buf[0]; - if (info_ptr && info_ptr->num_palette) - { - if (buf[0] >= info_ptr->num_palette) - { - png_warning(png_ptr, "Incorrect bKGD chunk index value"); - return; - } - png_ptr->background.red = - (png_uint_16)png_ptr->palette[buf[0]].red; - png_ptr->background.green = - (png_uint_16)png_ptr->palette[buf[0]].green; - png_ptr->background.blue = - (png_uint_16)png_ptr->palette[buf[0]].blue; - } - } - else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ - { - png_ptr->background.red = - png_ptr->background.green = - png_ptr->background.blue = - png_ptr->background.gray = png_get_uint_16(buf); - } - else - { - png_ptr->background.red = png_get_uint_16(buf); - png_ptr->background.green = png_get_uint_16(buf + 2); - png_ptr->background.blue = png_get_uint_16(buf + 4); - } - - png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); -} -#endif - -#if defined(PNG_READ_hIST_SUPPORTED) -void /* PRIVATE */ -png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - unsigned int num, i; - png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; - - png_debug(1, "in png_handle_hIST"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before hIST"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid hIST after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - png_warning(png_ptr, "Missing PLTE before hIST"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) - { - png_warning(png_ptr, "Duplicate hIST chunk"); - png_crc_finish(png_ptr, length); - return; - } - - num = length / 2 ; - if (num != (unsigned int) png_ptr->num_palette || num > - (unsigned int) PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, "Incorrect hIST chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - for (i = 0; i < num; i++) - { - png_byte buf[2]; - - png_crc_read(png_ptr, buf, 2); - readbuf[i] = png_get_uint_16(buf); - } - - if (png_crc_finish(png_ptr, 0)) - return; - - png_set_hIST(png_ptr, info_ptr, readbuf); -} -#endif - -#if defined(PNG_READ_pHYs_SUPPORTED) -void /* PRIVATE */ -png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[9]; - png_uint_32 res_x, res_y; - int unit_type; - - png_debug(1, "in png_handle_pHYs"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pHYs"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid pHYs after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) - { - png_warning(png_ptr, "Duplicate pHYs chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 9) - { - png_warning(png_ptr, "Incorrect pHYs chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) - return; - - res_x = png_get_uint_32(buf); - res_y = png_get_uint_32(buf + 4); - unit_type = buf[8]; - png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); -} -#endif - -#if defined(PNG_READ_oFFs_SUPPORTED) -void /* PRIVATE */ -png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[9]; - png_int_32 offset_x, offset_y; - int unit_type; - - png_debug(1, "in png_handle_oFFs"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before oFFs"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid oFFs after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) - { - png_warning(png_ptr, "Duplicate oFFs chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (length != 9) - { - png_warning(png_ptr, "Incorrect oFFs chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) - return; - - offset_x = png_get_int_32(buf); - offset_y = png_get_int_32(buf + 4); - unit_type = buf[8]; - png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); -} -#endif - -#if defined(PNG_READ_pCAL_SUPPORTED) -/* Read the pCAL chunk (described in the PNG Extensions document) */ -void /* PRIVATE */ -png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_int_32 X0, X1; - png_byte type, nparams; - png_charp buf, units, endptr; - png_charpp params; - png_size_t slength; - int i; - - png_debug(1, "in png_handle_pCAL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pCAL"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid pCAL after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) - { - png_warning(png_ptr, "Duplicate pCAL chunk"); - png_crc_finish(png_ptr, length); - return; - } - - png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)", - length + 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory for pCAL purpose."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - - png_debug(3, "Finding end of pCAL purpose string"); - for (buf = png_ptr->chunkdata; *buf; buf++) - /* Empty loop */ ; - - endptr = png_ptr->chunkdata + slength; - - /* We need to have at least 12 bytes after the purpose string - in order to get the parameter information. */ - if (endptr <= buf + 12) - { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); - X0 = png_get_int_32((png_bytep)buf+1); - X1 = png_get_int_32((png_bytep)buf+5); - type = buf[9]; - nparams = buf[10]; - units = buf + 11; - - png_debug(3, "Checking pCAL equation type and number of parameters"); - /* Check that we have the right number of parameters for known - equation types. */ - if ((type == PNG_EQUATION_LINEAR && nparams != 2) || - (type == PNG_EQUATION_BASE_E && nparams != 3) || - (type == PNG_EQUATION_ARBITRARY && nparams != 3) || - (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) - { - png_warning(png_ptr, "Invalid pCAL parameters for equation type"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - else if (type >= PNG_EQUATION_LAST) - { - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); - } - - for (buf = units; *buf; buf++) - /* Empty loop to move past the units string. */ ; - - png_debug(3, "Allocating pCAL parameters array"); - params = (png_charpp)png_malloc_warn(png_ptr, - (png_uint_32)(nparams * png_sizeof(png_charp))) ; - if (params == NULL) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "No memory for pCAL params."); - return; - } - - /* Get pointers to the start of each parameter string. */ - for (i = 0; i < (int)nparams; i++) - { - buf++; /* Skip the null string terminator from previous parameter. */ - - png_debug1(3, "Reading pCAL parameter %d", i); - for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) - /* Empty loop to move past each parameter string */ ; - - /* Make sure we haven't run out of data yet */ - if (buf > endptr) - { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, params); - return; - } - } - - png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, - units, params); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, params); -} -#endif - -#if defined(PNG_READ_sCAL_SUPPORTED) -/* Read the sCAL chunk */ -void /* PRIVATE */ -png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_charp ep; -#ifdef PNG_FLOATING_POINT_SUPPORTED - double width, height; - png_charp vp; -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - png_charp swidth, sheight; -#endif -#endif - png_size_t slength; - - png_debug(1, "in png_handle_sCAL"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sCAL"); - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sCAL after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) - { - png_warning(png_ptr, "Duplicate sCAL chunk"); - png_crc_finish(png_ptr, length); - return; - } - - png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)", - length + 1); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk"); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - - ep = png_ptr->chunkdata + 1; /* Skip unit byte */ - -#ifdef PNG_FLOATING_POINT_SUPPORTED - width = png_strtod(png_ptr, ep, &vp); - if (*vp) - { - png_warning(png_ptr, "malformed width string in sCAL chunk"); - return; - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (swidth == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); - return; - } - png_memcpy(swidth, ep, (png_size_t)png_strlen(ep)); -#endif -#endif - - for (ep = png_ptr->chunkdata; *ep; ep++) - /* Empty loop */ ; - ep++; - - if (png_ptr->chunkdata + slength < ep) - { - png_warning(png_ptr, "Truncated sCAL chunk"); -#if defined(PNG_FIXED_POINT_SUPPORTED) && \ - !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); -#endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - -#ifdef PNG_FLOATING_POINT_SUPPORTED - height = png_strtod(png_ptr, ep, &vp); - if (*vp) - { - png_warning(png_ptr, "malformed height string in sCAL chunk"); - return; - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (sheight == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); - return; - } - png_memcpy(sheight, ep, (png_size_t)png_strlen(ep)); -#endif -#endif - - if (png_ptr->chunkdata + slength < ep -#ifdef PNG_FLOATING_POINT_SUPPORTED - || width <= 0. || height <= 0. -#endif - ) - { - png_warning(png_ptr, "Invalid sCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); - png_free(png_ptr, sheight); -#endif - return; - } - - -#ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight); -#endif -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) - png_free(png_ptr, swidth); - png_free(png_ptr, sheight); -#endif -} -#endif - -#if defined(PNG_READ_tIME_SUPPORTED) -void /* PRIVATE */ -png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_byte buf[7]; - png_time mod_time; - - png_debug(1, "in png_handle_tIME"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Out of place tIME chunk"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) - { - png_warning(png_ptr, "Duplicate tIME chunk"); - png_crc_finish(png_ptr, length); - return; - } - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - - if (length != 7) - { - png_warning(png_ptr, "Incorrect tIME chunk length"); - png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 7); - if (png_crc_finish(png_ptr, 0)) - return; - - mod_time.second = buf[6]; - mod_time.minute = buf[5]; - mod_time.hour = buf[4]; - mod_time.day = buf[3]; - mod_time.month = buf[2]; - mod_time.year = png_get_uint_16(buf); - - png_set_tIME(png_ptr, info_ptr, &mod_time); -} -#endif - -#if defined(PNG_READ_tEXt_SUPPORTED) -/* Note: this does not properly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_textp text_ptr; - png_charp key; - png_charp text; - png_uint_32 skip = 0; - png_size_t slength; - int ret; - - png_debug(1, "in png_handle_tEXt"); - - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tEXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "tEXt chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory to process text chunk."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - key = png_ptr->chunkdata; - - key[slength] = 0x00; - - for (text = key; *text; text++) - /* Empty loop to find end of key */ ; - - if (text != key + slength) - text++; - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process text chunk."); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->key = key; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; -#endif - text_ptr->text = text; - text_ptr->text_length = png_strlen(text); - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, text_ptr); - if (ret) - png_warning(png_ptr, "Insufficient memory to process text chunk."); -} -#endif - -#if defined(PNG_READ_zTXt_SUPPORTED) -/* Note: this does not correctly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_textp text_ptr; - png_charp text; - int comp_type; - int ret; - png_size_t slength, prefix_len, data_len; - - png_debug(1, "in png_handle_zTXt"); - - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before zTXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - there is no hard and fast rule to tell us where to stop. */ - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "zTXt chunk too large to fit in memory"); - png_crc_finish(png_ptr, length); - return; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "Out of memory processing zTXt chunk."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (text = png_ptr->chunkdata; *text; text++) - /* Empty loop */ ; - - /* zTXt must have some text after the chunkdataword */ - if (text >= png_ptr->chunkdata + slength - 2) - { - png_warning(png_ptr, "Truncated zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - else - { - comp_type = *(++text); - if (comp_type != PNG_TEXT_COMPRESSION_zTXt) - { - png_warning(png_ptr, "Unknown compression type in zTXt chunk"); - comp_type = PNG_TEXT_COMPRESSION_zTXt; - } - text++; /* Skip the compression_method byte */ - } - prefix_len = text - png_ptr->chunkdata; - - png_decompress_chunk(png_ptr, comp_type, - (png_size_t)length, prefix_len, &data_len); - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process zTXt chunk."); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = comp_type; - text_ptr->key = png_ptr->chunkdata; -#ifdef PNG_iTXt_SUPPORTED - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; -#endif - text_ptr->text = png_ptr->chunkdata + prefix_len; - text_ptr->text_length = data_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - if (ret) - png_error(png_ptr, "Insufficient memory to store zTXt chunk."); -} -#endif - -#if defined(PNG_READ_iTXt_SUPPORTED) -/* Note: this does not correctly handle chunks that are > 64K under DOS */ -void /* PRIVATE */ -png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_textp text_ptr; - png_charp key, lang, text, lang_key; - int comp_flag; - int comp_type = 0; - int ret; - png_size_t slength, prefix_len, data_len; - - png_debug(1, "in png_handle_iTXt"); - - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iTXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; - -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - there is no hard and fast rule to tell us where to stop. */ - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "iTXt chunk too large to fit in memory"); - png_crc_finish(png_ptr, length); - return; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory to process iTXt chunk."); - return; - } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (lang = png_ptr->chunkdata; *lang; lang++) - /* Empty loop */ ; - lang++; /* Skip NUL separator */ - - /* iTXt must have a language tag (possibly empty), two compression bytes, - * translated keyword (possibly empty), and possibly some text after the - * keyword - */ - - if (lang >= png_ptr->chunkdata + slength - 3) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - else - { - comp_flag = *lang++; - comp_type = *lang++; - } - - for (lang_key = lang; *lang_key; lang_key++) - /* Empty loop */ ; - lang_key++; /* Skip NUL separator */ - - if (lang_key >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - for (text = lang_key; *text; text++) - /* Empty loop */ ; - text++; /* Skip NUL separator */ - if (text >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Malformed iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - prefix_len = text - png_ptr->chunkdata; - - key=png_ptr->chunkdata; - if (comp_flag) - png_decompress_chunk(png_ptr, comp_type, - (size_t)length, prefix_len, &data_len); - else - data_len = png_strlen(png_ptr->chunkdata + prefix_len); - text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process iTXt chunk."); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - text_ptr->compression = (int)comp_flag + 1; - text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); - text_ptr->lang = png_ptr->chunkdata + (lang - key); - text_ptr->itxt_length = data_len; - text_ptr->text_length = 0; - text_ptr->key = png_ptr->chunkdata; - text_ptr->text = png_ptr->chunkdata + prefix_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - if (ret) - png_error(png_ptr, "Insufficient memory to store iTXt chunk."); -} -#endif - -/* This function is called when we haven't found a handler for a - chunk. If there isn't a problem with the chunk itself (ie bad - chunk name, CRC, or a critical chunk), the chunk is silently ignored - -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which - case it will be saved away to be written out later. */ -void /* PRIVATE */ -png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -{ - png_uint_32 skip = 0; - - png_debug(1, "in png_handle_unknown"); - - - if (png_ptr->mode & PNG_HAVE_IDAT) - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ - png_ptr->mode |= PNG_AFTER_IDAT; - } - - if (!(png_ptr->chunk_name[0] & 0x20)) - { -#if defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - } - -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) - || (png_ptr->read_user_chunk_fn != NULL) -#endif - ) - { -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "unknown chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - png_memcpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof(png_ptr->unknown_chunk.name)); - png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] = '\0'; - png_ptr->unknown_chunk.size = (png_size_t)length; - if (length == 0) - png_ptr->unknown_chunk.data = NULL; - else - { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); - } -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) - if (png_ptr->read_user_chunk_fn != NULL) - { - /* Callback to user unknown chunk handler */ - int ret; - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - if (ret == 0) - { - if (!(png_ptr->chunk_name[0] & 0x20)) -#if defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - } - } - else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - else -#endif - skip = length; - - png_crc_finish(png_ptr, skip); - -#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED) - info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ -#endif -} - -/* This function is called to verify that a chunk name is valid. - This function can't have the "critical chunk check" incorporated - into it, since in the future we will need to be able to call user - functions to handle unknown critical chunks after we check that - the chunk name itself is valid. */ - -#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) - -void /* PRIVATE */ -png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) -{ - png_debug(1, "in png_check_chunk_name"); - if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || - isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) - { - png_chunk_error(png_ptr, "invalid chunk type"); - } -} - -/* Combines the row recently read in with the existing pixels in the - row. This routine takes care of alpha and transparency if requested. - This routine also handles the two methods of progressive display - of interlaced images, depending on the mask value. - The mask value describes which pixels are to be combined with - the row. The pattern always repeats every 8 pixels, so just 8 - bits are needed. A one indicates the pixel is to be combined, - a zero indicates the pixel is to be skipped. This is in addition - to any alpha or transparency value associated with the pixel. If - you want all pixels to be combined, pass 0xff (255) in mask. */ - -void /* PRIVATE */ -png_combine_row(png_structp png_ptr, png_bytep row, int mask) -{ - png_debug(1, "in png_combine_row"); - if (mask == 0xff) - { - png_memcpy(row, png_ptr->row_buf + 1, - PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); - } - else - { - switch (png_ptr->row_info.pixel_depth) - { - case 1: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_inc, s_start, s_end; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 7; - s_inc = 1; - } - else -#endif - { - s_start = 7; - s_end = 0; - s_inc = -1; - } - - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - int value; - - value = (*sp >> shift) & 0x01; - *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - else - shift += s_inc; - - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - case 2: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_start, s_end, s_inc; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - int value; - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 6; - s_inc = 2; - } - else -#endif - { - s_start = 6; - s_end = 0; - s_inc = -2; - } - - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - value = (*sp >> shift) & 0x03; - *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - else - shift += s_inc; - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - case 4: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_start, s_end, s_inc; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - int value; - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 4; - s_inc = 4; - } - else -#endif - { - s_start = 4; - s_end = 0; - s_inc = -4; - } - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - value = (*sp >> shift) & 0xf; - *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - else - shift += s_inc; - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - default: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - png_byte m = 0x80; - - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - png_memcpy(dp, sp, pixel_bytes); - } - - sp += pixel_bytes; - dp += pixel_bytes; - - if (m == 1) - m = 0x80; - else - m >>= 1; - } - break; - } - } - } -} - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* OLD pre-1.0.9 interface: -void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, - png_uint_32 transformations) - */ -void /* PRIVATE */ -png_do_read_interlace(png_structp png_ptr) -{ - png_row_infop row_info = &(png_ptr->row_info); - png_bytep row = png_ptr->row_buf + 1; - int pass = png_ptr->pass; - png_uint_32 transformations = png_ptr->transformations; -#ifdef PNG_USE_LOCAL_ARRAYS - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; -#endif - - png_debug(1, "in png_do_read_interlace"); - if (row != NULL && row_info != NULL) - { - png_uint_32 final_width; - - final_width = row_info->width * png_pass_inc[pass]; - - switch (row_info->pixel_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); - png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); - int sshift, dshift; - int s_start, s_end, s_inc; - int jstop = png_pass_inc[pass]; - png_byte v; - png_uint_32 i; - int j; - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (transformations & PNG_PACKSWAP) - { - sshift = (int)((row_info->width + 7) & 0x07); - dshift = (int)((final_width + 7) & 0x07); - s_start = 7; - s_end = 0; - s_inc = -1; - } - else -#endif - { - sshift = 7 - (int)((row_info->width + 7) & 0x07); - dshift = 7 - (int)((final_width + 7) & 0x07); - s_start = 0; - s_end = 7; - s_inc = 1; - } - - for (i = 0; i < row_info->width; i++) - { - v = (png_byte)((*sp >> sshift) & 0x01); - for (j = 0; j < jstop; j++) - { - *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - else - dshift += s_inc; - } - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - else - sshift += s_inc; - } - break; - } - case 2: - { - png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); - png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); - int sshift, dshift; - int s_start, s_end, s_inc; - int jstop = png_pass_inc[pass]; - png_uint_32 i; - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (transformations & PNG_PACKSWAP) - { - sshift = (int)(((row_info->width + 3) & 0x03) << 1); - dshift = (int)(((final_width + 3) & 0x03) << 1); - s_start = 6; - s_end = 0; - s_inc = -2; - } - else -#endif - { - sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); - dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); - s_start = 0; - s_end = 6; - s_inc = 2; - } - - for (i = 0; i < row_info->width; i++) - { - png_byte v; - int j; - - v = (png_byte)((*sp >> sshift) & 0x03); - for (j = 0; j < jstop; j++) - { - *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - else - dshift += s_inc; - } - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - else - sshift += s_inc; - } - break; - } - case 4: - { - png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); - png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); - int sshift, dshift; - int s_start, s_end, s_inc; - png_uint_32 i; - int jstop = png_pass_inc[pass]; - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) - if (transformations & PNG_PACKSWAP) - { - sshift = (int)(((row_info->width + 1) & 0x01) << 2); - dshift = (int)(((final_width + 1) & 0x01) << 2); - s_start = 4; - s_end = 0; - s_inc = -4; - } - else -#endif - { - sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); - dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); - s_start = 0; - s_end = 4; - s_inc = 4; - } - - for (i = 0; i < row_info->width; i++) - { - png_byte v = (png_byte)((*sp >> sshift) & 0xf); - int j; - - for (j = 0; j < jstop; j++) - { - *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); - if (dshift == s_end) - { - dshift = s_start; - dp--; - } - else - dshift += s_inc; - } - if (sshift == s_end) - { - sshift = s_start; - sp--; - } - else - sshift += s_inc; - } - break; - } - default: - { - png_size_t pixel_bytes = (row_info->pixel_depth >> 3); - png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes; - png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; - - int jstop = png_pass_inc[pass]; - png_uint_32 i; - - for (i = 0; i < row_info->width; i++) - { - png_byte v[8]; - int j; - - png_memcpy(v, sp, pixel_bytes); - for (j = 0; j < jstop; j++) - { - png_memcpy(dp, v, pixel_bytes); - dp -= pixel_bytes; - } - sp -= pixel_bytes; - } - break; - } - } - row_info->width = final_width; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); - } -#if !defined(PNG_READ_PACKSWAP_SUPPORTED) - transformations = transformations; /* Silence compiler warning */ -#endif -} -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - -void /* PRIVATE */ -png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, - png_bytep prev_row, int filter) -{ - png_debug(1, "in png_read_filter_row"); - png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter); - switch (filter) - { - case PNG_FILTER_VALUE_NONE: - break; - case PNG_FILTER_VALUE_SUB: - { - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; - png_bytep rp = row + bpp; - png_bytep lp = row; - - for (i = bpp; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_UP: - { - png_uint_32 i; - png_uint_32 istop = row_info->rowbytes; - png_bytep rp = row; - png_bytep pp = prev_row; - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_AVG: - { - png_uint_32 i; - png_bytep rp = row; - png_bytep pp = prev_row; - png_bytep lp = row; - png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; - png_uint_32 istop = row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + - ((int)(*pp++) / 2 )) & 0xff); - rp++; - } - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + - (int)(*pp++ + *lp++) / 2 ) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_PAETH: - { - png_uint_32 i; - png_bytep rp = row; - png_bytep pp = prev_row; - png_bytep lp = row; - png_bytep cp = prev_row; - png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; - png_uint_32 istop=row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } - - for (i = 0; i < istop; i++) /* Use leftover rp,pp */ - { - int a, b, c, pa, pb, pc, p; - - a = *lp++; - b = *pp++; - c = *cp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - /* - if (pa <= pb && pa <= pc) - p = a; - else if (pb <= pc) - p = b; - else - p = c; - */ - - p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; - - *rp = (png_byte)(((int)(*rp) + p) & 0xff); - rp++; - } - break; - } - default: - png_warning(png_ptr, "Ignoring bad adaptive filter type"); - *row = 0; - break; - } -} - -#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED -void /* PRIVATE */ -png_read_finish_row(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -#endif - - png_debug(1, "in png_read_finish_row"); - png_ptr->row_number++; - if (png_ptr->row_number < png_ptr->num_rows) - return; - -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - png_ptr->row_number = 0; - png_memset_check(png_ptr, png_ptr->prev_row, 0, - png_ptr->rowbytes + 1); - do - { - png_ptr->pass++; - if (png_ptr->pass >= 7) - break; - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; - - if (!(png_ptr->transformations & PNG_INTERLACE)) - { - png_ptr->num_rows = (png_ptr->height + - png_pass_yinc[png_ptr->pass] - 1 - - png_pass_ystart[png_ptr->pass]) / - png_pass_yinc[png_ptr->pass]; - if (!(png_ptr->num_rows)) - continue; - } - else /* if (png_ptr->transformations & PNG_INTERLACE) */ - break; - } while (png_ptr->iwidth == 0); - - if (png_ptr->pass < 7) - return; - } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif - char extra; - int ret; - - png_ptr->zstream.next_out = (Byte *)&extra; - png_ptr->zstream.avail_out = (uInt)1; - for (;;) - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_byte chunk_length[4]; - - png_crc_finish(png_ptr, 0); - - png_read_data(png_ptr, chunk_length, 4); - png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, png_ptr->chunk_name, 4); - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_error(png_ptr, "Not enough image data"); - - } - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret == Z_STREAM_END) - { - if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_warning(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression Error"); - - if (!(png_ptr->zstream.avail_out)) - { - png_warning(png_ptr, "Extra compressed data."); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - } - png_ptr->zstream.avail_out = 0; - } - - if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_warning(png_ptr, "Extra compression data"); - - inflateReset(&png_ptr->zstream); - - png_ptr->mode |= PNG_AFTER_IDAT; -} -#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ - -void /* PRIVATE */ -png_read_start_row(png_structp png_ptr) -{ -#ifdef PNG_USE_LOCAL_ARRAYS -#ifdef PNG_READ_INTERLACING_SUPPORTED - /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - - /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - - /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - - /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - - /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif -#endif - - int max_pixel_depth; - png_size_t row_bytes; - - png_debug(1, "in png_read_start_row"); - png_ptr->zstream.avail_in = 0; - png_init_read_transformations(png_ptr); -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) - { - if (!(png_ptr->transformations & PNG_INTERLACE)) - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - - png_pass_ystart[0]) / png_pass_yinc[0]; - else - png_ptr->num_rows = png_ptr->height; - - png_ptr->iwidth = (png_ptr->width + - png_pass_inc[png_ptr->pass] - 1 - - png_pass_start[png_ptr->pass]) / - png_pass_inc[png_ptr->pass]; - - png_ptr->irowbytes = - PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1; - } - else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - { - png_ptr->num_rows = png_ptr->height; - png_ptr->iwidth = png_ptr->width; - png_ptr->irowbytes = png_ptr->rowbytes + 1; - } - max_pixel_depth = png_ptr->pixel_depth; - -#if defined(PNG_READ_PACK_SUPPORTED) - if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) - max_pixel_depth = 8; -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if (png_ptr->num_trans) - max_pixel_depth = 32; - else - max_pixel_depth = 24; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - if (max_pixel_depth < 8) - max_pixel_depth = 8; - if (png_ptr->num_trans) - max_pixel_depth *= 2; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - if (png_ptr->num_trans) - { - max_pixel_depth *= 4; - max_pixel_depth /= 3; - } - } - } -#endif - -#if defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & (PNG_FILLER)) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - max_pixel_depth = 32; - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) - { - if (max_pixel_depth <= 8) - max_pixel_depth = 16; - else - max_pixel_depth = 32; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - if (max_pixel_depth <= 32) - max_pixel_depth = 32; - else - max_pixel_depth = 64; - } - } -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - { - if ( -#if defined(PNG_READ_EXPAND_SUPPORTED) - (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || -#endif -#if defined(PNG_READ_FILLER_SUPPORTED) - (png_ptr->transformations & (PNG_FILLER)) || -#endif - png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - if (max_pixel_depth <= 16) - max_pixel_depth = 32; - else - max_pixel_depth = 64; - } - else - { - if (max_pixel_depth <= 8) - { - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - max_pixel_depth = 32; - else - max_pixel_depth = 24; - } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - max_pixel_depth = 64; - else - max_pixel_depth = 48; - } - } -#endif - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ -defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - int user_pixel_depth = png_ptr->user_transform_depth* - png_ptr->user_transform_channels; - if (user_pixel_depth > max_pixel_depth) - max_pixel_depth=user_pixel_depth; - } -#endif - - /* Align the width on the next larger 8 pixels. Mainly used - * for interlacing - */ - row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); - /* Calculate the maximum bytes needed, adding a byte and a pixel - * for safety's sake - */ - row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + - 1 + ((max_pixel_depth + 7) >> 3); -#ifdef PNG_MAX_MALLOC_64K - if (row_bytes > (png_uint_32)65536L) - png_
      +
    • RandomAccessIterator + qBinaryFind + (RandomAccessIterator begin, RandomAccessIterator end, + const T & value)
    • +
    • ...