diff options
Diffstat (limited to 'src/platformsupport')
15 files changed, 1196 insertions, 122 deletions
diff --git a/src/platformsupport/clipboard/clipboard.pri b/src/platformsupport/clipboard/clipboard.pri new file mode 100644 index 0000000000..2532430f1e --- /dev/null +++ b/src/platformsupport/clipboard/clipboard.pri @@ -0,0 +1,5 @@ +mac { + HEADERS += $$PWD/qmacmime_p.h + OBJECTIVE_SOURCES += $$PWD/qmacmime.mm +} + diff --git a/src/platformsupport/clipboard/qmacmime.mm b/src/platformsupport/clipboard/qmacmime.mm new file mode 100644 index 0000000000..93d897503b --- /dev/null +++ b/src/platformsupport/clipboard/qmacmime.mm @@ -0,0 +1,844 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacmime_p.h" +#include "qguiapplication.h" + +QT_BEGIN_NAMESPACE + +typedef QList<QMacInternalPasteboardMime*> MimeList; +Q_GLOBAL_STATIC(MimeList, globalMimeList) +Q_GLOBAL_STATIC(QStringList, globalDraggedTypesList) + +void qt_mac_addToGlobalMimeList(QMacInternalPasteboardMime *macMime) +{ + // globalMimeList is in decreasing priority order. Recently added + // converters take prioity over previously added converters: prepend + // to the list. + globalMimeList()->prepend(macMime); +} + +void qt_mac_removeFromGlobalMimeList(QMacInternalPasteboardMime *macMime) +{ + if (!QGuiApplication::closingDown()) + globalMimeList()->removeAll(macMime); +} + +/*! + \fn void qRegisterDraggedTypes(const QStringList &types) + \relates QMacPasteboardMime + + Registers the given \a types as custom pasteboard types. + + This function should be called to enable the Drag and Drop events + for custom pasteboard types on Cocoa implementations. This is required + in addition to a QMacPasteboardMime subclass implementation. By default + drag and drop is enabled for all standard pasteboard types. + + \sa QMacPasteboardMime +*/ +void qt_mac_registerDraggedTypes(const QStringList &types) +{ + (*globalDraggedTypesList()) += types; +} + +const QStringList& qt_mac_enabledDraggedTypes() +{ + return (*globalDraggedTypesList()); +} + +/***************************************************************************** + QDnD debug facilities + *****************************************************************************/ +//#define DEBUG_MIME_MAPS + +/*! + \class QMacPasteboardMime + \brief The QMacPasteboardMime class converts between a MIME type and a + \l{http://developer.apple.com/macosx/uniformtypeidentifiers.html}{Uniform + Type Identifier (UTI)} format. + \since 4.2 + + \ingroup draganddrop + \inmodule QtWidgets + + Qt's drag and drop and clipboard facilities use the MIME + standard. On X11, this maps trivially to the Xdnd protocol. On + Mac, although some applications use MIME to describe clipboard + contents, it is more common to use Apple's UTI format. + + QMacPasteboardMime's role is to bridge the gap between MIME and UTI; + By subclasses this class, one can extend Qt's drag and drop + and clipboard handling to convert to and from unsupported, or proprietary, UTI formats. + + A subclass of QMacPasteboardMime will automatically be registered, and active, upon instantiation. + + Qt has predefined support for the following UTIs: + \list + \i public.utf8-plain-text - converts to "text/plain" + \i public.utf16-plain-text - converts to "text/plain" + \i public.html - converts to "text/html" + \i public.url - converts to "text/uri-list" + \i public.file-url - converts to "text/uri-list" + \i public.tiff - converts to "application/x-qt-image" + \i public.vcard - converts to "text/plain" + \i com.apple.traditional-mac-plain-text - converts to "text/plain" + \i com.apple.pict - converts to "application/x-qt-image" + \endlist + + When working with MIME data, Qt will interate through all instances of QMacPasteboardMime to + find an instance that can convert to, or from, a specific MIME type. It will do this by calling + canConvert() on each instance, starting with (and choosing) the last created instance first. + The actual conversions will be done by using convertToMime() and convertFromMime(). + + \note The API uses the term "flavor" in some cases. This is for backwards + compatibility reasons, and should now be understood as UTIs. +*/ + +/*! \enum QMacPasteboardMime::QMacPasteboardMimeType + \internal +*/ + +/*! + Constructs a new conversion object of type \a t, adding it to the + globally accessed list of available convertors. +*/ +QMacInternalPasteboardMime::QMacInternalPasteboardMime(char t) : type(t) +{ + qt_mac_addToGlobalMimeList(this); +} + +/*! + Destroys a conversion object, removing it from the global + list of available convertors. +*/ +QMacInternalPasteboardMime::~QMacInternalPasteboardMime() +{ + qt_mac_removeFromGlobalMimeList(this); +} + +/*! + Returns the item count for the given \a mimeData +*/ +int QMacInternalPasteboardMime::count(QMimeData *mimeData) +{ + Q_UNUSED(mimeData); + return 1; +} + +class QMacPasteboardMimeAny : public QMacInternalPasteboardMime { +private: + +public: + QMacPasteboardMimeAny() : QMacInternalPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) { + } + ~QMacPasteboardMimeAny() { + } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeAny::convertorName() +{ + return QLatin1String("Any-Mime"); +} + +QString QMacPasteboardMimeAny::flavorFor(const QString &mime) +{ + // do not handle the mime type name in the drag pasteboard + if (mime == QLatin1String("application/x-qt-mime-type-name")) + return QString(); + QString ret = QLatin1String("com.trolltech.anymime.") + mime; + return ret.replace(QLatin1Char('/'), QLatin1String("--")); +} + +QString QMacPasteboardMimeAny::mimeFor(QString flav) +{ + const QString any_prefix = QLatin1String("com.trolltech.anymime."); + if (flav.size() > any_prefix.length() && flav.startsWith(any_prefix)) + return flav.mid(any_prefix.length()).replace(QLatin1String("--"), QLatin1String("/")); + return QString(); +} + +bool QMacPasteboardMimeAny::canConvert(const QString &mime, QString flav) +{ + return mimeFor(flav) == mime; +} + +QVariant QMacPasteboardMimeAny::convertToMime(const QString &mime, QList<QByteArray> data, QString) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimeAny: Cannot handle multiple member data"); + QVariant ret; + if (mime == QLatin1String("text/plain")) + ret = QString::fromUtf8(data.first()); + else + ret = data.first(); + return ret; +} + +QList<QByteArray> QMacPasteboardMimeAny::convertFromMime(const QString &mime, QVariant data, QString) +{ + QList<QByteArray> ret; + if (mime == QLatin1String("text/plain")) + ret.append(data.toString().toUtf8()); + else + ret.append(data.toByteArray()); + return ret; +} + +class QMacPasteboardMimeTypeName : public QMacInternalPasteboardMime { +private: + +public: + QMacPasteboardMimeTypeName() : QMacInternalPasteboardMime(MIME_QT_CONVERTOR|MIME_ALL) { + } + ~QMacPasteboardMimeTypeName() { + } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeTypeName::convertorName() +{ + return QLatin1String("Qt-Mime-Type"); +} + +QString QMacPasteboardMimeTypeName::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("application/x-qt-mime-type-name")) + return QLatin1String("com.trolltech.qt.MimeTypeName"); + return QString(); +} + +QString QMacPasteboardMimeTypeName::mimeFor(QString) +{ + return QString(); +} + +bool QMacPasteboardMimeTypeName::canConvert(const QString &, QString) +{ + return false; +} + +QVariant QMacPasteboardMimeTypeName::convertToMime(const QString &, QList<QByteArray>, QString) +{ + QVariant ret; + return ret; +} + +QList<QByteArray> QMacPasteboardMimeTypeName::convertFromMime(const QString &, QVariant, QString) +{ + QList<QByteArray> ret; + ret.append(QString(QLatin1String("x-qt-mime-type-name")).toUtf8()); + return ret; +} + +class QMacPasteboardMimePlainText : public QMacInternalPasteboardMime { +public: + QMacPasteboardMimePlainText() : QMacInternalPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimePlainText::convertorName() +{ + return QLatin1String("PlainText"); +} + +QString QMacPasteboardMimePlainText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/plain")) + return QLatin1String("com.apple.traditional-mac-plain-text"); + return QString(); +} + +QString QMacPasteboardMimePlainText::mimeFor(QString flav) +{ + if (flav == QLatin1String("com.apple.traditional-mac-plain-text")) + return QLatin1String("text/plain"); + return QString(); +} + +bool QMacPasteboardMimePlainText::canConvert(const QString &mime, QString flav) +{ + return flavorFor(mime) == flav; +} + +QVariant QMacPasteboardMimePlainText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimePlainText: Cannot handle multiple member data"); + const QByteArray &firstData = data.first(); + QVariant ret; + if (flavor == QLatin1String("com.apple.traditional-mac-plain-text")) { + return QString::fromCFString(CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(firstData.constData()), + firstData.size(), CFStringGetSystemEncoding(), false)); + } else { + qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); + } + return ret; +} + +QList<QByteArray> QMacPasteboardMimePlainText::convertFromMime(const QString &, QVariant data, QString flavor) +{ + QList<QByteArray> ret; + QString string = data.toString(); + if (flavor == QLatin1String("com.apple.traditional-mac-plain-text")) + ret.append(string.toLatin1()); + return ret; +} + +class QMacPasteboardMimeUnicodeText : public QMacInternalPasteboardMime { +public: + QMacPasteboardMimeUnicodeText() : QMacInternalPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeUnicodeText::convertorName() +{ + return QLatin1String("UnicodeText"); +} + +QString QMacPasteboardMimeUnicodeText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/plain")) + return QLatin1String("public.utf16-plain-text"); + int i = mime.indexOf(QLatin1String("charset=")); + if (i >= 0) { + QString cs(mime.mid(i+8).toLower()); + i = cs.indexOf(QLatin1Char(';')); + if (i>=0) + cs = cs.left(i); + if (cs == QLatin1String("system")) + return QLatin1String("public.utf8-plain-text"); + else if (cs == QLatin1String("iso-10646-ucs-2") + || cs == QLatin1String("utf16")) + return QLatin1String("public.utf16-plain-text"); + } + return QString(); +} + +QString QMacPasteboardMimeUnicodeText::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.utf16-plain-text") || flav == QLatin1String("public.utf8-plain-text")) + return QLatin1String("text/plain"); + return QString(); +} + +bool QMacPasteboardMimeUnicodeText::canConvert(const QString &mime, QString flav) +{ + return (mime == QLatin1String("text/plain") + && (flav == QLatin1String("public.utf8-plain-text") || (flav == QLatin1String("public.utf16-plain-text")))); +} + +QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, QList<QByteArray> data, QString flavor) +{ + if (data.count() > 1) + qWarning("QMacPasteboardMimeUnicodeText: Cannot handle multiple member data"); + const QByteArray &firstData = data.first(); + // I can only handle two types (system and unicode) so deal with them that way + QVariant ret; + if (flavor == QLatin1String("public.utf8-plain-text")) { + ret = QString::fromCFString(CFStringCreateWithBytes(kCFAllocatorDefault, + reinterpret_cast<const UInt8 *>(firstData.constData()), + firstData.size(), CFStringGetSystemEncoding(), false)); + } else if (flavor == QLatin1String("public.utf16-plain-text")) { + ret = QString(reinterpret_cast<const QChar *>(firstData.constData()), + firstData.size() / sizeof(QChar)); + } else { + qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); + } + return ret; +} + +QList<QByteArray> QMacPasteboardMimeUnicodeText::convertFromMime(const QString &, QVariant data, QString flavor) +{ + QList<QByteArray> ret; + QString string = data.toString(); + if (flavor == QLatin1String("public.utf8-plain-text")) + ret.append(string.toUtf8()); + else if (flavor == QLatin1String("public.utf16-plain-text")) + ret.append(QByteArray((char*)string.utf16(), string.length()*2)); + return ret; +} + +class QMacPasteboardMimeHTMLText : public QMacInternalPasteboardMime { +public: + QMacPasteboardMimeHTMLText() : QMacInternalPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeHTMLText::convertorName() +{ + return QLatin1String("HTML"); +} + +QString QMacPasteboardMimeHTMLText::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/html")) + return QLatin1String("public.html"); + return QString(); +} + +QString QMacPasteboardMimeHTMLText::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.html")) + return QLatin1String("text/html"); + return QString(); +} + +bool QMacPasteboardMimeHTMLText::canConvert(const QString &mime, QString flav) +{ + return flavorFor(mime) == flav; +} + +QVariant QMacPasteboardMimeHTMLText::convertToMime(const QString &mimeType, QList<QByteArray> data, QString flavor) +{ + if (!canConvert(mimeType, flavor)) + return QVariant(); + if (data.count() > 1) + qWarning("QMacPasteboardMimeHTMLText: Cannot handle multiple member data"); + return data.first(); +} + +QList<QByteArray> QMacPasteboardMimeHTMLText::convertFromMime(const QString &mime, QVariant data, QString flavor) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flavor)) + return ret; + ret.append(data.toByteArray()); + return ret; +} + +class QMacPasteboardMimeFileUri : public QMacInternalPasteboardMime { +public: + QMacPasteboardMimeFileUri() : QMacInternalPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); + int count(QMimeData *mimeData); +}; + +QString QMacPasteboardMimeFileUri::convertorName() +{ + return QLatin1String("FileURL"); +} + +QString QMacPasteboardMimeFileUri::flavorFor(const QString &mime) +{ + if (mime == QLatin1String("text/uri-list")) + return QLatin1String("public.file-url"); + return QString(); +} + +QString QMacPasteboardMimeFileUri::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.file-url")) + return QLatin1String("text/uri-list"); + return QString(); +} + +bool QMacPasteboardMimeFileUri::canConvert(const QString &mime, QString flav) +{ + return mime == QLatin1String("text/uri-list") && flav == QLatin1String("public.file-url"); +} + +QVariant QMacPasteboardMimeFileUri::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) +{ + if (!canConvert(mime, flav)) + return QVariant(); + QList<QVariant> ret; + for (int i = 0; i < data.size(); ++i) { + QUrl url = QUrl::fromEncoded(data.at(i)); + if (url.host().toLower() == QLatin1String("localhost")) + url.setHost(QString()); + url.setPath(url.path().normalized(QString::NormalizationForm_C)); + ret.append(url); + } + return QVariant(ret); +} + +QList<QByteArray> QMacPasteboardMimeFileUri::convertFromMime(const QString &mime, QVariant data, QString flav) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flav)) + return ret; + QList<QVariant> urls = data.toList(); + for (int i = 0; i < urls.size(); ++i) { + QUrl url = urls.at(i).toUrl(); + if (url.scheme().isEmpty()) + url.setScheme(QLatin1String("file")); + if (url.scheme().toLower() == QLatin1String("file")) { + if (url.host().isEmpty()) + url.setHost(QLatin1String("localhost")); + url.setPath(url.path().normalized(QString::NormalizationForm_D)); + } + ret.append(url.toEncoded()); + } + return ret; +} + +int QMacPasteboardMimeFileUri::count(QMimeData *mimeData) +{ + return mimeData->urls().count(); +} + +class QMacPasteboardMimeUrl : public QMacInternalPasteboardMime { +public: + QMacPasteboardMimeUrl() : QMacInternalPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeUrl::convertorName() +{ + return QLatin1String("URL"); +} + +QString QMacPasteboardMimeUrl::flavorFor(const QString &mime) +{ + if (mime.startsWith(QLatin1String("text/uri-list"))) + return QLatin1String("public.url"); + return QString(); +} + +QString QMacPasteboardMimeUrl::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.url")) + return QLatin1String("text/uri-list"); + return QString(); +} + +bool QMacPasteboardMimeUrl::canConvert(const QString &mime, QString flav) +{ + return flav == QLatin1String("public.url") + && mime == QLatin1String("text/uri-list"); +} + +QVariant QMacPasteboardMimeUrl::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) +{ + if (!canConvert(mime, flav)) + return QVariant(); + + QList<QVariant> ret; + for (int i=0; i<data.size(); ++i) { + QUrl url = QUrl::fromEncoded(data.at(i)); + if (url.host().toLower() == QLatin1String("localhost")) + url.setHost(QString()); + url.setPath(url.path().normalized(QString::NormalizationForm_C)); + ret.append(url); + } + return QVariant(ret); +} + +QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QVariant data, QString flav) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flav)) + return ret; + + QList<QVariant> urls = data.toList(); + for (int i=0; i<urls.size(); ++i) { + QUrl url = urls.at(i).toUrl(); + if (url.scheme().isEmpty()) + url.setScheme(QLatin1String("file")); + if (url.scheme().toLower() == QLatin1String("file")) { + if (url.host().isEmpty()) + url.setHost(QLatin1String("localhost")); + url.setPath(url.path().normalized(QString::NormalizationForm_D)); + } + ret.append(url.toEncoded()); + } + return ret; +} + +class QMacPasteboardMimeVCard : public QMacInternalPasteboardMime +{ +public: + QMacPasteboardMimeVCard() : QMacInternalPasteboardMime(MIME_ALL){ } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeVCard::convertorName() +{ + return QLatin1String("VCard"); +} + +bool QMacPasteboardMimeVCard::canConvert(const QString &mime, QString flav) +{ + return mimeFor(flav) == mime; +} + +QString QMacPasteboardMimeVCard::flavorFor(const QString &mime) +{ + if (mime.startsWith(QLatin1String("text/plain"))) + return QLatin1String("public.vcard"); + return QString(); +} + +QString QMacPasteboardMimeVCard::mimeFor(QString flav) +{ + if (flav == QLatin1String("public.vcard")) + return QLatin1String("text/plain"); + return QString(); +} + +QVariant QMacPasteboardMimeVCard::convertToMime(const QString &mime, QList<QByteArray> data, QString) +{ + QByteArray cards; + if (mime == QLatin1String("text/plain")) { + for (int i=0; i<data.size(); ++i) + cards += data[i]; + } + return QVariant(cards); +} + +QList<QByteArray> QMacPasteboardMimeVCard::convertFromMime(const QString &mime, QVariant data, QString) +{ + QList<QByteArray> ret; + if (mime == QLatin1String("text/plain")) + ret.append(data.toString().toUtf8()); + return ret; +} + +/*! + \internal + + This is an internal function. +*/ +void QMacInternalPasteboardMime::initializeMimeTypes() +{ + if (globalMimeList()->isEmpty()) { + // Create QMacPasteboardMimeAny first to put it at the end of globalMimeList + // with lowest priority. (the constructor prepends to the list) + new QMacPasteboardMimeAny; + + //standard types that we wrap + new QMacPasteboardMimeUnicodeText; + new QMacPasteboardMimePlainText; + new QMacPasteboardMimeHTMLText; + new QMacPasteboardMimeFileUri; + new QMacPasteboardMimeUrl; + new QMacPasteboardMimeTypeName; + new QMacPasteboardMimeVCard; + } +} + +/*! + \internal +*/ +void QMacInternalPasteboardMime::destroyMimeTypes() +{ + MimeList *mimes = globalMimeList(); + while (!mimes->isEmpty()) + delete mimes->takeFirst(); +} + +/*! + Returns the most-recently created QMacPasteboardMime of type \a t that can convert + between the \a mime and \a flav formats. Returns 0 if no such convertor + exists. +*/ +QMacInternalPasteboardMime* +QMacInternalPasteboardMime::convertor(uchar t, const QString &mime, QString flav) +{ + MimeList *mimes = globalMimeList(); + for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) { +#ifdef DEBUG_MIME_MAPS + qDebug("QMacPasteboardMime::convertor: seeing if %s (%d) can convert %s to %d[%c%c%c%c] [%d]", + (*it)->convertorName().toLatin1().constData(), + (*it)->type & t, mime.toLatin1().constData(), + flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF, + (*it)->canConvert(mime,flav)); + for (int i = 0; i < (*it)->countFlavors(); ++i) { + int f = (*it)->flavor(i); + qDebug(" %d) %d[%c%c%c%c] [%s]", i, f, + (f >> 24) & 0xFF, (f >> 16) & 0xFF, (f >> 8) & 0xFF, (f) & 0xFF, + (*it)->convertorName().toLatin1().constData()); + } +#endif + if (((*it)->type & t) && (*it)->canConvert(mime, flav)) + return (*it); + } + return 0; +} +/*! + Returns a MIME type of type \a t for \a flav, or 0 if none exists. +*/ +QString QMacInternalPasteboardMime::flavorToMime(uchar t, QString flav) +{ + MimeList *mimes = globalMimeList(); + for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) { +#ifdef DEBUG_MIME_MAPS + qDebug("QMacMIme::flavorToMime: attempting %s (%d) for flavor %d[%c%c%c%c] [%s]", + (*it)->convertorName().toLatin1().constData(), + (*it)->type & t, flav, (flav >> 24) & 0xFF, (flav >> 16) & 0xFF, (flav >> 8) & 0xFF, (flav) & 0xFF, + (*it)->mimeFor(flav).toLatin1().constData()); + +#endif + if ((*it)->type & t) { + QString mimeType = (*it)->mimeFor(flav); + if (!mimeType.isNull()) + return mimeType; + } + } + return QString(); +} + +/*! + Returns a list of all currently defined QMacPasteboardMime objects of type \a t. +*/ +QList<QMacInternalPasteboardMime*> QMacInternalPasteboardMime::all(uchar t) +{ + MimeList ret; + MimeList *mimes = globalMimeList(); + for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) { + if ((*it)->type & t) + ret.append((*it)); + } + return ret; +} + + +/*! + \fn QString QMacPasteboardMime::convertorName() + + Returns a name for the convertor. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn bool QMacPasteboardMime::canConvert(const QString &mime, QString flav) + + Returns \c true if the convertor can convert (both ways) between + \a mime and \a flav; otherwise returns \c false. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QString QMacPasteboardMime::mimeFor(QString flav) + + Returns the MIME UTI used for Mac flavor \a flav, or 0 if this + convertor does not support \a flav. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QString QMacPasteboardMime::flavorFor(const QString &mime) + + Returns the Mac UTI used for MIME type \a mime, or 0 if this + convertor does not support \a mime. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QVariant QMacPasteboardMime::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) + + Returns \a data converted from Mac UTI \a flav to MIME type \a + mime. + + Note that Mac flavors must all be self-terminating. The input \a + data may contain trailing data. + + All subclasses must reimplement this pure virtual function. +*/ + +/*! + \fn QList<QByteArray> QMacPasteboardMime::convertFromMime(const QString &mime, QVariant data, QString flav) + + Returns \a data converted from MIME type \a mime + to Mac UTI \a flav. + + Note that Mac flavors must all be self-terminating. The return + value may contain trailing data. + + All subclasses must reimplement this pure virtual function. +*/ + +QT_END_NAMESPACE diff --git a/src/platformsupport/clipboard/qmacmime_p.h b/src/platformsupport/clipboard/qmacmime_p.h new file mode 100644 index 0000000000..0802987fab --- /dev/null +++ b/src/platformsupport/clipboard/qmacmime_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACMIME_H +#define QMACMIME_H + +#include <QtCore> + +#include <CoreFoundation/CoreFoundation.h> + +QT_BEGIN_NAMESPACE + +// Duplicate of QMacPasteboardMime in QtMacExtras. Keep in sync! +class QMacInternalPasteboardMime { + char type; +public: + enum QMacPasteboardMimeType { MIME_DND=0x01, + MIME_CLIP=0x02, + MIME_QT_CONVERTOR=0x04, + MIME_QT3_CONVERTOR=0x08, + MIME_ALL=MIME_DND|MIME_CLIP + }; + explicit QMacInternalPasteboardMime(char); + virtual ~QMacInternalPasteboardMime(); + + static void initializeMimeTypes(); + static void destroyMimeTypes(); + + static QList<QMacInternalPasteboardMime*> all(uchar); + static QMacInternalPasteboardMime *convertor(uchar, const QString &mime, QString flav); + static QString flavorToMime(uchar, QString flav); + + virtual QString convertorName() = 0; + + virtual bool canConvert(const QString &mime, QString flav) = 0; + virtual QString mimeFor(QString flav) = 0; + virtual QString flavorFor(const QString &mime) = 0; + virtual QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav) = 0; + virtual QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav) = 0; + virtual int count(QMimeData *mimeData); +}; + +void qt_mac_addToGlobalMimeList(QMacInternalPasteboardMime *macMime); +void qt_mac_removeFromGlobalMimeList(QMacInternalPasteboardMime *macMime); +void qt_mac_registerDraggedTypes(const QStringList &types); +const QStringList& qt_mac_enabledDraggedTypes(); + +QT_END_NAMESPACE + +#endif + diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index a36d0b83d4..7cf1f88b02 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include <QByteArray> -#include <QOpenGLFunctions> +#include <QOpenGLContext> #ifdef Q_OS_LINUX #include <sys/ioctl.h> @@ -50,6 +50,10 @@ #include "qeglconvenience_p.h" +#ifndef EGL_OPENGL_ES3_BIT_KHR +#define EGL_OPENGL_ES3_BIT_KHR 0x0040 +#endif + QT_BEGIN_NAMESPACE QVector<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format) @@ -239,16 +243,19 @@ EGLConfig QEglConfigChooser::chooseConfig() configureAttributes.append(surfaceType()); configureAttributes.append(EGL_RENDERABLE_TYPE); + bool needsES2Plus = false; switch (m_format.renderableType()) { case QSurfaceFormat::OpenVG: configureAttributes.append(EGL_OPENVG_BIT); break; #ifdef EGL_VERSION_1_4 case QSurfaceFormat::DefaultRenderableType: - if (!QOpenGLFunctions::isES()) +#ifndef QT_NO_OPENGL + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) configureAttributes.append(EGL_OPENGL_BIT); else - configureAttributes.append(EGL_OPENGL_ES2_BIT); +#endif // QT_NO_OPENGL + needsES2Plus = true; break; case QSurfaceFormat::OpenGL: configureAttributes.append(EGL_OPENGL_BIT); @@ -261,9 +268,15 @@ EGLConfig QEglConfigChooser::chooseConfig() } // fall through default: - configureAttributes.append(EGL_OPENGL_ES2_BIT); + needsES2Plus = true; break; } + if (needsES2Plus) { + if (m_format.majorVersion() >= 3 && q_hasEglExtension(display(), "EGL_KHR_create_context")) + configureAttributes.append(EGL_OPENGL_ES3_BIT_KHR); + else + configureAttributes.append(EGL_OPENGL_ES2_BIT); + } configureAttributes.append(EGL_NONE); EGLConfig cfg = 0; @@ -361,7 +374,9 @@ QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config, && (renderableType & EGL_OPENGL_BIT)) format.setRenderableType(QSurfaceFormat::OpenGL); else if (referenceFormat.renderableType() == QSurfaceFormat::DefaultRenderableType - && !QOpenGLFunctions::isES() +#ifndef QT_NO_OPENGL + && QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL +#endif && (renderableType & EGL_OPENGL_BIT)) format.setRenderableType(QSurfaceFormat::OpenGL); #endif diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 3a34748fc7..9c3b9b539c 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -41,8 +41,9 @@ #include "qeglplatformcontext_p.h" #include "qeglconvenience_p.h" +#include "qeglpbuffer_p.h" #include <qpa/qplatformwindow.h> -#include <QtGui/QOpenGLFunctions> +#include <QOpenGLContext> QT_BEGIN_NAMESPACE @@ -63,32 +64,50 @@ QT_BEGIN_NAMESPACE surface). Other than that, no further customization is necessary. */ -static inline void bindApi(const QSurfaceFormat &format) -{ - switch (format.renderableType()) { - case QSurfaceFormat::OpenVG: - eglBindAPI(EGL_OPENVG_API); - break; -#ifdef EGL_VERSION_1_4 - case QSurfaceFormat::DefaultRenderableType: - if (!QOpenGLFunctions::isES()) - eglBindAPI(EGL_OPENGL_API); - else - eglBindAPI(EGL_OPENGL_ES_API); - break; - case QSurfaceFormat::OpenGL: - eglBindAPI(EGL_OPENGL_API); - break; +// Constants from EGL_KHR_create_context +#ifndef EGL_CONTEXT_MINOR_VERSION_KHR +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#endif +#ifndef EGL_CONTEXT_FLAGS_KHR +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#endif +#ifndef EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#endif +#ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#endif +#ifndef EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#endif +#ifndef EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#endif +#ifndef EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 #endif - case QSurfaceFormat::OpenGLES: - default: - eglBindAPI(EGL_OPENGL_ES_API); - break; - } -} -QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLenum eglApi) +// Constants for OpenGL which are not available in the ES headers. +#ifndef GL_CONTEXT_FLAGS +#define GL_CONTEXT_FLAGS 0x821E +#endif +#ifndef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 +#endif +#ifndef GL_CONTEXT_FLAG_DEBUG_BIT +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#endif +#ifndef GL_CONTEXT_PROFILE_MASK +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#endif +#ifndef GL_CONTEXT_CORE_PROFILE_BIT +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#endif +#ifndef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#endif + +QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) : m_eglDisplay(display) , m_eglConfig(q_configFromGLFormat(display, format)) , m_swapInterval(-1) @@ -96,11 +115,10 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform , m_swapIntervalFromEnv(-1) { init(format, share); - Q_UNUSED(eglApi); } QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig config, EGLenum eglApi) + EGLConfig config) : m_eglDisplay(display) , m_eglConfig(config) , m_swapInterval(-1) @@ -108,32 +126,130 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform , m_swapIntervalFromEnv(-1) { init(format, share); - Q_UNUSED(eglApi); } void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share) { m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig); + // m_format now has the renderableType() resolved (it cannot be Default anymore) + // but does not yet contain version, profile, options. m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0; QVector<EGLint> contextAttrs; contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); contextAttrs.append(format.majorVersion()); + const bool hasKHRCreateContext = q_hasEglExtension(m_eglDisplay, "EGL_KHR_create_context"); + if (hasKHRCreateContext) { + contextAttrs.append(EGL_CONTEXT_MINOR_VERSION_KHR); + contextAttrs.append(format.minorVersion()); + int flags = 0; + // The debug bit is supported both for OpenGL and OpenGL ES. + if (format.testOption(QSurfaceFormat::DebugContext)) + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + // The fwdcompat bit is only for OpenGL 3.0+. + if (m_format.renderableType() == QSurfaceFormat::OpenGL + && format.majorVersion() >= 3 + && !format.testOption(QSurfaceFormat::DeprecatedFunctions)) + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + if (flags) { + contextAttrs.append(EGL_CONTEXT_FLAGS_KHR); + contextAttrs.append(flags); + } + // Profiles are OpenGL only and mandatory in 3.2+. The value is silently ignored for < 3.2. + if (m_format.renderableType() == QSurfaceFormat::OpenGL) { + contextAttrs.append(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); + contextAttrs.append(format.profile() == QSurfaceFormat::CoreProfile + ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR + : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); + } + } contextAttrs.append(EGL_NONE); - bindApi(m_format); + switch (m_format.renderableType()) { + case QSurfaceFormat::OpenVG: + m_api = EGL_OPENVG_API; + break; +#ifdef EGL_VERSION_1_4 + case QSurfaceFormat::OpenGL: + m_api = EGL_OPENGL_API; + break; +#endif // EGL_VERSION_1_4 + default: + m_api = EGL_OPENGL_ES_API; + break; + } + + eglBindAPI(m_api); m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { m_shareContext = 0; m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, 0, contextAttrs.constData()); } + + if (m_eglContext == EGL_NO_CONTEXT) { + qWarning("QEGLPlatformContext::init: eglError: %x, this: %p \n", eglGetError(), this); + return; + } + +#ifndef QT_NO_OPENGL + // Make the context current to ensure the GL version query works. This needs a surface too. + const EGLint pbufferAttributes[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_LARGEST_PBUFFER, EGL_FALSE, + EGL_NONE + }; + EGLSurface pbuffer = eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttributes); + if (pbuffer == EGL_NO_SURFACE) + return; + + if (eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) { + if (m_format.renderableType() == QSurfaceFormat::OpenGL + || m_format.renderableType() == QSurfaceFormat::OpenGLES) { + const GLubyte *s = glGetString(GL_VERSION); + if (s) { + QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); + int major, minor; + if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { + m_format.setMajorVersion(major); + m_format.setMinorVersion(minor); + } + } + m_format.setProfile(QSurfaceFormat::NoProfile); + m_format.setOptions(QSurfaceFormat::FormatOptions()); + if (m_format.renderableType() == QSurfaceFormat::OpenGL) { + // Check profile and options. + if (m_format.majorVersion() < 3) { + m_format.setOption(QSurfaceFormat::DeprecatedFunctions); + } else { + GLint value = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &value); + if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) + m_format.setOption(QSurfaceFormat::DeprecatedFunctions); + if (value & GL_CONTEXT_FLAG_DEBUG_BIT) + m_format.setOption(QSurfaceFormat::DebugContext); + if (m_format.version() >= qMakePair(3, 2)) { + value = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + if (value & GL_CONTEXT_CORE_PROFILE_BIT) + m_format.setProfile(QSurfaceFormat::CoreProfile); + else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + m_format.setProfile(QSurfaceFormat::CompatibilityProfile); + } + } + } + } + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + eglDestroySurface(m_eglDisplay, pbuffer); +#endif // QT_NO_OPENGL } bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface) { Q_ASSERT(surface->surface()->supportsOpenGL()); - bindApi(m_format); + eglBindAPI(m_api); EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface); @@ -201,7 +317,7 @@ QEGLPlatformContext::~QEGLPlatformContext() void QEGLPlatformContext::doneCurrent() { - bindApi(m_format); + eglBindAPI(m_api); bool ok = eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!ok) qWarning("QEGLPlatformContext::doneCurrent(): eglError: %d, this: %p \n", eglGetError(), this); @@ -209,7 +325,7 @@ void QEGLPlatformContext::doneCurrent() void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface) { - bindApi(m_format); + eglBindAPI(m_api); EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface); bool ok = eglSwapBuffers(m_eglDisplay, eglSurface); if (!ok) @@ -218,7 +334,7 @@ void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface) void (*QEGLPlatformContext::getProcAddress(const QByteArray &procName)) () { - bindApi(m_format); + eglBindAPI(m_api); return eglGetProcAddress(procName.constData()); } diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index d62082faa2..714633c3bc 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -51,10 +51,9 @@ QT_BEGIN_NAMESPACE class QEGLPlatformContext : public QPlatformOpenGLContext { public: + QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLenum eglApi = EGL_OPENGL_ES_API); - QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, - EGLConfig config, EGLenum eglApi = EGL_OPENGL_ES_API); + EGLConfig config); ~QEGLPlatformContext(); bool makeCurrent(QPlatformSurface *surface); @@ -81,6 +80,7 @@ private: EGLDisplay m_eglDisplay; EGLConfig m_eglConfig; QSurfaceFormat m_format; + EGLenum m_api; int m_swapInterval; bool m_swapIntervalEnvChecked; int m_swapIntervalFromEnv; diff --git a/src/platformsupport/eglconvenience/qeglplatformcursor_p.h b/src/platformsupport/eglconvenience/qeglplatformcursor_p.h index d1402d1457..c9ff9a1198 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcursor_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcursor_p.h @@ -117,7 +117,7 @@ private: CursorAtlas() : cursorsPerRow(0), texture(0), cursorWidth(0), cursorHeight(0) { } int cursorsPerRow; uint texture; - int width, height; // width and height of the the atlas + int width, height; // width and height of the atlas int cursorWidth, cursorHeight; // width and height of cursors inside the atlas QList<QPoint> hotSpots; QImage image; // valid until it's uploaded diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp index a961035e22..b48f993436 100644 --- a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp @@ -106,9 +106,6 @@ QEGLPlatformIntegration::~QEGLPlatformIntegration() void QEGLPlatformIntegration::initialize() { - if (!eglBindAPI(EGL_OPENGL_ES_API)) - qFatal("Could not bind GL_ES API"); - m_display = eglGetDisplay(nativeDisplay()); if (m_display == EGL_NO_DISPLAY) qFatal("Could not open egl display"); diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm index 1e15a9f466..5e311c99b1 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm @@ -469,7 +469,7 @@ bool QEventDispatcherCoreFoundation::hasPendingEvents() // assume that if the run-loop is currently blocking and waiting for a // source to signal then there are no system-events pending. If this // function is called from the main thread then the second clause - // of the condition will always be true, as the the run loop is + // of the condition will always be true, as the run loop is // never waiting in that case. The function would be more aptly named // 'maybeHasPendingEvents' in our case. diff --git a/src/platformsupport/fbconvenience/qfbwindow_p.h b/src/platformsupport/fbconvenience/qfbwindow_p.h index 5ad921b0d7..a2e0785c96 100644 --- a/src/platformsupport/fbconvenience/qfbwindow_p.h +++ b/src/platformsupport/fbconvenience/qfbwindow_p.h @@ -55,17 +55,17 @@ public: QFbWindow(QWindow *window); ~QFbWindow(); - virtual void raise(); - virtual void lower(); + void raise() Q_DECL_OVERRIDE; + void lower() Q_DECL_OVERRIDE; - virtual void setGeometry(const QRect &rect); - virtual void setVisible(bool visible); + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; - virtual void setWindowState(Qt::WindowState state); - virtual void setWindowFlags(Qt::WindowFlags type); - virtual Qt::WindowFlags windowFlags() const; + void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + void setWindowFlags(Qt::WindowFlags type) Q_DECL_OVERRIDE; + Qt::WindowFlags windowFlags() const; - WId winId() const { return mWindowId; } + WId winId() const Q_DECL_OVERRIDE { return mWindowId; } void setBackingStore(QFbBackingStore *store) { mBackingStore = store; } QFbBackingStore *backingStore() const { return mBackingStore; } @@ -74,6 +74,10 @@ public: virtual void repaint(const QRegion&); + void propagateSizeHints() Q_DECL_OVERRIDE { } + bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } + bool setMouseGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } + protected: friend class QFbScreen; diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 76506d12e9..afee68ebed 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -93,6 +93,7 @@ static const char *languageForWritingSystem[] = { }; enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; +#ifdef Q_OS_OSX static NSInteger languageMapSort(id obj1, id obj2, void *context) { NSArray *map1 = (NSArray *) obj1; @@ -104,6 +105,7 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context) return [languages indexOfObject: lang1] - [languages indexOfObject: lang2]; } +#endif QCoreTextFontDatabase::QCoreTextFontDatabase() { @@ -202,8 +204,8 @@ void QCoreTextFontDatabase::populateFontDatabase() void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font) { QString foundryName = QStringLiteral("CoreText"); - QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL); - QCFString styleName = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL); + QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); + QCFString styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute); QFont::Weight weight = QFont::Normal; QFont::Style style = QFont::StyleNormal; @@ -265,12 +267,6 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font) QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, true /* antialiased */, true /* scalable */, pixelSize, fixedPitch, writingSystems, (void *) font); - - // We need to map back and forth between PostScript-names and family-names for fallback list construction - CFStringRef psName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute); - psNameToFamily[QCFString::toQString((NSString *) psName)] = familyName; - familyNameToPsName[familyName] = QCFString::toQString((NSString *) psName); - CFRelease(psName); } void QCoreTextFontDatabase::releaseHandle(void *handle) @@ -350,26 +346,18 @@ QFont::StyleHint styleHintFromNSString(NSString *style) return QFont::AnyStyle; } -static QString familyNameFromPostScriptName(QHash<QString, QString> &psNameToFamily, - NSString *psName) +#ifdef Q_OS_OSX +static QString familyNameFromPostScriptName(NSString *psName) { - QString name = QCFString::toQString(psName); - if (psNameToFamily.contains(name)) - return psNameToFamily[name]; - else { - // Some of the font name in DefaultFontFallbacks.plist are hidden fonts like AquaHiraKaku, - // their family name begins with a dot, like ".AquaHiraKaku" or ".Apple Symbols Fallback", - // the only way (I've found) to get it are actually creating a CTFont with them. We only - // need to do it once though. - QCFType<CTFontRef> font = CTFontCreateWithName((CFStringRef) psName, 12.0, NULL); - if (font) { - QCFString family = CTFontCopyFamilyName(font); - psNameToFamily[name] = family; - return family; - } - return name; - } + QCFType<CTFontDescriptorRef> fontDescriptor = (CTFontDescriptorRef) CTFontDescriptorCreateWithNameAndSize((CFStringRef)psName, 12.0); + QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute); + QString name = QCFString::toQString(familyName); + if (name.isEmpty()) + qWarning() << "QCoreTextFontDatabase: Failed to resolve family name for PostScript name " << QCFString::toQString((CFStringRef)psName); + + return name; } +#endif QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { @@ -389,29 +377,29 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo if (fallbackLists.contains(family)) return fallbackLists.value(family); - if (!familyNameToPsName.contains(family)) - const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase(); - - QCFType<CTFontRef> font = CTFontCreateWithName(QCFString(familyNameToPsName[family]), 12.0, NULL); - if (font) { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; - - QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages); - if (cascadeList) { - QStringList fallbackList; - const int numCascades = CFArrayGetCount(cascadeList); - for (int i = 0; i < numCascades; ++i) { - CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i); - QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(fontFallback, kCTFontFamilyNameAttribute, NULL); - fallbackList.append(QCFString::toQString(fallbackFamilyName)); + QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(family)); + if (QCFType<CTFontDescriptorRef> fontDescriptor = CTFontDescriptorCreateWithAttributes(attributes)) { + if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(fontDescriptor, 12.0, 0)) { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; + + QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages); + if (cascadeList) { + QStringList fallbackList; + const int numCascades = CFArrayGetCount(cascadeList); + for (int i = 0; i < numCascades; ++i) { + CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i); + QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontFallback, kCTFontFamilyNameAttribute); + fallbackList.append(QCFString::toQString(fallbackFamilyName)); + } + fallbackLists[family] = fallbackList; } - fallbackLists[family] = fallbackList; } - } - if (fallbackLists.contains(family)) - return fallbackLists.value(family); + if (fallbackLists.contains(family)) + return fallbackLists.value(family); + } } #endif } @@ -424,9 +412,6 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo static bool didPopulateStyleFallbacks = false; if (!didPopulateStyleFallbacks) { #if defined(Q_OS_MACX) - // Ensure we have the psNameToFamily mapping set up - const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase(); - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; @@ -442,10 +427,10 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo NSArray *langs = [(NSArray *) item sortedArrayUsingFunction: languageMapSort context: languages]; for (NSArray *map in langs) - fallbackList.append(familyNameFromPostScriptName(psNameToFamily, [map objectAtIndex: 1])); + fallbackList.append(familyNameFromPostScriptName([map objectAtIndex: 1])); } else if ([item isKindOfClass: [NSString class]]) - fallbackList.append(familyNameFromPostScriptName(psNameToFamily, item)); + fallbackList.append(familyNameFromPostScriptName(item)); } if (QCoreTextFontEngine::supportsColorGlyphs()) @@ -579,7 +564,7 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData for (int i = 0; i < numFonts; ++i) { CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i)); populateFromDescriptor(fontDescriptor); - QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyLocalizedAttribute(fontDescriptor, kCTFontFamilyNameAttribute, NULL)); + QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute)); families.append(QCFString(familyName)); } } diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index 1560d36644..c6fc791503 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -72,6 +72,7 @@ public: QCoreTextFontDatabase(); ~QCoreTextFontDatabase(); void populateFontDatabase(); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; @@ -84,8 +85,6 @@ private: void populateFromDescriptor(CTFontDescriptorRef font); mutable QString defaultFontName; - mutable QHash<QString, QString> psNameToFamily; - mutable QHash<QString, QString> familyNameToPsName; void removeApplicationFonts(); diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 4fe78cb568..3c30df6efb 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -85,6 +85,7 @@ CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef) } QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) + : QFontEngine(Mac) { fontDef = def; transform = qt_transform_from_fontdef(fontDef); @@ -95,6 +96,7 @@ QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) } QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) + : QFontEngine(Mac) { fontDef = def; transform = qt_transform_from_fontdef(fontDef); @@ -192,10 +194,33 @@ void QCoreTextFontEngine::init() setUserData(QVariant::fromValue((void *)cgFont)); } +glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const +{ + int len = 0; + + QChar str[2]; + if (Q_UNLIKELY(QChar::requiresSurrogates(ucs4))) { + str[len++] = QChar(QChar::highSurrogate(ucs4)); + str[len++] = QChar(QChar::lowSurrogate(ucs4)); + } else { + str[len++] = QChar(ucs4); + } + + CGGlyph glyphIndices[2]; + + CTFontGetGlyphsForCharacters(ctfont, (const UniChar *)str, glyphIndices, len); + + return glyphIndices[0]; +} + bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { - QCFType<CFStringRef> cfstring; + Q_ASSERT(glyphs->numGlyphs >= *nglyphs); + if (*nglyphs < len) { + *nglyphs = len; + return false; + } QVarLengthArray<CGGlyph> cgGlyphs(len); CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); @@ -650,7 +675,7 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const return QFontEngine::FaceId(); } -bool QCoreTextFontEngine::canRender(const QChar *string, int len) +bool QCoreTextFontEngine::canRender(const QChar *string, int len) const { QVarLengthArray<CGGlyph> cgGlyphs(len); return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); @@ -659,16 +684,13 @@ bool QCoreTextFontEngine::canRender(const QChar *string, int len) bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const { QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0); - if (!table || !length) + if (!table) return false; CFIndex tableLength = CFDataGetLength(table); - int availableLength = *length; - *length = tableLength; - if (buffer) { - if (tableLength > availableLength) - return false; + if (buffer && int(*length) >= tableLength) CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - } + *length = tableLength; + Q_ASSERT(int(*length) > 0); return true; } diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index 1cdac820b6..b9593b983e 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -62,6 +62,7 @@ public: QCoreTextFontEngine(CGFontRef font, const QFontDef &def); ~QCoreTextFontEngine(); + virtual glyph_t glyphIndex(uint ucs4) const; virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const; @@ -78,15 +79,11 @@ public: virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags); - virtual const char *name() const { return "QCoreTextFontEngine"; } - - virtual bool canRender(const QChar *string, int len); + virtual bool canRender(const QChar *string, int len) const; virtual int synthesized() const { return synthesisFlags; } virtual bool supportsSubPixelPositions() const { return true; } - virtual Type type() const { return QFontEngine::Mac; } - void draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight); virtual FaceId faceId() const; diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index f5291ab216..5b4d2b1fb3 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -19,5 +19,6 @@ include(devicediscovery/devicediscovery.pri) include(services/services.pri) include(themes/themes.pri) include(linuxaccessibility/linuxaccessibility.pri) +include(clipboard/clipboard.pri) load(qt_module) |