From fcf4b598a169b336344393958f67320f5f9652ce Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 28 Sep 2010 11:01:20 +0100 Subject: Progressive download in Phonon MMF backend: added download managers This patch adds a Download class which uses the RHttpDownloadMgr API to download a media clip over HTTP. Task-number: QTBUG-10769 Reviewed-by: Derick Hawcroft --- src/3rdparty/phonon/mmf/download.cpp | 194 +++++++++++++++++++++++++++++++++++ src/3rdparty/phonon/mmf/download.h | 111 ++++++++++++++++++++ src/plugins/phonon/mmf/mmf.pro | 3 + 3 files changed, 308 insertions(+) create mode 100644 src/3rdparty/phonon/mmf/download.cpp create mode 100644 src/3rdparty/phonon/mmf/download.h diff --git a/src/3rdparty/phonon/mmf/download.cpp b/src/3rdparty/phonon/mmf/download.cpp new file mode 100644 index 0000000..7b80e4a --- /dev/null +++ b/src/3rdparty/phonon/mmf/download.cpp @@ -0,0 +1,194 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see . + +*/ + +#include "download.h" +#include "utils.h" +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +static const TBool InheritDownloads = EFalse; + +DownloadPrivate::DownloadPrivate(Download *parent) + : QObject(parent) + , m_parent(parent) + , m_download(0) + , m_length(0) +{ + +} + +DownloadPrivate::~DownloadPrivate() +{ + m_downloadManager.Disconnect(); + m_downloadManager.Close(); +} + +bool DownloadPrivate::start() +{ + TRACE_CONTEXT(DownloadPrivate::start, EVideoApi); + Q_ASSERT(!m_download); + // Connect to download manager + RProcess process; + const TUid uid3 = process.SecureId(); + TRAPD(err, m_downloadManager.ConnectL(uid3, *this, InheritDownloads)); + TRACE("connect err %d", err); + if (KErrNone == err) { + // Start download + QHBufC url(m_parent->sourceUrl().toString()); + TPtr8 url8 = url->Des().Collapse(); + TRAP(err, m_download = &m_downloadManager.CreateDownloadL(url8)); + TRACE("start err %d", err); + if (KErrNone == err) + m_download->Start(); + } + return (KErrNone == err); +} + +void DownloadPrivate::resume() +{ + +} + +void DownloadPrivate::HandleDMgrEventL(RHttpDownload &aDownload, THttpDownloadEvent aEvent) +{ + TRACE_CONTEXT(DownloadPrivate::HandleDMgrEventL, EVideoApi); + Q_ASSERT(&aDownload == m_download); + switch (aEvent.iDownloadState) { + case EHttpDlPaused: + if (EHttpContentTypeReceived == aEvent.iProgressState) { + TRACE_0("paused, content type received"); + m_download->Start(); + } + break; + case EHttpDlInprogress: + switch (aEvent.iProgressState) { + case EHttpProgResponseHeaderReceived: + { + TFileName fileName; + m_download->GetStringAttribute(EDlAttrDestFilename, fileName); + TRACE("in progress, response header received, filename %S", &fileName); + const QString fileNameQt = QDir::fromNativeSeparators(qt_TDesC2QString(fileName)); + m_parent->downloadStarted(fileNameQt); + } + break; + case EHttpProgResponseBodyReceived: + { + TInt32 length = 0; + m_download->GetIntAttribute(EDlAttrDownloadedSize, length); + if (length != m_length) { + TRACE("in progress, length %d", length); + m_length = length; + emit lengthChanged(m_length); + } + } + break; + } + break; + case EHttpDlCompleted: + TRACE_0("complete"); + m_parent->complete(); + break; + case EHttpDlFailed: + TRACE_0("failed"); + m_parent->error(); + break; + } +} + +Download::Download(const QUrl &url, QObject *parent) + : QObject(parent) + , m_private(new DownloadPrivate(this)) + , m_sourceUrl(url) + , m_state(Idle) +{ + qRegisterMetaType(); + connect(m_private, SIGNAL(lengthChanged(qint64)), this, SIGNAL(lengthChanged(qint64))); +} + +Download::~Download() +{ + +} + +const QUrl &Download::sourceUrl() const +{ + return m_sourceUrl; +} + +const QString &Download::targetFileName() const +{ + return m_targetFileName; +} + +void Download::start() +{ + TRACE_CONTEXT(Download::start, EVideoApi); + TRACE_ENTRY_0(); + Q_ASSERT(Idle == m_state); + const bool ok = m_private->start(); + setState(ok ? Initializing : Error); + TRACE_EXIT_0(); +} + +void Download::resume() +{ + TRACE_CONTEXT(Download::resume, EVideoApi); + TRACE_ENTRY_0(); + m_private->resume(); + TRACE_EXIT_0(); +} + +void Download::setState(State state) +{ + TRACE_CONTEXT(Download::setState, EVideoApi); + TRACE("oldState %d newState %d", m_state, state); + const State oldState = m_state; + m_state = state; + if (oldState != m_state) + emit stateChanged(m_state); +} + +void Download::error() +{ + TRACE_CONTEXT(Download::error, EVideoApi); + TRACE_0(""); + setState(Error); +} + +void Download::downloadStarted(const QString &targetFileName) +{ + TRACE_CONTEXT(Download::downloadStarted, EVideoApi); + TRACE_0("downloadStarted"); + m_targetFileName = targetFileName; + setState(Downloading); +} + +void Download::complete() +{ + TRACE_CONTEXT(Download::complete, EVideoApi); + TRACE_0(""); + setState(Complete); +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/download.h b/src/3rdparty/phonon/mmf/download.h new file mode 100644 index 0000000..b57348b --- /dev/null +++ b/src/3rdparty/phonon/mmf/download.h @@ -0,0 +1,111 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see . + +*/ + +#ifndef PHONON_MMF_DOWNLOAD_H +#define PHONON_MMF_DOWNLOAD_H + +#include +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QByteArray) +QT_FORWARD_DECLARE_CLASS(QFile) + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ + +class Download; + +class DownloadPrivate : public QObject + , public MHttpDownloadMgrObserver +{ + Q_OBJECT +public: + DownloadPrivate(Download *parent); + ~DownloadPrivate(); + bool start(); + void resume(); +signals: + void error(); + void targetFileNameChanged(); + void lengthChanged(qint64 length); + void complete(); +private: + // MHttpDownloadMgrObserver + void HandleDMgrEventL(RHttpDownload &aDownload, THttpDownloadEvent aEvent); +private: + Download *m_parent; + RHttpDownloadMgr m_downloadManager; + RHttpDownload *m_download; + qint64 m_length; +}; + +class Download : public QObject +{ + Q_OBJECT + friend class DownloadPrivate; +public: + Download(const QUrl &url, QObject *parent = 0); + ~Download(); + const QUrl &sourceUrl() const; + const QString &targetFileName() const; + void start(); + + // Only has effect when QT_PHONON_MMF_DOWNLOAD_DUMMY is defined + void resume(); + + enum State { + Idle, + Initializing, + Downloading, + Complete, + Error + }; + +signals: + void lengthChanged(qint64 length); + void stateChanged(Download::State state); + +private: + void setState(State state); + + // Called by DownloadPrivate + void error(); + void downloadStarted(const QString &targetFileName); + void complete(); + +private: + DownloadPrivate *m_private; + QUrl m_sourceUrl; + QString m_targetFileName; + State m_state; +}; + +} +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Phonon::MMF::Download::State) + +#endif diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index 7a6fdf8..902354f 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -36,6 +36,7 @@ symbian { $$PHONON_MMF_DIR/backend.h \ $$PHONON_MMF_DIR/bassboost.h \ $$PHONON_MMF_DIR/defs.h \ + $$PHONON_MMF_DIR/download.h \ $$PHONON_MMF_DIR/dummyplayer.h \ $$PHONON_MMF_DIR/effectfactory.h \ $$PHONON_MMF_DIR/effectparameter.h \ @@ -61,6 +62,7 @@ symbian { $$PHONON_MMF_DIR/abstractvideoplayer.cpp \ $$PHONON_MMF_DIR/backend.cpp \ $$PHONON_MMF_DIR/bassboost.cpp \ + $$PHONON_MMF_DIR/download.cpp \ $$PHONON_MMF_DIR/dummyplayer.cpp \ $$PHONON_MMF_DIR/effectfactory.cpp \ $$PHONON_MMF_DIR/effectparameter.cpp \ @@ -111,6 +113,7 @@ symbian { LIBS += -lapgrfx -lapmime # For recognizer LIBS += -lmmfcontrollerframework # For CMMFMetaDataEntry LIBS += -lmediaclientaudiostream # For CMdaAudioOutputStream + LIBS += -ldownloadmgr # These are for effects. LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerBase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect -- cgit v0.12 From bb994a5e2a260911ed3c5603d3414c63a28faab4 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 28 Sep 2010 11:05:41 +0100 Subject: Progressive download in Phonon MMF backend: integrated with player This commit integrates the Download class with the media playback classes in the backend, to implement Progressive Download. Note that this PDL implementation has one drawback: when video playback is paused due to shortage of data (i.e. due to the download being temporarily stalled), the display goes black. This is because, when the end of the currently-downloaded data is reached, the playback session is closed. When more data becomes available, the clip is re-opened, a seek is done to reach the previous playback position, and playback is re-started. Closing the playback session closes the video stack's connection to the display, thereby causing the video widget to go black while more data is buffered. This is a consequence of the level in the native video stack at which the Phonon integration is done: managing a network stall without requiring the playback session to be closed would require integration below the MMF client API, specifically at the MMF controller level. Task-number: QTBUG-10769 Reviewed-by: Derick Hawcroft --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 148 +++++++++++++++++++++--- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 17 +++ src/3rdparty/phonon/mmf/abstractvideoplayer.cpp | 24 +++- src/3rdparty/phonon/mmf/abstractvideoplayer.h | 5 +- src/3rdparty/phonon/mmf/audioplayer.cpp | 18 ++- src/3rdparty/phonon/mmf/audioplayer.h | 5 +- src/3rdparty/phonon/mmf/mediaobject.cpp | 36 +++--- src/3rdparty/phonon/mmf/mediaobject.h | 1 + 8 files changed, 211 insertions(+), 43 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 3702560..a728423 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -51,10 +51,13 @@ MMF::AbstractMediaPlayer::AbstractMediaPlayer , m_parent(parent) , m_pending(NothingPending) , m_positionTimer(new QTimer(this)) + , m_position(0) , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) , m_prefinishMarkSent(false) , m_aboutToFinishSent(false) + , m_download(0) + , m_downloadStalled(false) { connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); @@ -183,6 +186,7 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) } doSeek(ms); + m_position = ms; resetMarksIfRewound(); if(wasPlaying && state() != ErrorState) { @@ -207,6 +211,11 @@ bool MMF::AbstractMediaPlayer::isSeekable() const return true; } +qint64 MMF::AbstractMediaPlayer::currentTime() const +{ + return m_position; +} + void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) { TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi); @@ -247,6 +256,14 @@ void MMF::AbstractMediaPlayer::open() symbianErr = openFile(*file); if (KErrNone != symbianErr) errorMessage = tr("Error opening file"); + } else if (url.scheme() == QLatin1String("http")) { + Q_ASSERT(!m_download); + m_download = new Download(url, this); + connect(m_download, SIGNAL(lengthChanged(qint64)), + this, SLOT(downloadLengthChanged(qint64))); + connect(m_download, SIGNAL(stateChanged(Download::State)), + this, SLOT(downloadStateChanged(Download::State))); + m_download->start(); } else { symbianErr = openUrl(url.toString()); if (KErrNone != symbianErr) @@ -288,6 +305,14 @@ void MMF::AbstractMediaPlayer::open() TRACE_EXIT_0(); } +void MMF::AbstractMediaPlayer::close() +{ + doClose(); + delete m_download; + m_download = 0; + m_position = 0; +} + void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) { TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal); @@ -374,7 +399,8 @@ void MMF::AbstractMediaPlayer::bufferingComplete() { stopBufferStatusTimer(); emit MMF::AbstractPlayer::bufferStatus(100); - changeState(m_stateBeforeBuffering); + if (!progressiveDownloadStalled()) + changeState(m_stateBeforeBuffering); } void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) @@ -385,13 +411,28 @@ void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) void MMF::AbstractMediaPlayer::loadingComplete(int error) { - Q_ASSERT(Phonon::LoadingState == state()); - - if (KErrNone == error) { - updateMetaData(); - changeState(StoppedState); + TRACE_CONTEXT(AbstractMediaPlayer::loadingComplete, EAudioApi); + TRACE_ENTRY("state %d error %d", state(), error); + if (progressiveDownloadStalled()) { + Q_ASSERT(Phonon::BufferingState == state()); + if (KErrNone == error) { + bufferingComplete(); + doSeek(m_position); + startPlayback(); + m_downloadStalled = false; + } } else { - setError(tr("Loading clip failed"), error); + Q_ASSERT(Phonon::LoadingState == state()); + if (KErrNone == error) { + updateMetaData(); + changeState(StoppedState); + } else { + if (isProgressiveDownload() && KErrCorrupt == error) { + setProgressiveDownloadStalled(); + } else { + setError(tr("Loading clip failed"), error); + } + } } } @@ -415,8 +456,12 @@ void MMF::AbstractMediaPlayer::playbackComplete(int error) QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection); } else { - setError(tr("Playback complete"), error); - emit finished(); + if (isProgressiveDownload() && KErrCorrupt == error) { + setProgressiveDownloadStalled(); + } else { + setError(tr("Playback complete"), error); + emit finished(); + } } } @@ -425,15 +470,28 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds return in.Int64() / 1000; } +bool MMF::AbstractMediaPlayer::isProgressiveDownload() const +{ + return (0 != m_download); +} + +bool MMF::AbstractMediaPlayer::progressiveDownloadStalled() const +{ + return m_downloadStalled; +} + //----------------------------------------------------------------------------- // Slots //----------------------------------------------------------------------------- void MMF::AbstractMediaPlayer::positionTick() { - const qint64 current = currentTime(); - emitMarksIfReached(current); - emit MMF::AbstractPlayer::tick(current); + const qint64 pos = getCurrentTime(); + if (pos > m_position) { + m_position = pos; + emitMarksIfReached(m_position); + emit MMF::AbstractPlayer::tick(m_position); + } } void MMF::AbstractMediaPlayer::emitMarksIfReached(qint64 current) @@ -458,7 +516,7 @@ void MMF::AbstractMediaPlayer::emitMarksIfReached(qint64 current) void MMF::AbstractMediaPlayer::resetMarksIfRewound() { - const qint64 current = currentTime(); + const qint64 current = getCurrentTime(); const qint64 total = totalTime(); const qint64 remaining = total - current; @@ -487,9 +545,71 @@ void MMF::AbstractMediaPlayer::startPlayback() changeState(PlayingState); } +void MMF::AbstractMediaPlayer::setProgressiveDownloadStalled() +{ + TRACE_CONTEXT(AbstractMediaPlayer::setProgressiveDownloadStalled, EAudioApi); + TRACE_ENTRY("state %d", state()); + Q_ASSERT(isProgressiveDownload()); + m_downloadStalled = true; + doClose(); + bufferingStarted(); + // Video player loses window handle when closed - need to reapply it here + videoOutputChanged(); +#ifdef QT_PHONON_MMF_DOWNLOAD_DUMMY + m_download->resume(); +#endif +} + void MMF::AbstractMediaPlayer::bufferStatusTick() { - emit MMF::AbstractPlayer::bufferStatus(bufferStatus()); + // During progressive download, there is no way to detect the buffering status. + // Phonon does not support a "buffering; amount unknown" signal, therefore we + // return a buffering status of zero. + const int status = progressiveDownloadStalled() ? 0 : bufferStatus(); + emit MMF::AbstractPlayer::bufferStatus(status); +} + +void MMF::AbstractMediaPlayer::downloadLengthChanged(qint64 length) +{ + TRACE_CONTEXT(AbstractMediaPlayer::downloadLengthChanged, EAudioApi); + TRACE_ENTRY("length %Ld", length); + Q_UNUSED(length) + if (m_downloadStalled) { + bufferingComplete(); + int err = m_parent->openFileHandle(m_download->targetFileName()); + if (KErrNone == err) + err = openFile(*m_parent->file()); + if (KErrNone != err) + setError(tr("Error opening file")); + } +} + +void MMF::AbstractMediaPlayer::downloadStateChanged(Download::State state) +{ + TRACE_CONTEXT(AbstractMediaPlayer::downloadStateChanged, EAudioApi); + TRACE_ENTRY("state %d", state); + switch (state) { + case Download::Idle: + case Download::Initializing: + break; + case Download::Downloading: + { + int err = m_parent->openFileHandle(m_download->targetFileName()); + if (KErrNone == err) + err = openFile(*m_parent->file()); + else if (KErrCorrupt == err) + // Insufficient data downloaded - enter Buffering state + setProgressiveDownloadStalled(); + if (KErrNone != err) + setError(tr("Error opening file")); + } + break; + case Download::Complete: + break; + case Download::Error: + setError(tr("Download error")); + break; + } } Phonon::State MMF::AbstractMediaPlayer::phononState(PrivateState state) const diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index e795ecb..99fc101 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -23,6 +23,7 @@ along with this library. If not, see . #include #include #include "abstractplayer.h" +#include "download.h" class RFile; @@ -48,6 +49,7 @@ protected: public: virtual void open(); + virtual void close(); // MediaObjectInterface virtual void play(); @@ -55,6 +57,7 @@ public: virtual void stop(); virtual void seek(qint64 milliseconds); virtual bool isSeekable() const; + virtual qint64 currentTime() const; virtual void volumeChanged(qreal volume); protected: @@ -68,12 +71,15 @@ protected: virtual void doStop() = 0; virtual void doSeek(qint64 pos) = 0; virtual int setDeviceVolume(int mmfVolume) = 0; + virtual int openFile(const QString &fileName) = 0; virtual int openFile(RFile& file) = 0; virtual int openUrl(const QString& url) = 0; virtual int openDescriptor(const TDesC8 &des) = 0; virtual int bufferStatus() const = 0; + virtual void doClose() = 0; void updateMetaData(); + virtual qint64 getCurrentTime() const = 0; virtual int numberOfMetaDataEntries() const = 0; virtual QPair metaDataEntry(int index) const = 0; @@ -86,6 +92,9 @@ protected: static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); + bool isProgressiveDownload() const; + bool progressiveDownloadStalled() const; + private: void startPositionTimer(); void stopPositionTimer(); @@ -96,6 +105,7 @@ private: void emitMarksIfReached(qint64 position); void resetMarksIfRewound(); void startPlayback(); + void setProgressiveDownloadStalled(); enum Pending { NothingPending, @@ -108,6 +118,8 @@ private: private Q_SLOTS: void positionTick(); void bufferStatusTick(); + void downloadLengthChanged(qint64); + void downloadStateChanged(Download::State); private: MediaObject *const m_parent; @@ -115,6 +127,7 @@ private: Pending m_pending; QScopedPointer m_positionTimer; + qint64 m_position; QScopedPointer m_bufferStatusTimer; PrivateState m_stateBeforeBuffering; @@ -127,6 +140,10 @@ private: // Used for playback of resource files TPtrC8 m_buffer; + // Used for progressive download + Download *m_download; + bool m_downloadStalled; + QMultiMap m_metaData; }; diff --git a/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp index fb20bea..1ab5bae 100644 --- a/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp @@ -16,6 +16,7 @@ along with this library. If not, see . */ +#include #include #include #include @@ -132,6 +133,13 @@ int MMF::AbstractVideoPlayer::setDeviceVolume(int mmfVolume) return err; } +int MMF::AbstractVideoPlayer::openFile(const QString &fileName) +{ + const QHBufC nativeFileName(QDir::toNativeSeparators(fileName)); + TRAPD(err, m_player->OpenFileL(*nativeFileName)); + return err; +} + int MMF::AbstractVideoPlayer::openFile(RFile &file) { TRAPD(err, m_player->OpenFileL(file)); @@ -157,7 +165,7 @@ int MMF::AbstractVideoPlayer::bufferStatus() const return result; } -void MMF::AbstractVideoPlayer::close() +void MMF::AbstractVideoPlayer::doClose() { m_player->Close(); } @@ -167,9 +175,9 @@ bool MMF::AbstractVideoPlayer::hasVideo() const return true; } -qint64 MMF::AbstractVideoPlayer::currentTime() const +qint64 MMF::AbstractVideoPlayer::getCurrentTime() const { - TRACE_CONTEXT(AbstractVideoPlayer::currentTime, EVideoApi); + TRACE_CONTEXT(AbstractVideoPlayer::getCurrentTime, EVideoApi); TTimeIntervalMicroSeconds us; TRAPD(err, us = m_player->PositionL()) @@ -246,7 +254,9 @@ void MMF::AbstractVideoPlayer::MvpuoOpenComplete(TInt aError) TRACE_CONTEXT(AbstractVideoPlayer::MvpuoOpenComplete, EVideoApi); TRACE_ENTRY("state %d error %d", state(), aError); - __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic)); + __ASSERT_ALWAYS(LoadingState == state() || + progressiveDownloadStalled() && BufferingState == state(), + Utils::panic(InvalidStatePanic)); if (KErrNone == aError) m_player->Prepare(); @@ -261,7 +271,9 @@ void MMF::AbstractVideoPlayer::MvpuoPrepareComplete(TInt aError) TRACE_CONTEXT(AbstractVideoPlayer::MvpuoPrepareComplete, EVideoApi); TRACE_ENTRY("state %d error %d", state(), aError); - __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic)); + __ASSERT_ALWAYS(LoadingState == state() || + progressiveDownloadStalled() && BufferingState == state(), + Utils::panic(InvalidStatePanic)); TRAPD(err, getVideoClipParametersL(aError)); @@ -470,7 +482,7 @@ void MMF::AbstractVideoPlayer::updateScaleFactors(const QSize &windowSize, bool void MMF::AbstractVideoPlayer::parametersChanged(VideoParameters parameters) { - if (state() == LoadingState) + if (state() == LoadingState || progressiveDownloadStalled() && BufferingState == state()) m_pendingChanges |= parameters; else handleParametersChanged(parameters); diff --git a/src/3rdparty/phonon/mmf/abstractvideoplayer.h b/src/3rdparty/phonon/mmf/abstractvideoplayer.h index 3ff3c75..3bc5c7c 100644 --- a/src/3rdparty/phonon/mmf/abstractvideoplayer.h +++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.h @@ -64,21 +64,22 @@ public: virtual void doStop(); virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); + virtual int openFile(const QString &fileName); virtual int openFile(RFile &file); virtual int openUrl(const QString &url); virtual int openDescriptor(const TDesC8 &des); virtual int bufferStatus() const; - virtual void close(); + virtual void doClose(); // MediaObjectInterface virtual bool hasVideo() const; - virtual qint64 currentTime() const; virtual qint64 totalTime() const; // AbstractPlayer virtual void videoOutputChanged(); // AbstractMediaPlayer + virtual qint64 getCurrentTime() const; virtual int numberOfMetaDataEntries() const; virtual QPair metaDataEntry(int index) const; diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 7c8b9bd..dc5c800 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -16,6 +16,7 @@ along with this library. If not, see . */ +#include #include #include "audioplayer.h" @@ -109,6 +110,13 @@ int MMF::AudioPlayer::setDeviceVolume(int mmfVolume) #endif } +int MMF::AudioPlayer::openFile(const QString &fileName) +{ + const QHBufC nativeFileName(QDir::toNativeSeparators(fileName)); + TRAPD(err, m_player->OpenFileL(*nativeFileName)); + return err; +} + int MMF::AudioPlayer::openFile(RFile& file) { TRAPD(err, m_player->OpenFileL(file)); @@ -150,7 +158,7 @@ int MMF::AudioPlayer::bufferStatus() const return result; } -void MMF::AudioPlayer::close() +void MMF::AudioPlayer::doClose() { m_player->Close(); } @@ -160,9 +168,9 @@ bool MMF::AudioPlayer::hasVideo() const return false; } -qint64 MMF::AudioPlayer::currentTime() const +qint64 MMF::AudioPlayer::getCurrentTime() const { - TRACE_CONTEXT(AudioPlayer::currentTime, EAudioApi); + TRACE_CONTEXT(AudioPlayer::getCurrentTime, EAudioApi); TTimeIntervalMicroSeconds us; const TInt err = m_player->GetPosition(us); @@ -203,7 +211,9 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError, TRACE_CONTEXT(AudioPlayer::MapcInitComplete, EAudioInternal); TRACE_ENTRY("state %d error %d", state(), aError); - __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic)); + __ASSERT_ALWAYS(LoadingState == state() || + progressiveDownloadStalled() && BufferingState == state(), + Utils::panic(InvalidStatePanic)); if (KErrNone == aError) { maxVolumeChanged(m_player->MaxVolume()); diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index e43cadd..cf4f6d5 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -65,18 +65,19 @@ typedef CMdaAudioPlayerUtility NativePlayer; virtual void doStop(); virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); + virtual int openFile(const QString &fileName); virtual int openFile(RFile& file); virtual int openUrl(const QString& url); virtual int openDescriptor(const TDesC8 &des); virtual int bufferStatus() const; - virtual void close(); + virtual void doClose(); // MediaObjectInterface virtual bool hasVideo() const; - virtual qint64 currentTime() const; virtual qint64 totalTime() const; // AbstractMediaPlayer + virtual qint64 getCurrentTime() const; virtual int numberOfMetaDataEntries() const; virtual QPair metaDataEntry(int index) const; diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 98326b8..2c7a7ef 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -61,6 +61,9 @@ MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(paren TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi); TRACE_ENTRY_0(); + const int err = m_fileServer.Connect(); + QT_TRAP_THROWING(User::LeaveIfError(err)); + Q_UNUSED(parent); TRACE_EXIT_0(); @@ -99,12 +102,6 @@ bool MMF::MediaObject::openRecognizer() return false; } - err = m_fileServer.Connect(); - if (KErrNone != err) { - TRACE("RFs::Connect error %d", err); - return false; - } - // This must be called in order to be able to share file handles with // the recognizer server (see fileMediaType function). err = m_fileServer.ShareProtected(); @@ -127,13 +124,8 @@ MMF::MediaType MMF::MediaObject::fileMediaType MediaType result = MediaTypeUnknown; if (openRecognizer()) { - - const QHBufC fileNameSymbian(QDir::toNativeSeparators(fileName)); - - Q_ASSERT(!m_file); - m_file = new RFile; - TInt err = m_file->Open(m_fileServer, *fileNameSymbian, EFileRead | EFileShareReadersOnly); - + TInt err = openFileHandle(fileName); + const QHBufC nativeFileName(QDir::toNativeSeparators(fileName)); if (KErrNone == err) { TDataRecognitionResult recognizerResult; err = m_recognizer.RecognizeData(*m_file, recognizerResult); @@ -141,16 +133,30 @@ MMF::MediaType MMF::MediaObject::fileMediaType const TPtrC mimeType = recognizerResult.iDataType.Des(); result = Utils::mimeTypeToMediaType(mimeType); } else { - TRACE("RApaLsSession::RecognizeData filename %S error %d", fileNameSymbian.data(), err); + TRACE("RApaLsSession::RecognizeData filename %S error %d", nativeFileName.data(), err); } } else { - TRACE("RFile::Open filename %S error %d", fileNameSymbian.data(), err); + TRACE("RFile::Open filename %S error %d", nativeFileName.data(), err); } } return result; } +int MMF::MediaObject::openFileHandle(const QString &fileName) +{ + TRACE_CONTEXT(MediaObject::openFileHandle, EAudioInternal); + const QHBufC nativeFileName(QDir::toNativeSeparators(fileName)); + TRACE_ENTRY("filename %S", nativeFileName.data()); + if (m_file) + m_file->Close(); + delete m_file; + m_file = 0; + m_file = new RFile; + TInt err = m_file->Open(m_fileServer, *nativeFileName, EFileRead | EFileShareReadersOrWriters); + return err; +} + MMF::MediaType MMF::MediaObject::bufferMediaType(const uchar *data, qint64 size) { TRACE_CONTEXT(MediaObject::bufferMediaType, EAudioInternal); diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index 5399e27..5d785fb 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -89,6 +89,7 @@ public: void setVideoOutput(AbstractVideoOutput* videoOutput); + int openFileHandle(const QString &fileName); RFile* file() const; QResource* resource() const; -- cgit v0.12 From d1b6c5d5e101c9ffdfdfb7b712ea69025150ab05 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Mon, 27 Sep 2010 18:07:35 +0100 Subject: qmediaplayer: show buffer status of 0% During progressive download, it is not possible for the Symbian MMF Phonon backend to determine the buffering status, so it returns a value of 0%. This change causes qmediaplayer to display this value in the UI, thereby giving a visible notification of buffering during progressive download. Task-number: QTBUG-10769 Reviewed-by: Derick Hawcroft --- demos/qmediaplayer/mediaplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/qmediaplayer/mediaplayer.cpp b/demos/qmediaplayer/mediaplayer.cpp index 3cb0616..97a8e35 100644 --- a/demos/qmediaplayer/mediaplayer.cpp +++ b/demos/qmediaplayer/mediaplayer.cpp @@ -716,7 +716,7 @@ void MediaPlayer::openFile() void MediaPlayer::bufferStatus(int percent) { - if (percent == 0 || percent == 100) + if (percent == 100) progressLabel->setText(QString()); else { QString str = QString::fromLatin1("(%1%)").arg(percent); -- cgit v0.12 From 71af72bc037db6bac023bf9a0bbf6032c06b2d29 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Sun, 3 Oct 2010 19:43:29 +0100 Subject: Added qmake check for presence of RHttpDownloadMgr header downloadmgrclient.h is not found on S^4 baselines, causing a build failure. This commit is a temporary workaround, which disables progressive download support if the header is not found. The correct solution is to determine whether the RHttpDownloadMgr definition has moved, and if so, to modify the .pro file to include the new path. Task-number: QTBUG-10769 Reviewed-by: TrustMe --- src/3rdparty/phonon/mmf/abstractmediaplayer.cpp | 26 ++++++++++-- src/3rdparty/phonon/mmf/abstractmediaplayer.h | 9 ++++- src/3rdparty/phonon/mmf/download.h | 2 - src/plugins/phonon/mmf/mmf.pro | 53 +++++++++++++++---------- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index a728423..dfc5840 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -56,8 +56,10 @@ MMF::AbstractMediaPlayer::AbstractMediaPlayer , m_mmfMaxVolume(NullMaxVolume) , m_prefinishMarkSent(false) , m_aboutToFinishSent(false) +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD , m_download(0) , m_downloadStalled(false) +#endif { connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); @@ -256,7 +258,9 @@ void MMF::AbstractMediaPlayer::open() symbianErr = openFile(*file); if (KErrNone != symbianErr) errorMessage = tr("Error opening file"); - } else if (url.scheme() == QLatin1String("http")) { + } +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD + else if (url.scheme() == QLatin1String("http")) { Q_ASSERT(!m_download); m_download = new Download(url, this); connect(m_download, SIGNAL(lengthChanged(qint64)), @@ -264,7 +268,9 @@ void MMF::AbstractMediaPlayer::open() connect(m_download, SIGNAL(stateChanged(Download::State)), this, SLOT(downloadStateChanged(Download::State))); m_download->start(); - } else { + } +#endif + else { symbianErr = openUrl(url.toString()); if (KErrNone != symbianErr) errorMessage = tr("Error opening URL"); @@ -308,8 +314,10 @@ void MMF::AbstractMediaPlayer::open() void MMF::AbstractMediaPlayer::close() { doClose(); +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD delete m_download; m_download = 0; +#endif m_position = 0; } @@ -419,7 +427,9 @@ void MMF::AbstractMediaPlayer::loadingComplete(int error) bufferingComplete(); doSeek(m_position); startPlayback(); +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD m_downloadStalled = false; +#endif } } else { Q_ASSERT(Phonon::LoadingState == state()); @@ -472,12 +482,20 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds bool MMF::AbstractMediaPlayer::isProgressiveDownload() const { +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD return (0 != m_download); +#else + return false; +#endif } bool MMF::AbstractMediaPlayer::progressiveDownloadStalled() const { +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD return m_downloadStalled; +#else + return false; +#endif } //----------------------------------------------------------------------------- @@ -547,6 +565,7 @@ void MMF::AbstractMediaPlayer::startPlayback() void MMF::AbstractMediaPlayer::setProgressiveDownloadStalled() { +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD TRACE_CONTEXT(AbstractMediaPlayer::setProgressiveDownloadStalled, EAudioApi); TRACE_ENTRY("state %d", state()); Q_ASSERT(isProgressiveDownload()); @@ -555,7 +574,6 @@ void MMF::AbstractMediaPlayer::setProgressiveDownloadStalled() bufferingStarted(); // Video player loses window handle when closed - need to reapply it here videoOutputChanged(); -#ifdef QT_PHONON_MMF_DOWNLOAD_DUMMY m_download->resume(); #endif } @@ -569,6 +587,7 @@ void MMF::AbstractMediaPlayer::bufferStatusTick() emit MMF::AbstractPlayer::bufferStatus(status); } +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD void MMF::AbstractMediaPlayer::downloadLengthChanged(qint64 length) { TRACE_CONTEXT(AbstractMediaPlayer::downloadLengthChanged, EAudioApi); @@ -611,6 +630,7 @@ void MMF::AbstractMediaPlayer::downloadStateChanged(Download::State state) break; } } +#endif // PHONON_MMF_PROGRESSIVE_DOWNLOAD Phonon::State MMF::AbstractMediaPlayer::phononState(PrivateState state) const { diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index 99fc101..c3b4528 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -23,7 +23,9 @@ along with this library. If not, see . #include #include #include "abstractplayer.h" -#include "download.h" +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD +# include "download.h" +#endif class RFile; @@ -118,8 +120,10 @@ private: private Q_SLOTS: void positionTick(); void bufferStatusTick(); +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD void downloadLengthChanged(qint64); void downloadStateChanged(Download::State); +#endif private: MediaObject *const m_parent; @@ -140,9 +144,10 @@ private: // Used for playback of resource files TPtrC8 m_buffer; - // Used for progressive download +#ifdef PHONON_MMF_PROGRESSIVE_DOWNLOAD Download *m_download; bool m_downloadStalled; +#endif QMultiMap m_metaData; diff --git a/src/3rdparty/phonon/mmf/download.h b/src/3rdparty/phonon/mmf/download.h index b57348b..bda7963 100644 --- a/src/3rdparty/phonon/mmf/download.h +++ b/src/3rdparty/phonon/mmf/download.h @@ -70,8 +70,6 @@ public: const QUrl &sourceUrl() const; const QString &targetFileName() const; void start(); - - // Only has effect when QT_PHONON_MMF_DOWNLOAD_DUMMY is defined void resume(); enum State { diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index 902354f..ac11188 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -36,7 +36,6 @@ symbian { $$PHONON_MMF_DIR/backend.h \ $$PHONON_MMF_DIR/bassboost.h \ $$PHONON_MMF_DIR/defs.h \ - $$PHONON_MMF_DIR/download.h \ $$PHONON_MMF_DIR/dummyplayer.h \ $$PHONON_MMF_DIR/effectfactory.h \ $$PHONON_MMF_DIR/effectparameter.h \ @@ -62,7 +61,6 @@ symbian { $$PHONON_MMF_DIR/abstractvideoplayer.cpp \ $$PHONON_MMF_DIR/backend.cpp \ $$PHONON_MMF_DIR/bassboost.cpp \ - $$PHONON_MMF_DIR/download.cpp \ $$PHONON_MMF_DIR/dummyplayer.cpp \ $$PHONON_MMF_DIR/effectfactory.cpp \ $$PHONON_MMF_DIR/effectparameter.cpp \ @@ -77,25 +75,37 @@ symbian { $$PHONON_MMF_DIR/utils.cpp \ $$PHONON_MMF_DIR/videowidget.cpp - # Test for whether the build environment supports video rendering to graphics - # surfaces. - symbian:exists($${EPOCROOT}epoc32/include/platform/videoplayer2.h) { - HEADERS += \ - $$PHONON_MMF_DIR/videooutput_surface.h \ - $$PHONON_MMF_DIR/videoplayer_surface.h - SOURCES += \ - $$PHONON_MMF_DIR/videooutput_surface.cpp \ - $$PHONON_MMF_DIR/videoplayer_surface.cpp - DEFINES += PHONON_MMF_VIDEO_SURFACES - } else { - HEADERS += \ - $$PHONON_MMF_DIR/ancestormovemonitor.h \ - $$PHONON_MMF_DIR/videooutput_dsa.h \ - $$PHONON_MMF_DIR/videoplayer_dsa.h - SOURCES += \ - $$PHONON_MMF_DIR/ancestormovemonitor.cpp \ - $$PHONON_MMF_DIR/videooutput_dsa.cpp \ - $$PHONON_MMF_DIR/videoplayer_dsa.cpp \ + symbian { + # Test for whether the build environment supports video rendering to graphics + # surfaces. + exists($${EPOCROOT}epoc32/include/platform/videoplayer2.h) { + HEADERS += \ + $$PHONON_MMF_DIR/videooutput_surface.h \ + $$PHONON_MMF_DIR/videoplayer_surface.h + SOURCES += \ + $$PHONON_MMF_DIR/videooutput_surface.cpp \ + $$PHONON_MMF_DIR/videoplayer_surface.cpp + DEFINES += PHONON_MMF_VIDEO_SURFACES + } else { + HEADERS += \ + $$PHONON_MMF_DIR/ancestormovemonitor.h \ + $$PHONON_MMF_DIR/videooutput_dsa.h \ + $$PHONON_MMF_DIR/videoplayer_dsa.h + SOURCES += \ + $$PHONON_MMF_DIR/ancestormovemonitor.cpp \ + $$PHONON_MMF_DIR/videooutput_dsa.cpp \ + $$PHONON_MMF_DIR/videoplayer_dsa.cpp \ + } + + # Test whether the build environment includes support for the Download Manager + # API, required for Progressive Download + exists($${EPOCROOT}epoc32/include/downloadmgrclient.h) | \ + exists($${EPOCROOT}epoc32/include/mw/downloadmgrclient.h) { + HEADERS += $$PHONON_MMF_DIR/download.h + SOURCES += $$PHONON_MMF_DIR/download.cpp + LIBS += -ldownloadmgr + DEFINES += PHONON_MMF_PROGRESSIVE_DOWNLOAD + } } LIBS += -lcone @@ -113,7 +123,6 @@ symbian { LIBS += -lapgrfx -lapmime # For recognizer LIBS += -lmmfcontrollerframework # For CMMFMetaDataEntry LIBS += -lmediaclientaudiostream # For CMdaAudioOutputStream - LIBS += -ldownloadmgr # These are for effects. LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerBase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect -- cgit v0.12 From 4cff91c66207b870e12365421e63cd978e162e64 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 8 Oct 2010 10:55:54 +0200 Subject: Fix infinite loop when justifying undisplayable Arabic text If the Arabic text is for some reason undisplayable, e.g. because of QTBUG-13132, the font engine will be unable to find the tatweel character and the kashida width may be returned as 0. This would potentially cause an infinite loop, as "need" would remain >= minKashida forever because x - 0 is still >= 0. Task-number: QTBUG-13130 Reviewed-by: Lars --- src/gui/text/qtextengine.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 05de8f5..3bd6122 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1949,9 +1949,11 @@ void QTextEngine::justify(const QScriptLine &line) if (kashida_pos >= 0) { // qDebug("kashida position at %d in word", kashida_pos); set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si)); - minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth); - maxJustify = qMax(maxJustify, justificationPoints[nPoints].type); - ++nPoints; + if (justificationPoints[nPoints].kashidaWidth > 0) { + minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth); + maxJustify = qMax(maxJustify, justificationPoints[nPoints].type); + ++nPoints; + } } kashida_pos = -1; kashida_type = HB_Arabic_Normal; @@ -1975,9 +1977,11 @@ void QTextEngine::justify(const QScriptLine &line) } if (kashida_pos >= 0) { set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si)); - minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth); - maxJustify = qMax(maxJustify, justificationPoints[nPoints].type); - ++nPoints; + if (justificationPoints[nPoints].kashidaWidth > 0) { + minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth); + maxJustify = qMax(maxJustify, justificationPoints[nPoints].type); + ++nPoints; + } } } -- cgit v0.12 From 4d974ff0a748b22e668a4cb7ef38101122c85b3b Mon Sep 17 00:00:00 2001 From: Benjamin Poulain Date: Fri, 8 Oct 2010 14:21:10 +0200 Subject: Avoid in-place convertion of images with multiple references The decoding from image reader was assuming the image reader do not keep the image internally. This is not true for the GIF plugins because the previous image can be used to compose the current image. This was causing crash on ARM because the 16 bits color depth causes the image memory to be reduce by half. When the plugin was accessing the memory, it assumes the images has not changed and is on 32 bits. This patch disable the in-place conversion if a detach is required. Regular conversion is the correct solution in this case, and it can also be made faster by converting while copying. Reviewed-by: Andreas Kling --- src/gui/image/qimage.cpp | 4 ++++ tests/auto/qpixmap/tst_qpixmap.cpp | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index ac148ee..1157b93 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -6607,6 +6607,10 @@ bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFla if (format == newFormat) return true; + // No in-place conversion if we have to detach + if (ref > 1) + return false; + const InPlace_Image_Converter *const converterPtr = &inplace_converter_map[format][newFormat]; InPlace_Image_Converter converter = *converterPtr; if (converter) diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index 8005ec5..24cbb21 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -179,6 +179,7 @@ private slots: void fromImageReader_data(); void fromImageReader(); + void fromImageReaderAnimatedGif_data(); void fromImageReaderAnimatedGif(); void preserveDepth(); @@ -1605,6 +1606,8 @@ void tst_QPixmap::fromImageReader_data() QTest::newRow("designer_indexed8_no_alpha.gif") << prefix + "/designer_indexed8_no_alpha.gif"; QTest::newRow("designer_indexed8_with_alpha.gif") << prefix + "/designer_indexed8_with_alpha.gif"; QTest::newRow("designer_rgb32.jpg") << prefix + "/designer_rgb32.jpg"; + QTest::newRow("designer_indexed8_with_alpha_animated") << prefix + "/designer_indexed8_with_alpha_animated.gif"; + QTest::newRow("designer_indexed8_with_alpha_animated") << prefix + "/designer_indexed8_no_alpha_animated.gif"; } void tst_QPixmap::fromImageReader() @@ -1621,14 +1624,22 @@ void tst_QPixmap::fromImageReader() QVERIFY(pixmapsAreEqual(&pixmapWithCopy, &directLoadingPixmap)); } +void tst_QPixmap::fromImageReaderAnimatedGif_data() +{ + QTest::addColumn("imagePath"); + QTest::newRow("gif with alpha") << QString::fromLatin1("/designer_indexed8_with_alpha_animated.gif"); + QTest::newRow("gif without alpha") << QString::fromLatin1("/designer_indexed8_no_alpha_animated.gif"); +} + void tst_QPixmap::fromImageReaderAnimatedGif() { + QFETCH(QString, imagePath); #ifdef Q_OS_SYMBIAN const QString prefix = QLatin1String(SRCDIR) + "loadFromData"; #else const QString prefix = QLatin1String(SRCDIR) + "/loadFromData"; #endif - const QString path = prefix + QString::fromLatin1("/designer_indexed8_with_alpha_animated.gif"); + const QString path = prefix + imagePath; QImageReader referenceReader(path); QImageReader pixmapReader(path); -- cgit v0.12 From 7ca4e9622c4b2e4142d401fa10d50a0a45906615 Mon Sep 17 00:00:00 2001 From: axis Date: Thu, 7 Oct 2010 15:26:47 +0200 Subject: Fixed missing QMAKE_MOC definition in certain mkspecs. Also removed the use of DIR_SEPARATOR. It does not get defined until after symbian.conf has finished parsing. RevBy: Miikka Heikkinen --- mkspecs/common/symbian/symbian-mmp.conf | 10 ---------- mkspecs/common/symbian/symbian.conf | 8 ++++++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/mkspecs/common/symbian/symbian-mmp.conf b/mkspecs/common/symbian/symbian-mmp.conf index 5292781..1fbd302 100644 --- a/mkspecs/common/symbian/symbian-mmp.conf +++ b/mkspecs/common/symbian/symbian-mmp.conf @@ -4,16 +4,6 @@ include(symbian.conf) -contains(QMAKE_HOST.os, "Windows") { - QMAKE_MOC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc.exe - QMAKE_UIC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic.exe - QMAKE_IDC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc.exe -} else { - QMAKE_MOC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc - QMAKE_UIC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic - QMAKE_IDC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc -} - load(symbian/add_mmp_rules) symbian-abld { diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index cc5b788..d8c38f4 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -95,6 +95,10 @@ contains(QMAKE_HOST.os,Windows) { QMAKE_DEL_DIR = rmdir QMAKE_DEL_TREE = rmdir /s /q QMAKE_CHK_DIR_EXISTS = if not exist + + QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe + QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe + QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe } else { QMAKE_COPY = cp QMAKE_COPY_DIR = cp -r @@ -104,6 +108,10 @@ contains(QMAKE_HOST.os,Windows) { QMAKE_DEL_DIR = rmdir QMAKE_DEL_TREE = rm -rf QMAKE_CHK_DIR_EXISTS = test -d + + QMAKE_MOC = $$[QT_INSTALL_BINS]/moc + QMAKE_UIC = $$[QT_INSTALL_BINS]/uic + QMAKE_IDC = $$[QT_INSTALL_BINS]/idc } QMAKE_IDL = midl -- cgit v0.12 From aa0f3a7745472ea8c9ca43bb7d690a0591bde83b Mon Sep 17 00:00:00 2001 From: axis Date: Fri, 8 Oct 2010 14:58:44 +0200 Subject: Fixed some preprocessor parameters for Mac support. RevBy: Liang Qi --- mkspecs/features/symbian/symbian_building.prf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mkspecs/features/symbian/symbian_building.prf b/mkspecs/features/symbian/symbian_building.prf index 614fb65..1a51cb2 100644 --- a/mkspecs/features/symbian/symbian_building.prf +++ b/mkspecs/features/symbian/symbian_building.prf @@ -229,7 +229,7 @@ symbian_resources_INCLUDES = $$replace(symbian_resources_INCLUDES, ",", " -I") symbian_resources_INCLUDES += $$join(INCLUDEPATH, " -I", "-I") symbian_resources_DEFINES = $$join(DEFINES, " -D", "-D") symbian_resources_RCC_DIR = $$replace(RCC_DIR, "/$", "") -symbian_resources_INCLUDES += "-I $$symbian_resources_RCC_DIR" +symbian_resources_INCLUDES += "-I$$symbian_resources_RCC_DIR" for(symbian_resource, SYMBIAN_RESOURCES) { symbian_resource = $$basename(symbian_resource) @@ -245,7 +245,7 @@ symbianresources.commands = cpp -nostdinc -undef \ $$symbian_resources_INCLUDES \ $$symbian_resources_DEFINES \ ${QMAKE_FILE_NAME} \ - -o $${symbian_resources_RCC_DIR}/${QMAKE_FILE_BASE}.rpp \ + > $${symbian_resources_RCC_DIR}/${QMAKE_FILE_BASE}.rpp \ && rcomp -u -m045,046,047 \ -s$${symbian_resources_RCC_DIR}/${QMAKE_FILE_BASE}.rpp \ -o$${symbianDestdir}/${QMAKE_FILE_BASE}$${QT_LIBINFIX}.rsc \ @@ -265,7 +265,7 @@ contains(TEMPLATE, "app"):!contains(CONFIG, "no_icon") { $$symbian_resources_INCLUDES \ $$symbian_resources_DEFINES \ $${baseTarget}.rss \ - -o $${symbian_resources_RCC_DIR}/$${baseTarget}.rpp \ + > $${symbian_resources_RCC_DIR}/$${baseTarget}.rpp \ && rcomp -u -m045,046,047 \ -s$${symbian_resources_RCC_DIR}/$${baseTarget}.rpp \ -o$${symbianDestdir}/$${baseTarget}.rsc \ @@ -284,7 +284,7 @@ contains(TEMPLATE, "app"):!contains(CONFIG, "no_icon") { $$symbian_resources_INCLUDES \ $$symbian_resources_DEFINES \ $${baseTarget}_reg.rss \ - -o $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp \ + > $${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp \ && rcomp -u -m045,046,047 \ -s$${symbian_resources_RCC_DIR}/$${baseTarget}_reg.rpp \ -o$${symbianDestdir}/$${baseTarget}_reg.rsc \ -- cgit v0.12 From 4ee912a752a4b7f129e98e180328f1f46f053d4f Mon Sep 17 00:00:00 2001 From: axis Date: Fri, 1 Oct 2010 13:25:28 +0200 Subject: Added support for using inputMethodHints in QInputDialog edit widget. AutoTest: Included Task: QTBUG-13200 RevBy: Denis Dzyubenko --- src/gui/dialogs/qinputdialog.cpp | 6 ++++++ src/gui/kernel/qwidget.cpp | 11 +++++++++-- src/gui/kernel/qwidget_p.h | 3 +++ tests/auto/qinputdialog/tst_qinputdialog.cpp | 20 ++++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/gui/dialogs/qinputdialog.cpp b/src/gui/dialogs/qinputdialog.cpp index e996ee9..700b234 100644 --- a/src/gui/dialogs/qinputdialog.cpp +++ b/src/gui/dialogs/qinputdialog.cpp @@ -244,6 +244,9 @@ void QInputDialogPrivate::ensureLineEdit() Q_Q(QInputDialog); if (!lineEdit) { lineEdit = new QLineEdit(q); +#ifndef QT_NO_IM + qt_widget_private(lineEdit)->inheritsInputMethodHints = 1; +#endif lineEdit->hide(); QObject::connect(lineEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); @@ -255,6 +258,9 @@ void QInputDialogPrivate::ensureComboBox() Q_Q(QInputDialog); if (!comboBox) { comboBox = new QComboBox(q); +#ifndef QT_NO_IM + qt_widget_private(comboBox)->inheritsInputMethodHints = 1; +#endif comboBox->hide(); QObject::connect(comboBox, SIGNAL(editTextChanged(QString)), q, SLOT(_q_textChanged(QString))); diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index dc0dbf4..330d699 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -273,6 +273,9 @@ QWidgetPrivate::QWidgetPrivate(int version) , isMoved(0) , isGLWidget(0) , usesDoubleBufferedGLContext(0) +#ifndef QT_NO_IM + , inheritsInputMethodHints(0) +#endif #if defined(Q_WS_X11) , picture(0) #elif defined(Q_WS_WIN) @@ -9228,9 +9231,13 @@ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const */ Qt::InputMethodHints QWidget::inputMethodHints() const { - Q_D(const QWidget); #ifndef QT_NO_IM - return d->imHints; + const QWidgetPrivate *priv = d_func(); + while (priv->inheritsInputMethodHints) { + priv = priv->q_func()->parentWidget()->d_func(); + Q_ASSERT(priv); + } + return priv->imHints; #else //QT_NO_IM return 0; #endif //QT_NO_IM diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 4a79dc7..6c89659 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -748,6 +748,9 @@ public: uint isMoved : 1; uint isGLWidget : 1; uint usesDoubleBufferedGLContext : 1; +#ifndef QT_NO_IM + uint inheritsInputMethodHints : 1; +#endif // *************************** Platform specific ************************************ #if defined(Q_WS_X11) // <----------------------------------------------------------- X11 diff --git a/tests/auto/qinputdialog/tst_qinputdialog.cpp b/tests/auto/qinputdialog/tst_qinputdialog.cpp index 0d6644a..5d03142 100644 --- a/tests/auto/qinputdialog/tst_qinputdialog.cpp +++ b/tests/auto/qinputdialog/tst_qinputdialog.cpp @@ -74,6 +74,7 @@ private slots: void getItem_data(); void getItem(); void task256299_getTextReturnNullStringOnRejected(); + void inputMethodHintsOfChildWidget(); }; QString stripFraction(const QString &s) @@ -404,5 +405,24 @@ void tst_QInputDialog::getItem() delete parent; } +void tst_QInputDialog::inputMethodHintsOfChildWidget() +{ + QInputDialog dialog; + dialog.setInputMode(QInputDialog::TextInput); + QList children = dialog.children(); + QLineEdit *editWidget = 0; + for (int c = 0; c < children.size(); c++) { + editWidget = qobject_cast(children.at(c)); + if (editWidget) + break; + } + QVERIFY(editWidget); + QCOMPARE(editWidget->inputMethodHints(), dialog.inputMethodHints()); + QCOMPARE(editWidget->inputMethodHints(), Qt::ImhNone); + dialog.setInputMethodHints(Qt::ImhDigitsOnly); + QCOMPARE(editWidget->inputMethodHints(), dialog.inputMethodHints()); + QCOMPARE(editWidget->inputMethodHints(), Qt::ImhDigitsOnly); +} + QTEST_MAIN(tst_QInputDialog) #include "tst_qinputdialog.moc" -- cgit v0.12 From 0fcee2f495eb2e1c4b76aa8c3e5462595aed0ab3 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 8 Oct 2010 13:25:04 +0100 Subject: Account for native child widgets when handling focus events The code previously contained an implicit assumption that the control which received the FocusChanged event was a top-level widget. This meant that focus events delivered to native child widgets could cause unexpected changes in visibility of the statusbar and CBA. Task-number: QTBUG-13761 Reviewed-by: Jason Barron --- src/gui/kernel/qapplication_s60.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 296f24f..5ff2fd4 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1237,10 +1237,11 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle()); #ifdef Q_WS_S60 // If widget is fullscreen/minimized, hide status pane and button container otherwise show them. - const bool visible = !(qwidget->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized)); + QWidget *const window = qwidget->window(); + const bool visible = !(window->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized)); const bool statusPaneVisibility = visible; - const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen; - const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint; + const bool isFullscreen = window->windowState() & Qt::WindowFullScreen; + const bool cbaVisibilityHint = window->windowFlags() & Qt::WindowSoftkeysVisibleHint; const bool buttonGroupVisibility = (visible || (isFullscreen && cbaVisibilityHint)); S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility); #endif -- cgit v0.12 From f0c1f381af7d6338ded9f65d00ed54b1b9405ba9 Mon Sep 17 00:00:00 2001 From: Benjamin Poulain Date: Sat, 9 Oct 2010 17:28:06 +0200 Subject: Add missing data for the autotest of in-place conversion for Pixmap The commit 4d974ff0a748b22e668a4cb7ef38101122c85b3b uses an new image which was not commited with the patch. --- .../loadFromData/designer_indexed8_no_alpha_animated.gif | Bin 0 -> 4075 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif diff --git a/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif b/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif new file mode 100644 index 0000000..86a3a2e Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif differ -- cgit v0.12 From 36438bc216f939acd4e6772847d435e2e77d41c3 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 11 Oct 2010 10:48:54 +0200 Subject: Designer: Fix a crash when copying empty page-based containers. Reviewed-by: Jarek Kobus Task-number: QTBUG-14208 --- tools/designer/src/components/formeditor/formwindow.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/designer/src/components/formeditor/formwindow.cpp b/tools/designer/src/components/formeditor/formwindow.cpp index 15775f6..38a0544 100644 --- a/tools/designer/src/components/formeditor/formwindow.cpp +++ b/tools/designer/src/components/formeditor/formwindow.cpp @@ -1683,10 +1683,13 @@ void FormWindow::cut() // for cases like QMainWindow (central widget is an inner container) or QStackedWidget (page is an inner container) QWidget *FormWindow::innerContainer(QWidget *outerContainer) const { - bool isContainer = m_core->widgetDataBase()->isContainer(outerContainer); - if (isContainer) - if (QDesignerContainerExtension *container = qt_extension(m_core->extensionManager(), outerContainer)) - return container->widget(container->currentIndex()); + if (m_core->widgetDataBase()->isContainer(outerContainer)) + if (const QDesignerContainerExtension *container = qt_extension(m_core->extensionManager(), outerContainer)) { + const int currentIndex = container->currentIndex(); + return currentIndex >= 0 ? + container->widget(currentIndex) : + static_cast(0); + } return outerContainer; } @@ -1706,8 +1709,10 @@ QWidget *FormWindow::containerForPaste() const QWidget *containerOfW = findContainer(selection.first(), /* exclude layouts */ true); if (!containerOfW || containerOfW == mainContainer()) break; - // No layouts, must be container + // No layouts, must be container. No empty page-based containers. containerOfW = innerContainer(containerOfW); + if (!containerOfW) + break; if (LayoutInfo::layoutType(m_core, containerOfW) != LayoutInfo::NoLayout || !m_core->widgetDataBase()->isContainer(containerOfW)) break; w = containerOfW; @@ -1716,6 +1721,8 @@ QWidget *FormWindow::containerForPaste() const // and the like as the central widget has the layout). w = innerContainer(w); + if (!w) + return 0; if (LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout) return 0; // Go up via container extension (also includes step from QMainWindow to its central widget) -- cgit v0.12 From 48f18622b6fbfd19ccc77574d3750a8c0c1f6a7d Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 8 Oct 2010 16:59:44 +0100 Subject: Spectrum demo: put binaries into correct locations on Windows Task-number: QTBUG-13483 Reviewed-by: Miikka Heikkinen --- demos/spectrum/3rdparty/fftreal/fftreal.pro | 2 +- demos/spectrum/app/app.pro | 9 ++------- demos/spectrum/spectrum.pri | 12 ++++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/demos/spectrum/3rdparty/fftreal/fftreal.pro b/demos/spectrum/3rdparty/fftreal/fftreal.pro index 6305af4..e5093ba 100644 --- a/demos/spectrum/3rdparty/fftreal/fftreal.pro +++ b/demos/spectrum/3rdparty/fftreal/fftreal.pro @@ -40,7 +40,7 @@ symbian { macx { CONFIG += lib_bundle } else { - !symbian: DESTDIR = ../.. + !symbian: DESTDIR = ../..$${spectrum_build_dir} } # Install diff --git a/demos/spectrum/app/app.pro b/demos/spectrum/app/app.pro index 4fe8b6d..57be114 100644 --- a/demos/spectrum/app/app.pro +++ b/demos/spectrum/app/app.pro @@ -65,7 +65,7 @@ symbian { LIBS += -F$${fftreal_dir} LIBS += -framework fftreal } else { - LIBS += -L.. + LIBS += -L..$${spectrum_build_dir} LIBS += -lfftreal } } @@ -91,10 +91,8 @@ symbian { DEPLOYMENT += fftreal } } else { + DESTDIR = ..$${spectrum_build_dir} macx { - # Specify directory in which to create spectrum.app bundle - DESTDIR = .. - !contains(DEFINES, DISABLE_FFT) { # Relocate fftreal.framework into spectrum.app bundle framework_dir = ../spectrum.app/Contents/Frameworks @@ -110,9 +108,6 @@ symbian { ../spectrum.app/Contents/MacOS/spectrum } } else { - # Specify directory in which to create spectrum application - DESTDIR = .. - unix: { # Provide relative path from application to fftreal library QMAKE_LFLAGS += -Wl,--rpath=\\\$\$ORIGIN diff --git a/demos/spectrum/spectrum.pri b/demos/spectrum/spectrum.pri index c09aa0d..5773900 100644 --- a/demos/spectrum/spectrum.pri +++ b/demos/spectrum/spectrum.pri @@ -35,3 +35,15 @@ DEFINES += SPECTRUM_ANALYSER_SEPARATE_THREAD # Suppress warnings about strncpy potentially being unsafe, emitted by MSVC win32: DEFINES += _CRT_SECURE_NO_WARNINGS +win32 { + # spectrum_build_dir is defined with a leading slash so that it can + # be used in contexts such as + # ..$${spectrum_build_dir} + # without the result having a trailing slash where spectrum_build_dir + # is undefined. + spectrum_build_dir = /release + if (!debug_and_release|build_pass): CONFIG(debug, debug|release) { + spectrum_build_dir = /debug + } +} + -- cgit v0.12 From 3c2296647d2e7ddda4df6679a622b0bf46b34c35 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Fri, 8 Oct 2010 15:10:56 +0100 Subject: Spectrum demo: only use --rpath for linux-g++* mkspecs Task-number: QTBUG-13940 Reviewed-by: Martin Pejcoch --- demos/spectrum/app/app.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/spectrum/app/app.pro b/demos/spectrum/app/app.pro index 57be114..b3ff227 100644 --- a/demos/spectrum/app/app.pro +++ b/demos/spectrum/app/app.pro @@ -108,7 +108,7 @@ symbian { ../spectrum.app/Contents/MacOS/spectrum } } else { - unix: { + linux-g++*: { # Provide relative path from application to fftreal library QMAKE_LFLAGS += -Wl,--rpath=\\\$\$ORIGIN } -- cgit v0.12 From c27f1586d7c4c56af1f46fa09ad77f03b7736e5d Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 8 Oct 2010 15:31:09 +0100 Subject: Making the hybrid allocator change compatible across all 4.7.x The hybrid allocator introduced a new export to qtcore.dll and made all apps link to it when they linked with the corresponding qtmain.lib. However, this made all apps depend on this new export, and since that export is not present in early 4.7.x release, these apps would not run with the Qt DLLs from those releases, which breaks Qt's compatibility guarantees for patch releases. This change makes apps compatible with all 4.7.x releases again. For export frozen Qt builds (the sort that should be compatible across all 4.7.x releases), qtmain.lib no longer forces a static import link to qt_symbian_SetupThreadHeap(). Instead it dynamically loads qtcore.dll, looks up qt_symbian_SetupThreadHeap(), and calls it if present. If the function is not present, or on emulator builds where we know that qtcore will use the system allocator creation function, we call the system allocator creation function. For export unfrozen builds, there is no compatibility between builds or releases, so we do use a static import link to qt_symbian_SetupThreadHeap(), as we have to use the qtcore dll we have built with it anyway. This has been tested as follows: S60 3.1 SDK, def files not frozen. App compiled against latest code runs on the corresponding DLLs, and does not start with 4.7.0, which is what we expect. S60 3.2 SDK, def files frozen. App compiled against latest code runs on the corresponding DLLs with the new allocator, and runs on 4.7.0 DLLs with the old allocator. Which demonstrates compatibility. S60 5.0 SDK, def files not frozen, debug build. Same result as for the 3.1 SDK, which demonstrates debug build working too (all other tests are release build tests). S60 5.0 SDK, def files frozen, debug build. Same result as on S60 3.2 SDK, which demonstrates debug build working with def files. Symbian^3 SDK, def files frozen. Same result as on S60 3.2 SDK, demonstrating Symbian^3 compatibility. Symbian^4, code and tests compile and does not affect running. *** This change is only required for 4.7. It is not needed for 4.8+ *** *** If this change appears in 4.8+, it can be reverted. *** Task-number: QT-4080 Reviewed-by: Shane Kearns --- src/s60main/newallocator_hook.cpp | 87 ++++++++++++++++++++++++++++++++++++++- src/s60main/s60main.pro | 3 ++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/s60main/newallocator_hook.cpp b/src/s60main/newallocator_hook.cpp index 9cc6afb..9ea2ef0 100644 --- a/src/s60main/newallocator_hook.cpp +++ b/src/s60main/newallocator_hook.cpp @@ -41,6 +41,11 @@ #include #include +#ifdef QT_EXPORTS_NOT_FROZEN +// If exports in Qt DLLs are not frozen in this build, then we have to pick up the +// allocator creation function by import link. We know the function will be present +// in the DLLs we test with, as we have to use the DLLs we have built. + struct SStdEpocThreadCreateInfo; Q_CORE_EXPORT TInt qt_symbian_SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo); @@ -51,8 +56,88 @@ Q_CORE_EXPORT TInt qt_symbian_SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCre * Uses link-time symbol preemption to capture a call from the application * startup. On return, there is some kind of heap allocator installed on the * thread. -*/ +*/ TInt UserHeap::SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo) { return qt_symbian_SetupThreadHeap(aNotFirst, aInfo); } + +#else // QT_EXPORTS_NOT_FROZEN +// If we are using an export frozen build, it should be compatible with all 4.7.x Qt releases. +// We want to use the allocator creation function introduced in qtcore.dll after 4.7.1. But we +// can't import link to it, as it may not be present in whatever 4.7.x DLLs we are running with. +// So the function is found and called dynamically, by library lookup. If it is not found, we +// use the OS allocator creation functions instead. + +struct SThreadCreateInfo + { + TAny* iHandle; + TInt iType; + TThreadFunction iFunction; + TAny* iPtr; + TAny* iSupervisorStack; + TInt iSupervisorStackSize; + TAny* iUserStack; + TInt iUserStackSize; + TInt iInitialThreadPriority; + TPtrC iName; + TInt iTotalSize; // Size including any extras (must be a multiple of 8 bytes) + }; + +struct SStdEpocThreadCreateInfo : public SThreadCreateInfo + { + RAllocator* iAllocator; + TInt iHeapInitialSize; + TInt iHeapMaxSize; + TInt iPadding; // Make structure size a multiple of 8 bytes + }; + + +/* \internal + * + * Uses link-time symbol preemption to capture a call from the application + * startup. On return, there is some kind of heap allocator installed on the + * thread. +*/ +TInt UserHeap::SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo) +{ + TInt r = KErrNone; + +#ifndef __WINS__ + // attempt to create the fast allocator through a known export ordinal in qtcore.dll + RLibrary qtcore; + if (qtcore.Load(_L("qtcore.dll")) == KErrNone) + { + const int qt_symbian_SetupThreadHeap_eabi_ordinal = 3713; + TLibraryFunction libFunc = qtcore.Lookup(qt_symbian_SetupThreadHeap_eabi_ordinal); + if (libFunc) + { + typedef int (*TSetupThreadHeapFunc)(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo); + TSetupThreadHeapFunc p_qt_symbian_SetupThreadHeap = TSetupThreadHeapFunc(libFunc); + r = (*p_qt_symbian_SetupThreadHeap)(aNotFirst, aInfo); + } + qtcore.Close(); + if (libFunc) + return r; + } +#endif + + // no fast allocator support - use default allocator creation + if (!aInfo.iAllocator && aInfo.iHeapInitialSize>0) + { + // new heap required + RHeap* pH = NULL; + r = UserHeap::CreateThreadHeap(aInfo, pH); + } + else if (aInfo.iAllocator) + { + // sharing a heap + RAllocator* pA = aInfo.iAllocator; + pA->Open(); + User::SwitchAllocator(pA); + r = KErrNone; + } + return r; +} + +#endif // QT_EXPORTS_NOT_FROZEN diff --git a/src/s60main/s60main.pro b/src/s60main/s60main.pro index 664f155..8ab3bd3 100644 --- a/src/s60main/s60main.pro +++ b/src/s60main/s60main.pro @@ -31,6 +31,9 @@ symbian { # against GCCE apps, so remove it MMP_RULES -= $$MMP_RULES_DONT_EXPORT_ALL_CLASS_IMPEDIMENTA linux-armcc:QMAKE_CXXFLAGS *= --export_all_vtbl + + # Flag if exports are not frozen to avoid lookup of qtcore allocator creation function by ordinal + contains(CONFIG, def_files_disabled): DEFINES += QT_EXPORTS_NOT_FROZEN } else { error("$$_FILE_ is intended only for Symbian!") } -- cgit v0.12 From 062b8cfa9b1ece569fe2a8ae18230c862ca6f857 Mon Sep 17 00:00:00 2001 From: Jerome Pasion Date: Mon, 11 Oct 2010 15:14:56 +0200 Subject: Moved the property documentation to its proper location. Task-number: QTBUG-14351 Reviewed-by: David Boddie --- src/gui/graphicsview/qgraphicswidget.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 1bfe266..4a733be 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -750,6 +750,22 @@ QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) c /*! \property QGraphicsWidget::layout \brief The layout of the widget + + Any existing layout manager is deleted before the new layout is assigned. If + \a layout is 0, the widget is left without a layout. Existing subwidgets' + geometries will remain unaffected. + + QGraphicsWidget takes ownership of \a layout. + + All widgets that are currently managed by \a layout or all of its + sublayouts, are automatically reparented to this item. The layout is then + invalidated, and the child widget geometries are adjusted according to + this item's geometry() and contentsMargins(). Children who are not + explicitly managed by \a layout remain unaffected by the layout after + it has been assigned to this widget. + + If no layout is currently managing this widget, layout() will return 0. + */ /*! -- cgit v0.12 From 0644896a666b1215dad9c04d73dd44f03554060d Mon Sep 17 00:00:00 2001 From: Jerome Pasion Date: Mon, 11 Oct 2010 16:00:22 +0200 Subject: Added the default format of QTime::toString(). Task-number: QTBUG-13710 Reviewed-by: David Boddie --- src/corelib/tools/qdatetime.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index ab7530d..c252e64 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -1630,6 +1630,7 @@ QString QTime::toString(Qt::DateFormat format) const \endtable If the datetime is invalid, an empty string will be returned. + If \a format is empty, the default format "hh:mm:ss" is used. \sa QDate::toString() QDateTime::toString() */ -- cgit v0.12 From ef7df41b11c4f5e026b85ca9b02a9c05b427a301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 8 Oct 2010 15:33:25 +0200 Subject: Compile fix for OpenVG without VGFont. ShivaVG doesn't have VGFont support for example. Reviewed-by: Jason Barron --- src/openvg/qpaintengine_vg.cpp | 9 ++------- src/openvg/qvg_p.h | 5 +++++ src/openvg/qvgfontglyphcache_p.h | 6 ++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index f6d2435..ce9d11a 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -61,11 +61,6 @@ QT_BEGIN_NAMESPACE -// vgDrawGlyphs() only exists in OpenVG 1.1 and higher. -#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_DRAW_GLYPHS) -#define QVG_NO_DRAW_GLYPHS 1 -#endif - // vgRenderToMask() only exists in OpenVG 1.1 and higher. // Also, disable masking completely if we are using the scissor to clip. #if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_RENDER_TO_MASK) @@ -75,11 +70,11 @@ QT_BEGIN_NAMESPACE #define QVG_NO_RENDER_TO_MASK 1 #endif -#if !defined(QVG_NO_DRAW_GLYPHS) - // use the same rounding as in qrasterizer.cpp (6 bit fixed point) static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; +#if !defined(QVG_NO_DRAW_GLYPHS) + Q_DECL_IMPORT extern int qt_defaultDpiX(); Q_DECL_IMPORT extern int qt_defaultDpiY(); diff --git a/src/openvg/qvg_p.h b/src/openvg/qvg_p.h index 51abbee..94d1eae 100644 --- a/src/openvg/qvg_p.h +++ b/src/openvg/qvg_p.h @@ -55,6 +55,11 @@ // We mean it. // +// vgDrawGlyphs() only exists in OpenVG 1.1 and higher. +#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_DRAW_GLYPHS) +#define QVG_NO_DRAW_GLYPHS 1 +#endif + #include #if !defined(QT_NO_EGL) diff --git a/src/openvg/qvgfontglyphcache_p.h b/src/openvg/qvgfontglyphcache_p.h index b32a873..8bcdcc7 100644 --- a/src/openvg/qvgfontglyphcache_p.h +++ b/src/openvg/qvgfontglyphcache_p.h @@ -56,10 +56,14 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QVGPaintEnginePrivate; +#ifndef QVG_NO_DRAW_GLYPHS + class QVGFontGlyphCache { public: @@ -90,6 +94,8 @@ public: }; #endif +#endif + QT_END_NAMESPACE #endif // QVGFONTGLYPHCACHE_H -- cgit v0.12 From 1113344ece060bb7386ea540becbf59f9c8320ea Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Fri, 8 Oct 2010 11:39:49 +0200 Subject: Crash fix when using the runtime graphics system on Symbian. If QWidget::destroy() is called (perhaps by setParent) then the window surface is deleted by the destructor of QSymbianControl instead of in the "normal" place which is ~QWidget(). This means that we should not attempt to use the RWindow in the window surface because it is in the process of being destroyed. Reviewed-by: Jani Hautakangas --- src/gui/painting/qwindowsurface_s60.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index 8bac1f5..ea19fcd 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -101,9 +101,11 @@ QS60WindowSurface::~QS60WindowSurface() // Issue empty redraw to clear the UI surface QWidget *w = window(); - RWindow *const window = static_cast(w->winId()->DrawableWindow()); - window->BeginRedraw(); - window->EndRedraw(); + if (w->testAttribute(Qt::WA_WState_Created)) { + RWindow *const window = static_cast(w->winId()->DrawableWindow()); + window->BeginRedraw(); + window->EndRedraw(); + } } } #endif -- cgit v0.12 From edddadd88950f22f6d813e50acdcf2711d3d5a84 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Tue, 12 Oct 2010 10:58:11 +0200 Subject: Add support for Qt::WA_TranslucentBackground with OpenVG on Symbian^3 S^3 does not have a client side API to support semi-transparent EGL surfaces so if this flag is enabled for a particular widget, then we should return a raster surface instead of a VG surface. Raster surfaces can still be semi-transparent but will be slower to render to. Task-number: QTBUG-14400 Reviewed-by: Jani Hautakangas Reviewed-by: Gareth Stockwell Reviewed-by: Sami Merila --- src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp index 2c7c0b7..9674233 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp @@ -42,6 +42,9 @@ #include "qgraphicssystem_vg_p.h" #include #include +#if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) +#include +#endif QT_BEGIN_NAMESPACE @@ -64,6 +67,11 @@ QPixmapData *QVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) co QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const { +#if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) + QWidgetPrivate *d = qt_widget_private(widget); + if (!d->isOpaque && widget->testAttribute(Qt::WA_TranslucentBackground)) + return d->createDefaultWindowSurface_sys(); +#endif return new QVGWindowSurface(widget); } -- cgit v0.12 From 7cd0a90344d340f22b6b2d3afeef092dbaf2cd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 12 Oct 2010 12:54:15 +0200 Subject: Revert "Don't define highp/mediump/lowp if desktop GL has them" This reverts commit 6155050f68cc86c445552da61a5f240c16f5e2cd. The GL_ARB_ES2_compatibility extension does not mention the lowp, mediump or highp keywords. Task-number: QTBUG-14384 Reviewed-by: Samuel Reviewed-by: Prasanth --- dist/changes-4.6.4 | 4 +--- src/opengl/qgl.cpp | 3 --- src/opengl/qgl_p.h | 3 +-- src/opengl/qglshaderprogram.cpp | 10 ++-------- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/dist/changes-4.6.4 b/dist/changes-4.6.4 index 389aa3a..3949b9a 100644 --- a/dist/changes-4.6.4 +++ b/dist/changes-4.6.4 @@ -66,8 +66,6 @@ QtOpenGL - QGLShaderProgram * [QTBUG-12478] Don't resolve GLSL extensions if no shaders. * [QTBUG-12591] setUniformValue(QSize) was setting (w,w) not (w,h). - * [QTBUG-12862] Don't #define highp/mediump/lowp if the desktop OpenGL - implementation has the GL_ARB_ES2_compatibility extension. * [QTBUG-12554] Wrong OpenGLVersionFlags on OpenGL 4.0 systems. QtScript @@ -109,7 +107,7 @@ Third party components Qt for Unix (X11 and Mac OS X) ------------------------------ - - + - Qt for Linux/X11 ---------------- diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 9e74e04..7f25887 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -5264,8 +5264,6 @@ QGLExtensions::Extensions QGLExtensions::currentContextExtensions() glExtensions |= FragmentShader; if (extensions.match("GL_ARB_shader_objects")) glExtensions |= FragmentShader; - if (extensions.match("GL_ARB_ES2_compatibility")) - glExtensions |= ES2Compatibility; if (extensions.match("GL_ARB_texture_mirrored_repeat")) glExtensions |= MirroredRepeat; if (extensions.match("GL_EXT_framebuffer_object")) @@ -5286,7 +5284,6 @@ QGLExtensions::Extensions QGLExtensions::currentContextExtensions() glExtensions |= FramebufferObject; glExtensions |= GenerateMipmap; glExtensions |= FragmentShader; - glExtensions |= ES2Compatibility; #endif #if defined(QT_OPENGL_ES_1) if (extensions.match("GL_OES_framebuffer_object")) diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 623eeaf..387c8f7 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -284,8 +284,7 @@ public: DDSTextureCompression = 0x00008000, ETC1TextureCompression = 0x00010000, PVRTCTextureCompression = 0x00020000, - FragmentShader = 0x00040000, - ES2Compatibility = 0x00080000 + FragmentShader = 0x00040000 }; Q_DECLARE_FLAGS(Extensions, Extension) diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index bc1c009..74382b0 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -97,10 +97,6 @@ QT_BEGIN_NAMESPACE to just features that are present in GLSL/ES, and avoid standard variable names that only work on the desktop. - If the \c{GL_ARB_ES2_compatibility} extension is present, - then the above prefix is not added because the desktop OpenGL - implementation supports precision qualifiers. - \section1 Simple shader example \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 1 @@ -398,10 +394,8 @@ bool QGLShader::compileSourceCode(const char *source) srclen.append(GLint(headerLen)); } #ifdef QGL_DEFINE_QUALIFIERS - if (!(QGLExtensions::glExtensions() & QGLExtensions::ES2Compatibility)) { - src.append(qualifierDefines); - srclen.append(GLint(sizeof(qualifierDefines) - 1)); - } + src.append(qualifierDefines); + srclen.append(GLint(sizeof(qualifierDefines) - 1)); #endif #ifdef QGL_REDEFINE_HIGHP if (d->shaderType == Fragment) { -- cgit v0.12 From 087414e3ee4dd4c9f8f13c5a9eb69c5f70fb3d59 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 12 Oct 2010 17:19:46 +0200 Subject: Doc - remove disclaimer Task-number: QTBUG-14407 Reviewed-by: Friedemann Kleint Reviewed-by: Henry Haverinen --- doc/src/porting/qt4-designer.qdoc | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/doc/src/porting/qt4-designer.qdoc b/doc/src/porting/qt4-designer.qdoc index fff3e89..ea5147a 100644 --- a/doc/src/porting/qt4-designer.qdoc +++ b/doc/src/porting/qt4-designer.qdoc @@ -36,18 +36,14 @@ \QD has been completely re-written based on our experience with the previous versions of the product for Qt 3. One of the main new - ideas behind this new version is to release the application as a + ideas is to release the application as a collection of interchangeable components that include the property editor, the widget box, and other useful tools for creating graphical user interfaces with Qt. These components can either be used together in the \QD application, or independently integrated into other systems. As a result, certain features such as the project editor and code editor have been removed from the version - included with this release. - - The current version of \QD is near feature complete and can be used for - many tasks. However, it is still under continuous development. This - document will explain what is already in place. + included with release 4. See also the \l{Qt Designer Manual}. @@ -128,7 +124,7 @@ \row \i \bold{Widget Editing Mode} - The new \QD allows widgets to be dropped into existing layouts on + \QD now allows widgets to be dropped into existing layouts on the form. Previously, it was necessary to break layouts in order to add new widgets to them. @@ -189,7 +185,7 @@ \row \i \bold{The Resource Editor} - The new \QD fully supports The Qt Resource System, and provide the + \QD now fully supports The Qt Resource System, and provides the Resource Editor to help designers and developers manage the resources that are needed by their applications. @@ -210,8 +206,8 @@ \i \inlineimage designer-action-editor.png \i \bold{The Action Editor} - With the release of Qt 4.1, \QD introduces the Action Editor - simplifying the management of actions when creating main window + With the release of Qt 4.1, \QD the Action Editor was introduced + to simplify the management of actions when creating main window applications. When creating a main window, you can add a menu bar and toolbars @@ -261,7 +257,7 @@ \section1 Run-Time Support for Forms - With the Qt 4.1 release, the new QtUiTools module is introduced to + With the Qt 4.1 release, the new QtUiTools module was introduced to provide classes handling forms created with \QD. Currently the module only contains the QUiLoader class. -- cgit v0.12 From 1eb194d0b29e1bb3c5bafe711cea2c116cb2ea16 Mon Sep 17 00:00:00 2001 From: Morten Engvoldsen Date: Wed, 13 Oct 2010 09:48:18 +0200 Subject: Doc: adjusting the search field width --- doc/src/template/style/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/template/style/style.css b/doc/src/template/style/style.css index ec0202a..12d297d 100755 --- a/doc/src/template/style/style.css +++ b/doc/src/template/style/style.css @@ -650,7 +650,7 @@ margin-top: 5px; _margin: 0 0 0 -20px; padding: 10px; - width: 220px; + width: 30%; _width: 196px; height: 250px; overflow: auto; -- cgit v0.12