<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "liblocationwrapper_p.h"

using namespace std;

QTM_BEGIN_NAMESPACE

Q_GLOBAL_STATIC(LiblocationWrapper, LocationEngine)

LiblocationWrapper *LiblocationWrapper::instance()
{
    return LocationEngine();
}

LiblocationWrapper::~LiblocationWrapper()
{
    if (locationDevice)
        g_object_unref(locationDevice);
    if (locationControl)
        g_object_unref(locationControl);
}

bool LiblocationWrapper::inited()
{
    int retval = false;
    if (!(locationState & LiblocationWrapper::Inited)) {
        g_type_init();

        locationControl = location_gpsd_control_get_default();

        if (locationControl) {
            g_object_set(G_OBJECT(locationControl),
                         "preferred-method", LOCATION_METHOD_USER_SELECTED,
                         "preferred-interval", LOCATION_INTERVAL_1S,
                         NULL);
            locationDevice =
                    (LocationGPSDevice*)g_object_new(LOCATION_TYPE_GPS_DEVICE,
                                                     NULL);

            if (locationDevice) {
                errorHandlerId =
                    g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                     G_CALLBACK(&locationError),
                                     static_cast<void*>(this));
                posChangedId =
                    g_signal_connect(G_OBJECT(locationDevice), "changed",
                                     G_CALLBACK(&locationChanged),
                                     static_cast<void*>(this));
                locationState = LiblocationWrapper::Inited;
                retval = true;
                startcounter = 0;
            }
        }
    } else {
        retval = true;
    }
    return retval;
}

void LiblocationWrapper::locationError(LocationGPSDevice *device,
                                       gint errorCode, gpointer data)
{
    Q_UNUSED(device);
    QString locationError;

    switch (errorCode) {
    case LOCATION_ERROR_USER_REJECTED_DIALOG:
        locationError = "User didn't enable requested methods";
        break;
    case LOCATION_ERROR_USER_REJECTED_SETTINGS:
        locationError = "User changed settings, which disabled location.";
        break;
    case LOCATION_ERROR_BT_GPS_NOT_AVAILABLE:
        locationError = "Problems with BT GPS";
        break;
    case LOCATION_ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
        locationError = "Requested method is not allowed in offline mode";
        break;
    case LOCATION_ERROR_SYSTEM:
        locationError = "System error.";
        break;
    default:
        locationError = "Unknown error.";
    }

    qDebug() << "Location error:" << locationError;

    LiblocationWrapper *object;
    object = (LiblocationWrapper *)data;
    emit object->error();
}

void LiblocationWrapper::locationChanged(LocationGPSDevice *device,
                                                 gpointer data)
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    QGeoSatelliteInfo satInfo;
    int satellitesInUseCount = 0;
    LiblocationWrapper *object;

    if (!data || !device) {
        return;
    }

    object = (LiblocationWrapper *)data;

    if (device) {
        if (device->fix) {
            if (device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) {
                posInfo.setTimestamp(QDateTime::fromTime_t(device->fix->time));
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
                coordinate.setLatitude(device->fix->latitude);
                coordinate.setLongitude(device->fix->longitude);
                posInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy,
                                     device->fix->eph);
                posInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy,
                                     device->fix->epv);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) {
                coordinate.setAltitude(device->fix->altitude);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_SPEED_SET) {
                posInfo.setAttribute(QGeoPositionInfo::GroundSpeed,
                                     device->fix->speed);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_CLIMB_SET) {
                posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed,
                                     device->fix->climb);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_TRACK_SET) {
                posInfo.setAttribute(QGeoPositionInfo::Direction,
                                     device->fix->track);
            }
        }

        if (device->satellites_in_view) {
            QList<QGeoSatelliteInfo> satsInView;
            QList<QGeoSatelliteInfo> satsInUse;
            unsigned int i;
            for (i=0;i<device->satellites->len;i++) {
                LocationGPSDeviceSatellite *satData =
                    (LocationGPSDeviceSatellite *)g_ptr_array_index(device->satellites,
                                                                    i);
                satInfo.setSignalStrength(satData->signal_strength);
                satInfo.setPrnNumber(satData->prn);
                satInfo.setAttribute(QGeoSatelliteInfo::Elevation,
                                     satData->elevation);
                satInfo.setAttribute(QGeoSatelliteInfo::Azimuth,
                                     satData->azimuth);

                satsInView.append(satInfo);
                if (satData->in_use) {
                    satellitesInUseCount++;
                    satsInUse.append(satInfo);
                }
            }

            if (!satsInView.isEmpty())
                object->satellitesInViewUpdated(satsInView);

            if (!satsInUse.isEmpty())
                object->satellitesInUseUpdated(satsInUse);
        }
    }

    posInfo.setCoordinate(coordinate);

    if ((device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) &&
        ((device->fix->mode == LOCATION_GPS_DEVICE_MODE_3D) ||
         (device->fix->mode == LOCATION_GPS_DEVICE_MODE_2D))) {
        object->setLocation(posInfo, true);
    } else {
        object->setLocation(posInfo, false);
    }
}

void LiblocationWrapper::setLocation(const QGeoPositionInfo &update,
                                     bool locationValid)
{
    validLastSatUpdate = locationValid;
    lastSatUpdate = update;
}

QGeoPositionInfo LiblocationWrapper::position() {
    return lastSatUpdate;
}

bool LiblocationWrapper::fixIsValid()
{
    return validLastSatUpdate;
}

QGeoPositionInfo LiblocationWrapper::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    double time;
    double latitude;
    double longitude;
    double altitude;
    double speed;
    double track;
    double climb;

    GConfItem lastKnownPositionTime("/system/nokia/location/lastknown/time");
    GConfItem lastKnownPositionLatitude("/system/nokia/location/lastknown/latitude");
    GConfItem lastKnownPositionLongitude("/system/nokia/location/lastknown/longitude");
    GConfItem lastKnownPositionAltitude("/system/nokia/location/lastknown/altitude");
    GConfItem lastKnownPositionSpeed("/system/nokia/location/lastknown/speed");
    GConfItem lastKnownPositionTrack("/system/nokia/location/lastknown/track");
    GConfItem lastKnownPositionClimb("/system/nokia/location/lastknown/climb");

    if (validLastSatUpdate)
        return lastSatUpdate;

    if (!fromSatellitePositioningMethodsOnly)
        if (validLastUpdate)
            return lastUpdate;

    time = lastKnownPositionTime.value().toDouble();
    latitude = lastKnownPositionLatitude.value().toDouble();
    longitude = lastKnownPositionLongitude.value().toDouble();
    altitude = lastKnownPositionAltitude.value().toDouble();
    speed = lastKnownPositionSpeed.value().toDouble();
    track = lastKnownPositionTrack.value().toDouble();
    climb = lastKnownPositionClimb.value().toDouble();

    if (longitude && latitude) {
        coordinate.setLongitude(longitude);
        coordinate.setLatitude(latitude);
        if (altitude) {
            coordinate.setAltitude(altitude);
        }
        posInfo.setCoordinate(coordinate);
    }

    if (speed) {
        posInfo.setAttribute(QGeoPositionInfo::GroundSpeed, speed);
    }

    if (track) {
        posInfo.setAttribute(QGeoPositionInfo::Direction, track);
    }

    if (climb) {
        posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, climb);
    }

    // Only positions with time (3D) are provided.
    if (time) {
        posInfo.setTimestamp(QDateTime::fromTime_t(time));
        return posInfo;
    }

    return QGeoPositionInfo();
}

void LiblocationWrapper::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInView = satellites;
}

void LiblocationWrapper::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInUse = satellites;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInView()
{
    return satsInView;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInUse()
{
    return satsInUse;
}

void LiblocationWrapper::start() {
    startcounter++;

    if ((locationState & LiblocationWrapper::Inited) &&
        !(locationState & LiblocationWrapper::Started)) {
        if (!errorHandlerId) {
            errorHandlerId =
                g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                 G_CALLBACK(&locationError),
                                 static_cast<void*>(this));
        }

        if (!posChangedId) {
            posChangedId =
                g_signal_connect(G_OBJECT(locationDevice), "changed",
                                 G_CALLBACK(&locationChanged),
                                 static_cast<void*>(this));
        }

        location_gpsd_control_start(locationControl);

        locationState |= LiblocationWrapper::Started;
        locationState &= ~LiblocationWrapper::Stopped;
    }
}

void LiblocationWrapper::stop() {
    startcounter--;

    if (startcounter > 0)
        return;

    if ((locationState & (LiblocationWrapper::Started |
                          LiblocationWrapper::Inited)) &&
        !(locationState & LiblocationWrapper::Stopped)) {
        if (errorHandlerId)
            g_signal_handler_disconnect(G_OBJECT(locationControl),
                                        errorHandlerId);
        if (posChangedId)
            g_signal_handler_disconnect(G_OBJECT(locationDevice),
                                        posChangedId);
        errorHandlerId = 0;
        posChangedId = 0;
        startcounter = 0;
        location_gpsd_control_stop(locationControl);

        locationState &= ~LiblocationWrapper::Started;
        locationState |= LiblocationWrapper::Stopped;
    }
}

bool LiblocationWrapper::isActive() {
    if (locationState & LiblocationWrapper::Started)
        return true;
    else
        return false;
}

#include "moc_liblocationwrapper_p.cpp"
QTM_END_NAMESPACE

<commit_msg>Fix for bug in Maemo 5 Location regarding position accuracy.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "liblocationwrapper_p.h"

using namespace std;

QTM_BEGIN_NAMESPACE

Q_GLOBAL_STATIC(LiblocationWrapper, LocationEngine)

LiblocationWrapper *LiblocationWrapper::instance()
{
    return LocationEngine();
}

LiblocationWrapper::~LiblocationWrapper()
{
    if (locationDevice)
        g_object_unref(locationDevice);
    if (locationControl)
        g_object_unref(locationControl);
}

bool LiblocationWrapper::inited()
{
    int retval = false;
    if (!(locationState & LiblocationWrapper::Inited)) {
        g_type_init();

        locationControl = location_gpsd_control_get_default();

        if (locationControl) {
            g_object_set(G_OBJECT(locationControl),
                         "preferred-method", LOCATION_METHOD_USER_SELECTED,
                         "preferred-interval", LOCATION_INTERVAL_1S,
                         NULL);
            locationDevice =
                    (LocationGPSDevice*)g_object_new(LOCATION_TYPE_GPS_DEVICE,
                                                     NULL);

            if (locationDevice) {
                errorHandlerId =
                    g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                     G_CALLBACK(&locationError),
                                     static_cast<void*>(this));
                posChangedId =
                    g_signal_connect(G_OBJECT(locationDevice), "changed",
                                     G_CALLBACK(&locationChanged),
                                     static_cast<void*>(this));
                locationState = LiblocationWrapper::Inited;
                retval = true;
                startcounter = 0;
            }
        }
    } else {
        retval = true;
    }
    return retval;
}

void LiblocationWrapper::locationError(LocationGPSDevice *device,
                                       gint errorCode, gpointer data)
{
    Q_UNUSED(device);
    QString locationError;

    switch (errorCode) {
    case LOCATION_ERROR_USER_REJECTED_DIALOG:
        locationError = "User didn't enable requested methods";
        break;
    case LOCATION_ERROR_USER_REJECTED_SETTINGS:
        locationError = "User changed settings, which disabled location.";
        break;
    case LOCATION_ERROR_BT_GPS_NOT_AVAILABLE:
        locationError = "Problems with BT GPS";
        break;
    case LOCATION_ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
        locationError = "Requested method is not allowed in offline mode";
        break;
    case LOCATION_ERROR_SYSTEM:
        locationError = "System error.";
        break;
    default:
        locationError = "Unknown error.";
    }

    qDebug() << "Location error:" << locationError;

    LiblocationWrapper *object;
    object = (LiblocationWrapper *)data;
    emit object->error();
}

void LiblocationWrapper::locationChanged(LocationGPSDevice *device,
                                                 gpointer data)
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    QGeoSatelliteInfo satInfo;
    int satellitesInUseCount = 0;
    LiblocationWrapper *object;

    if (!data || !device) {
        return;
    }

    object = (LiblocationWrapper *)data;

    if (device) {
        if (device->fix) {
            if (device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) {
                posInfo.setTimestamp(QDateTime::fromTime_t(device->fix->time));
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) {
                coordinate.setLatitude(device->fix->latitude);
                coordinate.setLongitude(device->fix->longitude);
                posInfo.setAttribute(QGeoPositionInfo::HorizontalAccuracy,
                                     device->fix->eph * 100);
                posInfo.setAttribute(QGeoPositionInfo::VerticalAccuracy,
                                     device->fix->epv);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) {
                coordinate.setAltitude(device->fix->altitude);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_SPEED_SET) {
                posInfo.setAttribute(QGeoPositionInfo::GroundSpeed,
                                     device->fix->speed);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_CLIMB_SET) {
                posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed,
                                     device->fix->climb);
            }

            if (device->fix->fields & LOCATION_GPS_DEVICE_TRACK_SET) {
                posInfo.setAttribute(QGeoPositionInfo::Direction,
                                     device->fix->track);
            }
        }

        if (device->satellites_in_view) {
            QList<QGeoSatelliteInfo> satsInView;
            QList<QGeoSatelliteInfo> satsInUse;
            unsigned int i;
            for (i=0;i<device->satellites->len;i++) {
                LocationGPSDeviceSatellite *satData =
                    (LocationGPSDeviceSatellite *)g_ptr_array_index(device->satellites,
                                                                    i);
                satInfo.setSignalStrength(satData->signal_strength);
                satInfo.setPrnNumber(satData->prn);
                satInfo.setAttribute(QGeoSatelliteInfo::Elevation,
                                     satData->elevation);
                satInfo.setAttribute(QGeoSatelliteInfo::Azimuth,
                                     satData->azimuth);

                satsInView.append(satInfo);
                if (satData->in_use) {
                    satellitesInUseCount++;
                    satsInUse.append(satInfo);
                }
            }

            if (!satsInView.isEmpty())
                object->satellitesInViewUpdated(satsInView);

            if (!satsInUse.isEmpty())
                object->satellitesInUseUpdated(satsInUse);
        }
    }

    posInfo.setCoordinate(coordinate);

    if ((device->fix->fields & LOCATION_GPS_DEVICE_TIME_SET) &&
        ((device->fix->mode == LOCATION_GPS_DEVICE_MODE_3D) ||
         (device->fix->mode == LOCATION_GPS_DEVICE_MODE_2D))) {
        object->setLocation(posInfo, true);
    } else {
        object->setLocation(posInfo, false);
    }
}

void LiblocationWrapper::setLocation(const QGeoPositionInfo &update,
                                     bool locationValid)
{
    validLastSatUpdate = locationValid;
    lastSatUpdate = update;
}

QGeoPositionInfo LiblocationWrapper::position() {
    return lastSatUpdate;
}

bool LiblocationWrapper::fixIsValid()
{
    return validLastSatUpdate;
}

QGeoPositionInfo LiblocationWrapper::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const
{
    QGeoPositionInfo posInfo;
    QGeoCoordinate coordinate;
    double time;
    double latitude;
    double longitude;
    double altitude;
    double speed;
    double track;
    double climb;

    GConfItem lastKnownPositionTime("/system/nokia/location/lastknown/time");
    GConfItem lastKnownPositionLatitude("/system/nokia/location/lastknown/latitude");
    GConfItem lastKnownPositionLongitude("/system/nokia/location/lastknown/longitude");
    GConfItem lastKnownPositionAltitude("/system/nokia/location/lastknown/altitude");
    GConfItem lastKnownPositionSpeed("/system/nokia/location/lastknown/speed");
    GConfItem lastKnownPositionTrack("/system/nokia/location/lastknown/track");
    GConfItem lastKnownPositionClimb("/system/nokia/location/lastknown/climb");

    if (validLastSatUpdate)
        return lastSatUpdate;

    if (!fromSatellitePositioningMethodsOnly)
        if (validLastUpdate)
            return lastUpdate;

    time = lastKnownPositionTime.value().toDouble();
    latitude = lastKnownPositionLatitude.value().toDouble();
    longitude = lastKnownPositionLongitude.value().toDouble();
    altitude = lastKnownPositionAltitude.value().toDouble();
    speed = lastKnownPositionSpeed.value().toDouble();
    track = lastKnownPositionTrack.value().toDouble();
    climb = lastKnownPositionClimb.value().toDouble();

    if (longitude && latitude) {
        coordinate.setLongitude(longitude);
        coordinate.setLatitude(latitude);
        if (altitude) {
            coordinate.setAltitude(altitude);
        }
        posInfo.setCoordinate(coordinate);
    }

    if (speed) {
        posInfo.setAttribute(QGeoPositionInfo::GroundSpeed, speed);
    }

    if (track) {
        posInfo.setAttribute(QGeoPositionInfo::Direction, track);
    }

    if (climb) {
        posInfo.setAttribute(QGeoPositionInfo::VerticalSpeed, climb);
    }

    // Only positions with time (3D) are provided.
    if (time) {
        posInfo.setTimestamp(QDateTime::fromTime_t(time));
        return posInfo;
    }

    return QGeoPositionInfo();
}

void LiblocationWrapper::satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInView = satellites;
}

void LiblocationWrapper::satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
{
    satsInUse = satellites;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInView()
{
    return satsInView;
}

QList<QGeoSatelliteInfo> LiblocationWrapper::satellitesInUse()
{
    return satsInUse;
}

void LiblocationWrapper::start() {
    startcounter++;

    if ((locationState & LiblocationWrapper::Inited) &&
        !(locationState & LiblocationWrapper::Started)) {
        if (!errorHandlerId) {
            errorHandlerId =
                g_signal_connect(G_OBJECT(locationControl), "error-verbose",
                                 G_CALLBACK(&locationError),
                                 static_cast<void*>(this));
        }

        if (!posChangedId) {
            posChangedId =
                g_signal_connect(G_OBJECT(locationDevice), "changed",
                                 G_CALLBACK(&locationChanged),
                                 static_cast<void*>(this));
        }

        location_gpsd_control_start(locationControl);

        locationState |= LiblocationWrapper::Started;
        locationState &= ~LiblocationWrapper::Stopped;
    }
}

void LiblocationWrapper::stop() {
    startcounter--;

    if (startcounter > 0)
        return;

    if ((locationState & (LiblocationWrapper::Started |
                          LiblocationWrapper::Inited)) &&
        !(locationState & LiblocationWrapper::Stopped)) {
        if (errorHandlerId)
            g_signal_handler_disconnect(G_OBJECT(locationControl),
                                        errorHandlerId);
        if (posChangedId)
            g_signal_handler_disconnect(G_OBJECT(locationDevice),
                                        posChangedId);
        errorHandlerId = 0;
        posChangedId = 0;
        startcounter = 0;
        location_gpsd_control_stop(locationControl);

        locationState &= ~LiblocationWrapper::Started;
        locationState |= LiblocationWrapper::Stopped;
    }
}

bool LiblocationWrapper::isActive() {
    if (locationState & LiblocationWrapper::Started)
        return true;
    else
        return false;
}

#include "moc_liblocationwrapper_p.cpp"
QTM_END_NAMESPACE

<|endoftext|>


<commit_before>#include <QApplication>
#include <QSet>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>

#include <QMetaObject>
#include <QMetaProperty>
#include <QPushButton>
#include <QDebug>
#include <iostream>
#include <QtDeclarative>
#include <QtDeclarative/private/qdeclarativemetatype_p.h>
#include <QtDeclarative/QDeclarativeView>

static QHash<QByteArray, const QDeclarativeType *> qmlTypeByCppName;
static QHash<QByteArray, QByteArray> cppToQml;

QByteArray convertToQmlType(const QByteArray &cppName)
{
    QByteArray qmlName = cppToQml.value(cppName, cppName);
    qmlName.replace("::", ".");
    qmlName.replace("/", ".");
    return qmlName;
}

void erasure(QByteArray *typeName, bool *isList, bool *isPointer)
{
    static QByteArray declListPrefix = "QDeclarativeListProperty<";

    if (typeName->endsWith('*')) {
        *isPointer = true;
        typeName->truncate(typeName->length() - 1);
        erasure(typeName, isList, isPointer);
    } else if (typeName->startsWith(declListPrefix)) {
        *isList = true;
        typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
        *typeName = typeName->mid(declListPrefix.size());
        erasure(typeName, isList, isPointer);
    }

    *typeName = convertToQmlType(*typeName);
}

void processMetaObject(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
{
    if (! meta || metas->contains(meta))
        return;

    metas->insert(meta);
    processMetaObject(meta->superClass(), metas);
}

void processObject(QObject *object, QSet<const QMetaObject *> *metas)
{
    if (! object)
        return;

    const QMetaObject *meta = object->metaObject();
    processMetaObject(meta, metas);

    for (int index = 0; index < meta->propertyCount(); ++index) {
        QMetaProperty prop = meta->property(index);
        if (QDeclarativeMetaType::isQObject(prop.userType())) {
            QObject *oo = QDeclarativeMetaType::toQObject(prop.read(object));
            if (oo && !metas->contains(oo->metaObject()))
                processObject(oo, metas);
        }
    }
}

void processDeclarativeType(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
{
    processMetaObject(ty->metaObject(), metas);
}

void writeType(QXmlStreamAttributes *attrs, QByteArray typeName)
{
    bool isList = false, isPointer = false;
    erasure(&typeName, &isList, &isPointer);
    attrs->append(QXmlStreamAttribute("type", typeName));
    if (isList)
        attrs->append(QXmlStreamAttribute("isList", "true"));
}

void dump(const QMetaProperty &prop, QXmlStreamWriter *xml)
{
    xml->writeStartElement("property");

    QXmlStreamAttributes attributes;
    attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(prop.name())));

    writeType(&attributes, prop.typeName());

    xml->writeAttributes(attributes);
    xml->writeEndElement();
}

void dump(const QMetaMethod &meth, QXmlStreamWriter *xml)
{
    if (meth.methodType() == QMetaMethod::Signal) {
        if (meth.access() != QMetaMethod::Protected)
            return; // nothing to do.
    } else if (meth.access() != QMetaMethod::Public) {
        return; // nothing to do.
    }

    QByteArray name = meth.signature();
    int lparenIndex = name.indexOf('(');
    if (lparenIndex == -1) {
        return; // invalid signature
    }

    name = name.left(lparenIndex);

    QString elementName = QLatin1String("method");

    QXmlStreamAttributes attributes;
    if (meth.methodType() == QMetaMethod::Signal)
        elementName = QLatin1String("signal");

    xml->writeStartElement(elementName);

    attributes.append(QXmlStreamAttribute("name", name));

    const QString typeName = convertToQmlType(meth.typeName());
    if (! typeName.isEmpty())
        attributes.append(QXmlStreamAttribute("type", typeName));

    xml->writeAttributes(attributes);

    for (int i = 0; i < meth.parameterTypes().size(); ++i) {
        QByteArray argName = meth.parameterNames().at(i);

        xml->writeStartElement("param");

        QXmlStreamAttributes attrs;

        if (! argName.isEmpty())
            attrs.append(QXmlStreamAttribute("name", argName));

        writeType(&attrs, meth.parameterTypes().at(i));
        xml->writeAttributes(attrs);

        xml->writeEndElement();
    }

    xml->writeEndElement();
}

void dump(const QMetaEnum &e, QXmlStreamWriter *xml)
{
    xml->writeStartElement("enum");

    QXmlStreamAttributes attributes;
    attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(e.name()))); // ### FIXME
    xml->writeAttributes(attributes);

    for (int index = 0; index < e.keyCount(); ++index) {
        xml->writeStartElement("enumerator");

        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(e.key(index))));
        attributes.append(QXmlStreamAttribute("value", QString::number(e.value(index))));
        xml->writeAttributes(attributes);

        xml->writeEndElement();
    }

    xml->writeEndElement();
}

class FriendlyQObject: public QObject
{
public:
    static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
};

void dump(const QMetaObject *meta, QXmlStreamWriter *xml)
{
    xml->writeStartElement("type");

    QXmlStreamAttributes attributes;
    attributes.append(QXmlStreamAttribute("name", convertToQmlType(meta->className())));

    if (const QDeclarativeType *qmlTy = qmlTypeByCppName.value(meta->className())) {
        attributes.append(QXmlStreamAttribute("version", QString("%1.%2").arg(qmlTy->majorVersion()).arg(qmlTy->minorVersion())));
    }

    for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
        QMetaClassInfo classInfo = meta->classInfo(index);
        if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
            attributes.append(QXmlStreamAttribute("defaultProperty", QLatin1String(classInfo.value())));
            break;
        }
    }

    QString version;

    if (meta->superClass())
        attributes.append(QXmlStreamAttribute("extends", convertToQmlType(meta->superClass()->className())));

    if (! version.isEmpty())
        attributes.append(QXmlStreamAttribute("version", version));

    xml->writeAttributes(attributes);

    for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
        dump(meta->enumerator(index), xml);

    for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
        dump(meta->property(index), xml);

    for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
        dump(meta->method(index), xml);

    xml->writeEndElement();
}

void writeScriptElement(QXmlStreamWriter *xml)
{
    xml->writeStartElement("type");
    {
        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", "Script"));
        xml->writeAttributes(attributes);
    }

    xml->writeStartElement("property");
    {
        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", "script"));
        attributes.append(QXmlStreamAttribute("type", "string"));
        xml->writeAttributes(attributes);
    }
    xml->writeEndElement();

    xml->writeStartElement("property");
    {
        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", "source"));
        attributes.append(QXmlStreamAttribute("type", "QUrl"));
        xml->writeAttributes(attributes);
    }
    xml->writeEndElement();

    xml->writeEndElement();
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QDeclarativeView view;
    QDeclarativeEngine *engine = view.engine();

    {
        QByteArray code;
        code += "import Qt 4.7;\n";
        code += "import Qt.widgets 4.7;\n";
        code += "import Qt.multimedia 1.0;\n";
        code += "import Qt.labs.particles 4.7;\n";
        code += "import org.webkit 1.0;\n";
        code += "Item {}";
        QDeclarativeComponent c(engine);
        c.setData(code, QUrl("xxx"));
        c.create();
    }

    cppToQml.insert("QString", "string");
    cppToQml.insert("QEasingCurve", "Qt.Easing");
    cppToQml.insert("QDeclarativeEasingValueType::Type", "Type");

    QSet<const QMetaObject *> metas;

    metas.insert(FriendlyQObject::qtMeta());

    // ### TODO: We don't treat extended types correctly. Currently only hits the
    // QDeclarativeGraphicsWidget extension to QGraphicsWidget
    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
        if (ty->isExtendedType())
            continue;

        cppToQml.insert(ty->metaObject()->className(), ty->qmlTypeName());
        qmlTypeByCppName.insert(ty->metaObject()->className(), ty);
        processDeclarativeType(ty, &metas);
    }

    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
        if (ty->isExtendedType())
            continue;

        QByteArray tyName = ty->qmlTypeName();
        tyName = tyName.mid(tyName.lastIndexOf('/') + 1);

        QByteArray code;
        code += "import Qt 4.7;\n";
        code += "import Qt.widgets 4.7;\n";
        code += "import Qt.multimedia 1.0;\n";
        code += "import Qt.labs.particles 4.7;\n";
        code += "import org.webkit 1.0;\n";
        code += tyName;
        code += " {}\n";

        QDeclarativeComponent c(engine);
        c.setData(code, QUrl("xxx"));
        processObject(c.create(), &metas);
    }

    QByteArray bytes;
    QXmlStreamWriter xml(&bytes);
    xml.setAutoFormatting(true);

    xml.writeStartDocument("1.0");
    xml.writeStartElement("module");

    QMap<QString, const QMetaObject *> nameToMeta;
    foreach (const QMetaObject *meta, metas) {
        nameToMeta.insert(convertToQmlType(meta->className()), meta);
    }
    foreach (const QMetaObject *meta, nameToMeta) {
        dump(meta, &xml);
    }

    writeScriptElement(&xml);

    xml.writeEndElement();
    xml.writeEndDocument();

    std::cout << bytes.constData();

    QTimer timer;
    timer.setSingleShot(true);
    timer.setInterval(0);
    QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));

    timer.start();

    return app.exec();
}
<commit_msg>QmlJS: Make the qmldump tool treat extended types correctly.<commit_after>#include <QApplication>
#include <QSet>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>

#include <QMetaObject>
#include <QMetaProperty>
#include <QPushButton>
#include <QDebug>
#include <iostream>
#include <QtDeclarative>
#include <QtDeclarative/private/qdeclarativemetatype_p.h>
#include <QtDeclarative/QDeclarativeView>

static QHash<QByteArray, const QDeclarativeType *> qmlTypeByCppName;
static QHash<QByteArray, QByteArray> cppToQml;

QByteArray convertToQmlType(const QByteArray &cppName)
{
    QByteArray qmlName = cppToQml.value(cppName, cppName);
    qmlName.replace("::", ".");
    qmlName.replace("/", ".");
    return qmlName;
}

void erasure(QByteArray *typeName, bool *isList, bool *isPointer)
{
    static QByteArray declListPrefix = "QDeclarativeListProperty<";

    if (typeName->endsWith('*')) {
        *isPointer = true;
        typeName->truncate(typeName->length() - 1);
        erasure(typeName, isList, isPointer);
    } else if (typeName->startsWith(declListPrefix)) {
        *isList = true;
        typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
        *typeName = typeName->mid(declListPrefix.size());
        erasure(typeName, isList, isPointer);
    }

    *typeName = convertToQmlType(*typeName);
}

void processMetaObject(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
{
    if (! meta || metas->contains(meta))
        return;

    metas->insert(meta);
    processMetaObject(meta->superClass(), metas);
}

void processObject(QObject *object, QSet<const QMetaObject *> *metas)
{
    if (! object)
        return;

    const QMetaObject *meta = object->metaObject();
    processMetaObject(meta, metas);

    for (int index = 0; index < meta->propertyCount(); ++index) {
        QMetaProperty prop = meta->property(index);
        if (QDeclarativeMetaType::isQObject(prop.userType())) {
            QObject *oo = QDeclarativeMetaType::toQObject(prop.read(object));
            if (oo && !metas->contains(oo->metaObject()))
                processObject(oo, metas);
        }
    }
}

void processDeclarativeType(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
{
    processMetaObject(ty->metaObject(), metas);
}

void writeType(QXmlStreamAttributes *attrs, QByteArray typeName)
{
    bool isList = false, isPointer = false;
    erasure(&typeName, &isList, &isPointer);
    attrs->append(QXmlStreamAttribute("type", typeName));
    if (isList)
        attrs->append(QXmlStreamAttribute("isList", "true"));
}

void dump(const QMetaProperty &prop, QXmlStreamWriter *xml)
{
    xml->writeStartElement("property");

    QXmlStreamAttributes attributes;
    attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(prop.name())));

    writeType(&attributes, prop.typeName());

    xml->writeAttributes(attributes);
    xml->writeEndElement();
}

void dump(const QMetaMethod &meth, QXmlStreamWriter *xml)
{
    if (meth.methodType() == QMetaMethod::Signal) {
        if (meth.access() != QMetaMethod::Protected)
            return; // nothing to do.
    } else if (meth.access() != QMetaMethod::Public) {
        return; // nothing to do.
    }

    QByteArray name = meth.signature();
    int lparenIndex = name.indexOf('(');
    if (lparenIndex == -1) {
        return; // invalid signature
    }

    name = name.left(lparenIndex);

    QString elementName = QLatin1String("method");

    QXmlStreamAttributes attributes;
    if (meth.methodType() == QMetaMethod::Signal)
        elementName = QLatin1String("signal");

    xml->writeStartElement(elementName);

    attributes.append(QXmlStreamAttribute("name", name));

    const QString typeName = convertToQmlType(meth.typeName());
    if (! typeName.isEmpty())
        attributes.append(QXmlStreamAttribute("type", typeName));

    xml->writeAttributes(attributes);

    for (int i = 0; i < meth.parameterTypes().size(); ++i) {
        QByteArray argName = meth.parameterNames().at(i);

        xml->writeStartElement("param");

        QXmlStreamAttributes attrs;

        if (! argName.isEmpty())
            attrs.append(QXmlStreamAttribute("name", argName));

        writeType(&attrs, meth.parameterTypes().at(i));
        xml->writeAttributes(attrs);

        xml->writeEndElement();
    }

    xml->writeEndElement();
}

void dump(const QMetaEnum &e, QXmlStreamWriter *xml)
{
    xml->writeStartElement("enum");

    QXmlStreamAttributes attributes;
    attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(e.name()))); // ### FIXME
    xml->writeAttributes(attributes);

    for (int index = 0; index < e.keyCount(); ++index) {
        xml->writeStartElement("enumerator");

        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", QString::fromUtf8(e.key(index))));
        attributes.append(QXmlStreamAttribute("value", QString::number(e.value(index))));
        xml->writeAttributes(attributes);

        xml->writeEndElement();
    }

    xml->writeEndElement();
}

class FriendlyQObject: public QObject
{
public:
    static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
};

void dump(const QMetaObject *meta, QXmlStreamWriter *xml)
{
    xml->writeStartElement("type");

    QXmlStreamAttributes attributes;
    attributes.append(QXmlStreamAttribute("name", convertToQmlType(meta->className())));

    if (const QDeclarativeType *qmlTy = qmlTypeByCppName.value(meta->className())) {
        attributes.append(QXmlStreamAttribute("version", QString("%1.%2").arg(qmlTy->majorVersion()).arg(qmlTy->minorVersion())));
    }

    for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
        QMetaClassInfo classInfo = meta->classInfo(index);
        if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
            attributes.append(QXmlStreamAttribute("defaultProperty", QLatin1String(classInfo.value())));
            break;
        }
    }

    QString version;

    if (meta->superClass())
        attributes.append(QXmlStreamAttribute("extends", convertToQmlType(meta->superClass()->className())));

    if (! version.isEmpty())
        attributes.append(QXmlStreamAttribute("version", version));

    xml->writeAttributes(attributes);

    for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
        dump(meta->enumerator(index), xml);

    for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
        dump(meta->property(index), xml);

    for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
        dump(meta->method(index), xml);

    xml->writeEndElement();
}

void writeScriptElement(QXmlStreamWriter *xml)
{
    xml->writeStartElement("type");
    {
        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", "Script"));
        xml->writeAttributes(attributes);
    }

    xml->writeStartElement("property");
    {
        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", "script"));
        attributes.append(QXmlStreamAttribute("type", "string"));
        xml->writeAttributes(attributes);
    }
    xml->writeEndElement();

    xml->writeStartElement("property");
    {
        QXmlStreamAttributes attributes;
        attributes.append(QXmlStreamAttribute("name", "source"));
        attributes.append(QXmlStreamAttribute("type", "QUrl"));
        xml->writeAttributes(attributes);
    }
    xml->writeEndElement();

    xml->writeEndElement();
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QDeclarativeView view;
    QDeclarativeEngine *engine = view.engine();

    {
        QByteArray code;
        code += "import Qt 4.7;\n";
        code += "import Qt.widgets 4.7;\n";
        code += "import Qt.multimedia 1.0;\n";
        code += "import Qt.labs.particles 4.7;\n";
        code += "import org.webkit 1.0;\n";
        code += "Item {}";
        QDeclarativeComponent c(engine);
        c.setData(code, QUrl("xxx"));
        c.create();
    }

    cppToQml.insert("QString", "string");
    cppToQml.insert("QEasingCurve", "Qt.Easing");
    cppToQml.insert("QDeclarativeEasingValueType::Type", "Type");

    QSet<const QMetaObject *> metas;

    metas.insert(FriendlyQObject::qtMeta());

    QMultiHash<QByteArray, QByteArray> extensions;
    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
        qmlTypeByCppName.insert(ty->metaObject()->className(), ty);
        if (ty->isExtendedType()) {
            extensions.insert(ty->typeName(), ty->metaObject()->className());
        } else {
            cppToQml.insert(ty->metaObject()->className(), ty->qmlTypeName());
        }
        processDeclarativeType(ty, &metas);
    }

    // Adjust qml names of extended objects.
    // The chain ends up being:
    // __extended__.originalname - the base object
    // __extension_0_.originalname - first extension
    // ..
    // __extension_n-2_.originalname - second to last extension
    // originalname - last extension
    foreach (const QByteArray &extendedCpp, extensions.keys()) {
        const QByteArray extendedQml = cppToQml.value(extendedCpp);
        cppToQml.insert(extendedCpp, "__extended__." + extendedQml);
        QList<QByteArray> extensionCppNames = extensions.values(extendedCpp);
        for (int i = 0; i < extensionCppNames.size() - 1; ++i) {
            QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(i), QString(extendedQml)).toAscii();
            cppToQml.insert(extensionCppNames.value(i), adjustedName);
        }
        cppToQml.insert(extensionCppNames.last(), extendedQml);
    }

    foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
        if (ty->isExtendedType())
            continue;

        QByteArray tyName = ty->qmlTypeName();
        tyName = tyName.mid(tyName.lastIndexOf('/') + 1);

        QByteArray code;
        code += "import Qt 4.7;\n";
        code += "import Qt.widgets 4.7;\n";
        code += "import Qt.multimedia 1.0;\n";
        code += "import Qt.labs.particles 4.7;\n";
        code += "import org.webkit 1.0;\n";
        code += tyName;
        code += " {}\n";

        QDeclarativeComponent c(engine);
        c.setData(code, QUrl("xxx"));
        processObject(c.create(), &metas);
    }

    QByteArray bytes;
    QXmlStreamWriter xml(&bytes);
    xml.setAutoFormatting(true);

    xml.writeStartDocument("1.0");
    xml.writeStartElement("module");

    QMap<QString, const QMetaObject *> nameToMeta;
    foreach (const QMetaObject *meta, metas) {
        nameToMeta.insert(convertToQmlType(meta->className()), meta);
    }
    foreach (const QMetaObject *meta, nameToMeta) {
        dump(meta, &xml);
    }

    writeScriptElement(&xml);

    xml.writeEndElement();
    xml.writeEndDocument();

    std::cout << bytes.constData();

    QTimer timer;
    timer.setSingleShot(true);
    timer.setInterval(0);
    QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));

    timer.start();

    return app.exec();
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>

#include "zlib.h"

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/udp_tracker_connection.hpp"
#include "libtorrent/io.hpp"

namespace
{
	enum
	{
		udp_connection_retries = 4,
		udp_announce_retries = 15,
		udp_connect_timeout = 15,
		udp_announce_timeout = 10,
		udp_buffer_size = 2048
	};
}

using namespace boost::posix_time;

namespace libtorrent
{

	udp_tracker_connection::udp_tracker_connection(
		tracker_request const& req
		, std::string const& hostname
		, unsigned short port
		, boost::weak_ptr<request_callback> c
		, const http_settings& stn)
		: tracker_connection(c)
		, m_request_time(second_clock::universal_time())
		, m_request(req)
		, m_transaction_id(0)
		, m_connection_id(0)
		, m_settings(stn)
		, m_attempts(0)
	{
		// TODO: this is a problem. DNS-lookup is blocking!
		// (may block up to 5 seconds)
		address a(hostname.c_str(), port);
		if (has_requester()) requester().m_tracker_address = a;
		m_socket.reset(new socket(socket::udp, false));
		m_socket->connect(a);

		send_udp_connect();
	}

	bool udp_tracker_connection::send_finished() const
	{
		using namespace boost::posix_time;

		time_duration d = second_clock::universal_time() - m_request_time;
		return (m_transaction_id != 0
			&& m_connection_id != 0)
			|| d > seconds(m_settings.tracker_timeout);
	}

	bool udp_tracker_connection::tick()
	{
		using namespace boost::posix_time;

		time_duration d = second_clock::universal_time() - m_request_time;
		if (m_connection_id == 0
			&& d > seconds(udp_connect_timeout))
		{
			if (m_attempts >= udp_connection_retries)
			{
				if (has_requester())
					requester().tracker_request_timed_out(m_request);
				return true;
			}
			send_udp_connect();
			return false;
		}

		if (m_connection_id != 0
			&& d > seconds(udp_announce_timeout))
		{
			if (m_attempts >= udp_announce_retries)
			{
				if (has_requester())
					requester().tracker_request_timed_out(m_request);
				return true;
			}

			if (m_request.kind == tracker_request::announce_request)
				send_udp_announce();
			else if (m_request.kind == tracker_request::scrape_request)
				send_udp_scrape();
			return false;
		}

		char buf[udp_buffer_size];
		int ret = m_socket->receive(buf, udp_buffer_size);

		// if there was nothing to receive, return
		if (ret == 0) return false;
		if (ret < 0)
		{
			socket::error_code err = m_socket->last_error();
			if (err == socket::would_block) return false;
			throw network_error(m_socket->last_error());
		}
		if (ret == udp_buffer_size)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, "tracker reply too big");
			return true;
		}

		if (m_connection_id == 0)
		{
			return parse_connect_response(buf, ret);
		}
		else if (m_request.kind == tracker_request::announce_request)
		{
			return parse_announce_response(buf, ret);
		}
		else if (m_request.kind == tracker_request::scrape_request)
		{
			return parse_scrape_response(buf, ret);
		}

		assert(false);
		return false;
	}

	void udp_tracker_connection::send_udp_announce()
	{
		if (m_transaction_id == 0)
			m_transaction_id = rand() ^ (rand() << 16);

		std::vector<char> buf;
		std::back_insert_iterator<std::vector<char> > out(buf);

		// connection_id
		detail::write_int64(m_connection_id, out);
		// action (announce)
		detail::write_int32(announce, out);
		// transaction_id
		detail::write_int32(m_transaction_id, out);
		// info_hash
		std::copy(m_request.info_hash.begin(), m_request.info_hash.end(), out);
		// peer_id
		std::copy(m_request.id.begin(), m_request.id.end(), out);
		// downloaded
		detail::write_int64(m_request.downloaded, out);
		// left
		detail::write_int64(m_request.left, out);
		// uploaded
		detail::write_int64(m_request.uploaded, out);
		// event
		detail::write_int32(m_request.event, out);
		// ip address
		detail::write_int32(0, out);
		// key
		detail::write_int32(m_request.key, out);
		// num_want
		detail::write_int32(m_request.num_want, out);
		// port
		detail::write_uint16(m_request.listen_port, out);

		m_socket->send(&buf[0], buf.size());
		m_request_time = second_clock::universal_time();
		++m_attempts;
	}

	void udp_tracker_connection::send_udp_scrape()
	{
		if (m_transaction_id == 0)
			m_transaction_id = rand() ^ (rand() << 16);

		std::vector<char> buf;
		std::back_insert_iterator<std::vector<char> > out(buf);

		// connection_id
		detail::write_int64(m_connection_id, out);
		// action (scrape)
		detail::write_int32(scrape, out);
		// transaction_id
		detail::write_int32(m_transaction_id, out);
		// info_hash
		std::copy(m_request.info_hash.begin(), m_request.info_hash.end(), out);

		m_socket->send(&buf[0], buf.size());
		m_request_time = second_clock::universal_time();
		++m_attempts;
	}

	void udp_tracker_connection::send_udp_connect()
	{
		char send_buf[16];
		char* ptr = send_buf;

		if (m_transaction_id == 0)
			m_transaction_id = rand() ^ (rand() << 16);

		// connection_id
		detail::write_int64(0x41727101980, ptr);
		// action (connect)
		detail::write_int32(connect, ptr);
		// transaction_id
		detail::write_int32(m_transaction_id, ptr);

		m_socket->send(send_buf, 16);
		m_request_time = second_clock::universal_time();
		++m_attempts;
	}

	bool udp_tracker_connection::parse_announce_response(const char* buf, int len)
	{
		assert(buf != 0);
		assert(len > 0);

		if (len < 8)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 8, ignoring");
#endif
			return false;
		}

		int action = detail::read_int32(buf);
		int transaction = detail::read_int32(buf);
		if (transaction != m_transaction_id)
		{
			return false;
		}

		if (action == error)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, std::string(buf, buf + len - 8));
			return true;
		}
		if (action != announce) return false;

		if (len < 20)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 20, ignoring");
#endif
			return false;
		}
		int interval = detail::read_int32(buf);
		int incomplete = detail::read_int32(buf);
		int complete = detail::read_int32(buf);
		int num_peers = (len - 20) / 6;
		if ((len - 20) % 6 != 0)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, "invalid tracker response");
			return true;
		}

		if (!has_requester()) return true;

		std::vector<peer_entry> peer_list;
		for (int i = 0; i < num_peers; ++i)
		{
			peer_entry e;
			std::stringstream s;
			s << (int)detail::read_uint8(buf) << ".";
			s << (int)detail::read_uint8(buf) << ".";
			s << (int)detail::read_uint8(buf) << ".";
			s << (int)detail::read_uint8(buf);
			e.ip = s.str();
			e.port = detail::read_uint16(buf);
			e.id.clear();
			peer_list.push_back(e);
		}

		requester().tracker_response(m_request, peer_list, interval
			, complete, incomplete);
		return true;
	}

	bool udp_tracker_connection::parse_scrape_response(const char* buf, int len)
	{
		assert(buf != 0);
		assert(len > 0);

		if (len < 8)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 8, ignoring");
#endif
			return false;
		}

		int action = detail::read_int32(buf);
		int transaction = detail::read_int32(buf);
		if (transaction != m_transaction_id)
		{
			return false;
		}

		if (action == error)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, std::string(buf, buf + len - 8));
			return true;
		}
		if (action != scrape) return false;

		if (len < 20)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 20, ignoring");
#endif
			return false;
		}
		int complete = detail::read_int32(buf);
		int completed = detail::read_int32(buf);
		int incomplete = detail::read_int32(buf);

		if (!has_requester()) return true;

		std::vector<peer_entry> peer_list;
		requester().tracker_response(m_request, peer_list, 0
			, complete, incomplete);
		return true;
	}

	bool udp_tracker_connection::parse_connect_response(const char* buf, int len)
	{
		assert(buf != 0);
		assert(len > 0);

		if (len < 8)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 8, ignoring");
#endif
			return false;
		}
		const char* ptr = buf;
		int action = detail::read_int32(ptr);
		int transaction = detail::read_int32(ptr);

		if (action == error)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, std::string(ptr, buf + len));
			return true;
		}
		if (action != connect) return false;
		if (m_transaction_id != transaction)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with incorrect transaction id, ignoring");
#endif
			return false;
		}

		if (len < 16)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a connection message size < 16, ignoring");
#endif
			return false;
		}
		// reset transaction
		m_transaction_id = 0;
		m_attempts = 0;
		m_connection_id = detail::read_int64(ptr);

		if (m_request.kind == tracker_request::announce_request)
			send_udp_announce();
		else if (m_request.kind == tracker_request::scrape_request)
			send_udp_scrape();

		return false;
	}

}

<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>

#include "zlib.h"

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/udp_tracker_connection.hpp"
#include "libtorrent/io.hpp"

namespace
{
	enum
	{
		udp_connection_retries = 4,
		udp_announce_retries = 15,
		udp_connect_timeout = 15,
		udp_announce_timeout = 10,
		udp_buffer_size = 2048
	};
}

using namespace boost::posix_time;

namespace libtorrent
{

	udp_tracker_connection::udp_tracker_connection(
		tracker_request const& req
		, std::string const& hostname
		, unsigned short port
		, boost::weak_ptr<request_callback> c
		, const http_settings& stn)
		: tracker_connection(c)
		, m_request_time(second_clock::universal_time())
		, m_request(req)
		, m_transaction_id(0)
		, m_connection_id(0)
		, m_settings(stn)
		, m_attempts(0)
	{
		// TODO: this is a problem. DNS-lookup is blocking!
		// (may block up to 5 seconds)
		address a(hostname.c_str(), port);
		if (has_requester()) requester().m_tracker_address = a;
		m_socket.reset(new socket(socket::udp, false));
		m_socket->connect(a);

		send_udp_connect();
	}

	bool udp_tracker_connection::send_finished() const
	{
		using namespace boost::posix_time;

		time_duration d = second_clock::universal_time() - m_request_time;
		return (m_transaction_id != 0
			&& m_connection_id != 0)
			|| d > seconds(m_settings.tracker_timeout);
	}

	bool udp_tracker_connection::tick()
	{
		using namespace boost::posix_time;

		time_duration d = second_clock::universal_time() - m_request_time;
		if (m_connection_id == 0
			&& d > seconds(udp_connect_timeout))
		{
			if (m_attempts >= udp_connection_retries)
			{
				if (has_requester())
					requester().tracker_request_timed_out(m_request);
				return true;
			}
			send_udp_connect();
			return false;
		}

		if (m_connection_id != 0
			&& d > seconds(udp_announce_timeout))
		{
			if (m_attempts >= udp_announce_retries)
			{
				if (has_requester())
					requester().tracker_request_timed_out(m_request);
				return true;
			}

			if (m_request.kind == tracker_request::announce_request)
				send_udp_announce();
			else if (m_request.kind == tracker_request::scrape_request)
				send_udp_scrape();
			return false;
		}

		char buf[udp_buffer_size];
		int ret = m_socket->receive(buf, udp_buffer_size);

		// if there was nothing to receive, return
		if (ret == 0) return false;
		if (ret < 0)
		{
			socket::error_code err = m_socket->last_error();
			if (err == socket::would_block) return false;
			throw network_error(m_socket->last_error());
		}
		if (ret == udp_buffer_size)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, "tracker reply too big");
			return true;
		}

		if (m_connection_id == 0)
		{
			return parse_connect_response(buf, ret);
		}
		else if (m_request.kind == tracker_request::announce_request)
		{
			return parse_announce_response(buf, ret);
		}
		else if (m_request.kind == tracker_request::scrape_request)
		{
			return parse_scrape_response(buf, ret);
		}

		assert(false);
		return false;
	}

	void udp_tracker_connection::send_udp_announce()
	{
		if (m_transaction_id == 0)
			m_transaction_id = rand() ^ (rand() << 16);

		std::vector<char> buf;
		std::back_insert_iterator<std::vector<char> > out(buf);

		// connection_id
		detail::write_int64(m_connection_id, out);
		// action (announce)
		detail::write_int32(announce, out);
		// transaction_id
		detail::write_int32(m_transaction_id, out);
		// info_hash
		std::copy(m_request.info_hash.begin(), m_request.info_hash.end(), out);
		// peer_id
		std::copy(m_request.id.begin(), m_request.id.end(), out);
		// downloaded
		detail::write_int64(m_request.downloaded, out);
		// left
		detail::write_int64(m_request.left, out);
		// uploaded
		detail::write_int64(m_request.uploaded, out);
		// event
		detail::write_int32(m_request.event, out);
		// ip address
		detail::write_int32(0, out);
		// key
		detail::write_int32(m_request.key, out);
		// num_want
		detail::write_int32(m_request.num_want, out);
		// port
		detail::write_uint16(m_request.listen_port, out);
		// extensions
		detail::write_uint16(0, out);

		m_socket->send(&buf[0], buf.size());
		m_request_time = second_clock::universal_time();
		++m_attempts;
	}

	void udp_tracker_connection::send_udp_scrape()
	{
		if (m_transaction_id == 0)
			m_transaction_id = rand() ^ (rand() << 16);

		std::vector<char> buf;
		std::back_insert_iterator<std::vector<char> > out(buf);

		// connection_id
		detail::write_int64(m_connection_id, out);
		// action (scrape)
		detail::write_int32(scrape, out);
		// transaction_id
		detail::write_int32(m_transaction_id, out);
		// info_hash
		std::copy(m_request.info_hash.begin(), m_request.info_hash.end(), out);

		m_socket->send(&buf[0], buf.size());
		m_request_time = second_clock::universal_time();
		++m_attempts;
	}

	void udp_tracker_connection::send_udp_connect()
	{
		char send_buf[16];
		char* ptr = send_buf;

		if (m_transaction_id == 0)
			m_transaction_id = rand() ^ (rand() << 16);

		// connection_id
		detail::write_int64(0x41727101980, ptr);
		// action (connect)
		detail::write_int32(connect, ptr);
		// transaction_id
		detail::write_int32(m_transaction_id, ptr);

		m_socket->send(send_buf, 16);
		m_request_time = second_clock::universal_time();
		++m_attempts;
	}

	bool udp_tracker_connection::parse_announce_response(const char* buf, int len)
	{
		assert(buf != 0);
		assert(len > 0);

		if (len < 8)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 8, ignoring");
#endif
			return false;
		}

		int action = detail::read_int32(buf);
		int transaction = detail::read_int32(buf);
		if (transaction != m_transaction_id)
		{
			return false;
		}

		if (action == error)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, std::string(buf, buf + len - 8));
			return true;
		}
		if (action != announce) return false;

		if (len < 20)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 20, ignoring");
#endif
			return false;
		}
		int interval = detail::read_int32(buf);
		int incomplete = detail::read_int32(buf);
		int complete = detail::read_int32(buf);
		int num_peers = (len - 20) / 6;
		if ((len - 20) % 6 != 0)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, "invalid tracker response");
			return true;
		}

		if (!has_requester()) return true;

		std::vector<peer_entry> peer_list;
		for (int i = 0; i < num_peers; ++i)
		{
			peer_entry e;
			std::stringstream s;
			s << (int)detail::read_uint8(buf) << ".";
			s << (int)detail::read_uint8(buf) << ".";
			s << (int)detail::read_uint8(buf) << ".";
			s << (int)detail::read_uint8(buf);
			e.ip = s.str();
			e.port = detail::read_uint16(buf);
			e.id.clear();
			peer_list.push_back(e);
		}

		requester().tracker_response(m_request, peer_list, interval
			, complete, incomplete);
		return true;
	}

	bool udp_tracker_connection::parse_scrape_response(const char* buf, int len)
	{
		assert(buf != 0);
		assert(len > 0);

		if (len < 8)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 8, ignoring");
#endif
			return false;
		}

		int action = detail::read_int32(buf);
		int transaction = detail::read_int32(buf);
		if (transaction != m_transaction_id)
		{
			return false;
		}

		if (action == error)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, std::string(buf, buf + len - 8));
			return true;
		}
		if (action != scrape) return false;

		if (len < 20)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 20, ignoring");
#endif
			return false;
		}
		int complete = detail::read_int32(buf);
		int completed = detail::read_int32(buf);
		int incomplete = detail::read_int32(buf);

		if (!has_requester()) return true;

		std::vector<peer_entry> peer_list;
		requester().tracker_response(m_request, peer_list, 0
			, complete, incomplete);
		return true;
	}

	bool udp_tracker_connection::parse_connect_response(const char* buf, int len)
	{
		assert(buf != 0);
		assert(len > 0);

		if (len < 8)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with size < 8, ignoring");
#endif
			return false;
		}
		const char* ptr = buf;
		int action = detail::read_int32(ptr);
		int transaction = detail::read_int32(ptr);

		if (action == error)
		{
			if (has_requester())
				requester().tracker_request_error(
					m_request, -1, std::string(ptr, buf + len));
			return true;
		}
		if (action != connect) return false;
		if (m_transaction_id != transaction)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a message with incorrect transaction id, ignoring");
#endif
			return false;
		}

		if (len < 16)
		{
#ifdef TORRENT_VERBOSE_LOGGING
			if (has_requester())
				requester().debug_log("udp_tracker_connection: "
				"got a connection message size < 16, ignoring");
#endif
			return false;
		}
		// reset transaction
		m_transaction_id = 0;
		m_attempts = 0;
		m_connection_id = detail::read_int64(ptr);

		if (m_request.kind == tracker_request::announce_request)
			send_udp_announce();
		else if (m_request.kind == tracker_request::scrape_request)
			send_udp_scrape();

		return false;
	}

}

<|endoftext|>


<commit_before>/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/gpu/GrContext.h"

#include "include/gpu/GrContextThreadSafeProxy.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrContextThreadSafeProxyPriv.h"
#include "src/gpu/GrGpu.h"

#include "src/gpu/effects/GrSkSLFP.h"
#include "src/gpu/gl/GrGLGpu.h"
#include "src/gpu/mock/GrMockGpu.h"
#include "src/gpu/text/GrStrikeCache.h"
#ifdef SK_METAL
#include "src/gpu/mtl/GrMtlTrampoline.h"
#endif
#ifdef SK_VULKAN
#include "src/gpu/vk/GrVkGpu.h"
#endif

#ifdef SK_DISABLE_REDUCE_OPLIST_SPLITTING
static const bool kDefaultReduceOpListSplitting = false;
#else
static const bool kDefaultReduceOpListSplitting = true;
#endif

class SK_API GrLegacyDirectContext : public GrContext {
public:
    GrLegacyDirectContext(GrBackendApi backend, const GrContextOptions& options)
            : INHERITED(backend, options)
            , fAtlasManager(nullptr) {
    }

    ~GrLegacyDirectContext() override {
        // this if-test protects against the case where the context is being destroyed
        // before having been fully created
        if (this->priv().getGpu()) {
            this->flush();
        }

        delete fAtlasManager;
    }

    void abandonContext() override {
        INHERITED::abandonContext();
        fAtlasManager->freeAll();
    }

    void releaseResourcesAndAbandonContext() override {
        INHERITED::releaseResourcesAndAbandonContext();
        fAtlasManager->freeAll();
    }

    void freeGpuResources() override {
        this->flush();
        fAtlasManager->freeAll();

        INHERITED::freeGpuResources();
    }

protected:
    bool init(sk_sp<const GrCaps> caps, sk_sp<GrSkSLFPFactoryCache> FPFactoryCache) override {
        SkASSERT(caps && !FPFactoryCache);
        SkASSERT(!fThreadSafeProxy);

        FPFactoryCache.reset(new GrSkSLFPFactoryCache());
        fThreadSafeProxy = GrContextThreadSafeProxyPriv::Make(this->backend(),
                                                              this->options(),
                                                              this->contextID(),
                                                              caps, FPFactoryCache);

        if (!INHERITED::init(std::move(caps), std::move(FPFactoryCache))) {
            return false;
        }

        bool reduceOpListSplitting = kDefaultReduceOpListSplitting;
        if (GrContextOptions::Enable::kNo == this->options().fReduceOpListSplitting) {
            reduceOpListSplitting = false;
        } else if (GrContextOptions::Enable::kYes == this->options().fReduceOpListSplitting) {
            reduceOpListSplitting = true;
        }

        this->setupDrawingManager(true, reduceOpListSplitting);

        SkASSERT(this->caps());

        GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
        if (GrContextOptions::Enable::kNo == this->options().fAllowMultipleGlyphCacheTextures ||
            // multitexturing supported only if range can represent the index + texcoords fully
            !(this->caps()->shaderCaps()->floatIs32Bits() ||
              this->caps()->shaderCaps()->integerSupport())) {
            allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
        } else {
            allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
        }

        GrStrikeCache* glyphCache = this->priv().getGrStrikeCache();
        GrProxyProvider* proxyProvider = this->priv().proxyProvider();

        fAtlasManager = new GrAtlasManager(proxyProvider, glyphCache,
                                           this->options().fGlyphCacheTextureMaximumBytes,
                                           allowMultitexturing);
        this->priv().addOnFlushCallbackObject(fAtlasManager);

        return true;
    }

    GrAtlasManager* onGetAtlasManager() override { return fAtlasManager; }

private:
    GrAtlasManager* fAtlasManager;

    typedef GrContext INHERITED;
};

sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface) {
    GrContextOptions defaultOptions;
    return MakeGL(std::move(interface), defaultOptions);
}

sk_sp<GrContext> GrContext::MakeGL(const GrContextOptions& options) {
    return MakeGL(nullptr, options);
}

sk_sp<GrContext> GrContext::MakeGL() {
    GrContextOptions defaultOptions;
    return MakeGL(nullptr, defaultOptions);
}

sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface,
                                   const GrContextOptions& options) {
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kOpenGL, options));

    context->fGpu = GrGLGpu::Make(std::move(interface), options, context.get());
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
}

sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) {
    GrContextOptions defaultOptions;
    return MakeMock(mockOptions, defaultOptions);
}

sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions,
                                     const GrContextOptions& options) {
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMock, options));

    context->fGpu = GrMockGpu::Make(mockOptions, options, context.get());
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
}

sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext& backendContext) {
#ifdef SK_VULKAN
    GrContextOptions defaultOptions;
    return MakeVulkan(backendContext, defaultOptions);
#else
    return nullptr;
#endif
}

sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext& backendContext,
                                       const GrContextOptions& options) {
#ifdef SK_VULKAN
    GrContextOptions defaultOptions;
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kVulkan, options));

    context->fGpu = GrVkGpu::Make(backendContext, options, context.get());
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
#else
    return nullptr;
#endif
}

#ifdef SK_METAL
sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) {
    GrContextOptions defaultOptions;
    return MakeMetal(device, queue, defaultOptions);
}

sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMetal, options));

    context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue);
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
}
#endif

<commit_msg>Change opList-splitting reduction default to be off<commit_after>/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/gpu/GrContext.h"

#include "include/gpu/GrContextThreadSafeProxy.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrContextThreadSafeProxyPriv.h"
#include "src/gpu/GrGpu.h"

#include "src/gpu/effects/GrSkSLFP.h"
#include "src/gpu/gl/GrGLGpu.h"
#include "src/gpu/mock/GrMockGpu.h"
#include "src/gpu/text/GrStrikeCache.h"
#ifdef SK_METAL
#include "src/gpu/mtl/GrMtlTrampoline.h"
#endif
#ifdef SK_VULKAN
#include "src/gpu/vk/GrVkGpu.h"
#endif

#ifdef SK_DISABLE_REDUCE_OPLIST_SPLITTING
static const bool kDefaultReduceOpListSplitting = false;
#else
static const bool kDefaultReduceOpListSplitting = false;
#endif

class SK_API GrLegacyDirectContext : public GrContext {
public:
    GrLegacyDirectContext(GrBackendApi backend, const GrContextOptions& options)
            : INHERITED(backend, options)
            , fAtlasManager(nullptr) {
    }

    ~GrLegacyDirectContext() override {
        // this if-test protects against the case where the context is being destroyed
        // before having been fully created
        if (this->priv().getGpu()) {
            this->flush();
        }

        delete fAtlasManager;
    }

    void abandonContext() override {
        INHERITED::abandonContext();
        fAtlasManager->freeAll();
    }

    void releaseResourcesAndAbandonContext() override {
        INHERITED::releaseResourcesAndAbandonContext();
        fAtlasManager->freeAll();
    }

    void freeGpuResources() override {
        this->flush();
        fAtlasManager->freeAll();

        INHERITED::freeGpuResources();
    }

protected:
    bool init(sk_sp<const GrCaps> caps, sk_sp<GrSkSLFPFactoryCache> FPFactoryCache) override {
        SkASSERT(caps && !FPFactoryCache);
        SkASSERT(!fThreadSafeProxy);

        FPFactoryCache.reset(new GrSkSLFPFactoryCache());
        fThreadSafeProxy = GrContextThreadSafeProxyPriv::Make(this->backend(),
                                                              this->options(),
                                                              this->contextID(),
                                                              caps, FPFactoryCache);

        if (!INHERITED::init(std::move(caps), std::move(FPFactoryCache))) {
            return false;
        }

        bool reduceOpListSplitting = kDefaultReduceOpListSplitting;
        if (GrContextOptions::Enable::kNo == this->options().fReduceOpListSplitting) {
            reduceOpListSplitting = false;
        } else if (GrContextOptions::Enable::kYes == this->options().fReduceOpListSplitting) {
            reduceOpListSplitting = true;
        }

        this->setupDrawingManager(true, reduceOpListSplitting);

        SkASSERT(this->caps());

        GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
        if (GrContextOptions::Enable::kNo == this->options().fAllowMultipleGlyphCacheTextures ||
            // multitexturing supported only if range can represent the index + texcoords fully
            !(this->caps()->shaderCaps()->floatIs32Bits() ||
              this->caps()->shaderCaps()->integerSupport())) {
            allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
        } else {
            allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
        }

        GrStrikeCache* glyphCache = this->priv().getGrStrikeCache();
        GrProxyProvider* proxyProvider = this->priv().proxyProvider();

        fAtlasManager = new GrAtlasManager(proxyProvider, glyphCache,
                                           this->options().fGlyphCacheTextureMaximumBytes,
                                           allowMultitexturing);
        this->priv().addOnFlushCallbackObject(fAtlasManager);

        return true;
    }

    GrAtlasManager* onGetAtlasManager() override { return fAtlasManager; }

private:
    GrAtlasManager* fAtlasManager;

    typedef GrContext INHERITED;
};

sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface) {
    GrContextOptions defaultOptions;
    return MakeGL(std::move(interface), defaultOptions);
}

sk_sp<GrContext> GrContext::MakeGL(const GrContextOptions& options) {
    return MakeGL(nullptr, options);
}

sk_sp<GrContext> GrContext::MakeGL() {
    GrContextOptions defaultOptions;
    return MakeGL(nullptr, defaultOptions);
}

sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface,
                                   const GrContextOptions& options) {
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kOpenGL, options));

    context->fGpu = GrGLGpu::Make(std::move(interface), options, context.get());
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
}

sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) {
    GrContextOptions defaultOptions;
    return MakeMock(mockOptions, defaultOptions);
}

sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions,
                                     const GrContextOptions& options) {
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMock, options));

    context->fGpu = GrMockGpu::Make(mockOptions, options, context.get());
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
}

sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext& backendContext) {
#ifdef SK_VULKAN
    GrContextOptions defaultOptions;
    return MakeVulkan(backendContext, defaultOptions);
#else
    return nullptr;
#endif
}

sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext& backendContext,
                                       const GrContextOptions& options) {
#ifdef SK_VULKAN
    GrContextOptions defaultOptions;
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kVulkan, options));

    context->fGpu = GrVkGpu::Make(backendContext, options, context.get());
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
#else
    return nullptr;
#endif
}

#ifdef SK_METAL
sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) {
    GrContextOptions defaultOptions;
    return MakeMetal(device, queue, defaultOptions);
}

sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) {
    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMetal, options));

    context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue);
    if (!context->fGpu) {
        return nullptr;
    }

    if (!context->init(context->fGpu->refCaps(), nullptr)) {
        return nullptr;
    }
    return context;
}
#endif

<|endoftext|>