<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Research In Motion
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite 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 <qtest.h>
#include <QDebug>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <qqml.h>
#include <QMetaMethod>

#include "../../shared/util.h"

class ExportedClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int qmlObjectProp READ qmlObjectProp NOTIFY qmlObjectPropChanged)
    Q_PROPERTY(int cppObjectProp READ cppObjectProp NOTIFY cppObjectPropChanged)
    Q_PROPERTY(int unboundProp READ unboundProp NOTIFY unboundPropChanged)
    Q_PROPERTY(int v8BindingProp READ v8BindingProp NOTIFY v8BindingPropChanged)
    Q_PROPERTY(int v4BindingProp READ v4BindingProp NOTIFY v4BindingPropChanged)
    Q_PROPERTY(int v4BindingProp2 READ v4BindingProp2 NOTIFY v4BindingProp2Changed)
    Q_PROPERTY(int scriptBindingProp READ scriptBindingProp NOTIFY scriptBindingPropChanged)
public:
    int qmlObjectPropConnections;
    int cppObjectPropConnections;
    int unboundPropConnections;
    int v8BindingPropConnections;
    int v4BindingPropConnections;
    int v4BindingProp2Connections;
    int scriptBindingPropConnections;
    int boundSignalConnections;
    int unusedSignalConnections;

    ExportedClass()
        : qmlObjectPropConnections(0), cppObjectPropConnections(0), unboundPropConnections(0),
          v8BindingPropConnections(0), v4BindingPropConnections(0), v4BindingProp2Connections(0),
          scriptBindingPropConnections(0), boundSignalConnections(0), unusedSignalConnections(0)
    {}

    ~ExportedClass()
    {
        QCOMPARE(qmlObjectPropConnections, 0);
        QCOMPARE(cppObjectPropConnections, 0);
        QCOMPARE(unboundPropConnections, 0);
        QCOMPARE(v8BindingPropConnections, 0);
        QCOMPARE(v4BindingPropConnections, 0);
        QCOMPARE(v4BindingProp2Connections, 0);
        QCOMPARE(scriptBindingPropConnections, 0);
        QCOMPARE(boundSignalConnections, 0);
        QCOMPARE(unusedSignalConnections, 0);
    }

    int qmlObjectProp() const { return 42; }
    int unboundProp() const { return 42; }
    int v8BindingProp() const { return 42; }
    int v4BindingProp() const { return 42; }
    int v4BindingProp2() const { return 42; }
    int cppObjectProp() const { return 42; }
    int scriptBindingProp() const { return 42; }

    void verifyReceiverCount()
    {
        QCOMPARE(receivers(SIGNAL(qmlObjectPropChanged())), qmlObjectPropConnections);
        QCOMPARE(receivers(SIGNAL(cppObjectPropChanged())), cppObjectPropConnections);
        QCOMPARE(receivers(SIGNAL(unboundPropChanged())), unboundPropConnections);
        QCOMPARE(receivers(SIGNAL(v8BindingPropChanged())), v8BindingPropConnections);
        QCOMPARE(receivers(SIGNAL(v4BindingPropChanged())), v4BindingPropConnections);
        QCOMPARE(receivers(SIGNAL(v4BindingProp2Changed())), v4BindingProp2Connections);
        QCOMPARE(receivers(SIGNAL(scriptBindingPropChanged())), scriptBindingPropConnections);
        QCOMPARE(receivers(SIGNAL(boundSignal())), boundSignalConnections);
        QCOMPARE(receivers(SIGNAL(unusedSignal())), unusedSignalConnections);
    }

protected:
    void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
        if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections++;
        if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections++;
        if (signal.name() == "unboundPropChanged") unboundPropConnections++;
        if (signal.name() == "v8BindingPropChanged") v8BindingPropConnections++;
        if (signal.name() == "v4BindingPropChanged") v4BindingPropConnections++;
        if (signal.name() == "v4BindingProp2Changed") v4BindingProp2Connections++;
        if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections++;
        if (signal.name() == "boundSignal")   boundSignalConnections++;
        if (signal.name() == "unusedSignal") unusedSignalConnections++;
        verifyReceiverCount();
        //qDebug() << Q_FUNC_INFO << this << signal.name();
    }

    void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
        if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections--;
        if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections--;
        if (signal.name() == "unboundPropChanged") unboundPropConnections--;
        if (signal.name() == "v8BindingPropChanged") v8BindingPropConnections--;
        if (signal.name() == "v4BindingPropChanged") v4BindingPropConnections--;
        if (signal.name() == "v4BindingProp2Changed") v4BindingProp2Connections--;
        if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections--;
        if (signal.name() == "boundSignal")   boundSignalConnections--;
        if (signal.name() == "unusedSignal") unusedSignalConnections--;
        verifyReceiverCount();
        //qDebug() << Q_FUNC_INFO << this << signal.methodSignature();
    }

signals:
    void qmlObjectPropChanged();
    void cppObjectPropChanged();
    void unboundPropChanged();
    void v8BindingPropChanged();
    void v4BindingPropChanged();
    void v4BindingProp2Changed();
    void scriptBindingPropChanged();
    void boundSignal();
    void unusedSignal();
};

class tst_qqmlnotifier : public QQmlDataTest
{
    Q_OBJECT
public:
    tst_qqmlnotifier()
        : root(0), exportedClass(0), exportedObject(0)
    {}

private slots:
    void initTestCase() Q_DECL_OVERRIDE;
    void cleanupTestCase();
    void testConnectNotify();

    void removeV4Binding();
    void removeV4Binding2();
    void removeV8Binding();
    void removeScriptBinding();
    // No need to test value type proxy bindings - the user can't override disconnectNotify() anyway,
    // as the classes are private to the QML engine

    void readProperty();
    void propertyChange();
    void disconnectOnDestroy();

private:
    void createObjects();

    QQmlEngine engine;
    QObject *root;
    ExportedClass *exportedClass;
    ExportedClass *exportedObject;
};

void tst_qqmlnotifier::initTestCase()
{
    QQmlDataTest::initTestCase();
    qmlRegisterType<ExportedClass>("Test", 1, 0, "ExportedClass");
}

void tst_qqmlnotifier::createObjects()
{
    delete root;
    root = 0;
    exportedClass = exportedObject = 0;

    QQmlComponent component(&engine, testFileUrl("connectnotify.qml"));
    exportedObject = new ExportedClass();
    exportedObject->setObjectName("exportedObject");
    engine.rootContext()->setContextProperty("_exportedObject", exportedObject);
    root = component.create();
    QVERIFY(root != 0);

    exportedClass = qobject_cast<ExportedClass *>(
                root->findChild<ExportedClass*>("exportedClass"));
    QVERIFY(exportedClass != 0);
}

void tst_qqmlnotifier::cleanupTestCase()
{
    delete root;
    root = 0;
    delete exportedObject;
    exportedObject = 0;
}

void tst_qqmlnotifier::testConnectNotify()
{
    createObjects();

    QCOMPARE(exportedClass->qmlObjectPropConnections, 1);
    QCOMPARE(exportedClass->cppObjectPropConnections, 0);
    QCOMPARE(exportedClass->unboundPropConnections, 0);
    QCOMPARE(exportedClass->v8BindingPropConnections, 1);
    QCOMPARE(exportedClass->v4BindingPropConnections, 1);
    QCOMPARE(exportedClass->v4BindingProp2Connections, 2);
    QCOMPARE(exportedClass->scriptBindingPropConnections, 1);
    QCOMPARE(exportedClass->boundSignalConnections, 1);
    QCOMPARE(exportedClass->unusedSignalConnections, 0);
    exportedClass->verifyReceiverCount();

    QCOMPARE(exportedObject->qmlObjectPropConnections, 0);
    QCOMPARE(exportedObject->cppObjectPropConnections, 1);
    QCOMPARE(exportedObject->unboundPropConnections, 0);
    QCOMPARE(exportedObject->v8BindingPropConnections, 0);
    QCOMPARE(exportedObject->v4BindingPropConnections, 0);
    QCOMPARE(exportedObject->v4BindingProp2Connections, 0);
    QCOMPARE(exportedObject->scriptBindingPropConnections, 0);
    QCOMPARE(exportedObject->boundSignalConnections, 0);
    QCOMPARE(exportedObject->unusedSignalConnections, 0);
    exportedObject->verifyReceiverCount();
}

void tst_qqmlnotifier::removeV4Binding()
{
    createObjects();

    // Removing a binding should disconnect all of its guarded properties
    QVERIFY(QMetaObject::invokeMethod(root, "removeV4Binding"));
    QCOMPARE(exportedClass->v4BindingPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::removeV4Binding2()
{
    createObjects();

    // In this case, the v4BindingProp2 property is used by two v4 bindings.
    // Make sure that removing one binding doesn't by accident disconnect all.
    QVERIFY(QMetaObject::invokeMethod(root, "removeV4Binding2"));
    QCOMPARE(exportedClass->v4BindingProp2Connections, 1);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::removeV8Binding()
{
    createObjects();

    // Removing a binding should disconnect all of its guarded properties
    QVERIFY(QMetaObject::invokeMethod(root, "removeV8Binding"));
    QCOMPARE(exportedClass->v8BindingPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::removeScriptBinding()
{
    createObjects();

    // Removing a binding should disconnect all of its guarded properties
    QVERIFY(QMetaObject::invokeMethod(root, "removeScriptBinding"));
    QCOMPARE(exportedClass->scriptBindingPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::readProperty()
{
    createObjects();

    // Reading a property should not connect to it
    QVERIFY(QMetaObject::invokeMethod(root, "readProperty"));
    QCOMPARE(exportedClass->unboundPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::propertyChange()
{
    createObjects();

    // Changing the state will trigger the PropertyChange to overwrite a value with a binding.
    // For this, the new binding needs to be connected, and afterwards disconnected.
    QVERIFY(QMetaObject::invokeMethod(root, "changeState"));
    QCOMPARE(exportedClass->unboundPropConnections, 1);
    exportedClass->verifyReceiverCount();
    QVERIFY(QMetaObject::invokeMethod(root, "changeState"));
    QCOMPARE(exportedClass->unboundPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::disconnectOnDestroy()
{
    createObjects();

    // Deleting a QML object should remove all connections. For exportedClass, this is tested in
    // the destructor, and for exportedObject, it is tested below.
    delete root;
    root = 0;
    QCOMPARE(exportedObject->cppObjectPropConnections, 0);
    exportedObject->verifyReceiverCount();
}

QTEST_MAIN(tst_qqmlnotifier)

#include "tst_qqmlnotifier.moc"
<commit_msg>Don't call receivers from disconnectNotify<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Research In Motion
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite 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 <qtest.h>
#include <QDebug>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <qqml.h>
#include <QMetaMethod>

#include "../../shared/util.h"

class ExportedClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int qmlObjectProp READ qmlObjectProp NOTIFY qmlObjectPropChanged)
    Q_PROPERTY(int cppObjectProp READ cppObjectProp NOTIFY cppObjectPropChanged)
    Q_PROPERTY(int unboundProp READ unboundProp NOTIFY unboundPropChanged)
    Q_PROPERTY(int v8BindingProp READ v8BindingProp NOTIFY v8BindingPropChanged)
    Q_PROPERTY(int v4BindingProp READ v4BindingProp NOTIFY v4BindingPropChanged)
    Q_PROPERTY(int v4BindingProp2 READ v4BindingProp2 NOTIFY v4BindingProp2Changed)
    Q_PROPERTY(int scriptBindingProp READ scriptBindingProp NOTIFY scriptBindingPropChanged)
public:
    int qmlObjectPropConnections;
    int cppObjectPropConnections;
    int unboundPropConnections;
    int v8BindingPropConnections;
    int v4BindingPropConnections;
    int v4BindingProp2Connections;
    int scriptBindingPropConnections;
    int boundSignalConnections;
    int unusedSignalConnections;

    ExportedClass()
        : qmlObjectPropConnections(0), cppObjectPropConnections(0), unboundPropConnections(0),
          v8BindingPropConnections(0), v4BindingPropConnections(0), v4BindingProp2Connections(0),
          scriptBindingPropConnections(0), boundSignalConnections(0), unusedSignalConnections(0)
    {}

    ~ExportedClass()
    {
        QCOMPARE(qmlObjectPropConnections, 0);
        QCOMPARE(cppObjectPropConnections, 0);
        QCOMPARE(unboundPropConnections, 0);
        QCOMPARE(v8BindingPropConnections, 0);
        QCOMPARE(v4BindingPropConnections, 0);
        QCOMPARE(v4BindingProp2Connections, 0);
        QCOMPARE(scriptBindingPropConnections, 0);
        QCOMPARE(boundSignalConnections, 0);
        QCOMPARE(unusedSignalConnections, 0);
    }

    int qmlObjectProp() const { return 42; }
    int unboundProp() const { return 42; }
    int v8BindingProp() const { return 42; }
    int v4BindingProp() const { return 42; }
    int v4BindingProp2() const { return 42; }
    int cppObjectProp() const { return 42; }
    int scriptBindingProp() const { return 42; }

    void verifyReceiverCount()
    {
        //Note: QTBUG-34829 means we can't call this from within disconnectNotify or it can lock
        QCOMPARE(receivers(SIGNAL(qmlObjectPropChanged())), qmlObjectPropConnections);
        QCOMPARE(receivers(SIGNAL(cppObjectPropChanged())), cppObjectPropConnections);
        QCOMPARE(receivers(SIGNAL(unboundPropChanged())), unboundPropConnections);
        QCOMPARE(receivers(SIGNAL(v8BindingPropChanged())), v8BindingPropConnections);
        QCOMPARE(receivers(SIGNAL(v4BindingPropChanged())), v4BindingPropConnections);
        QCOMPARE(receivers(SIGNAL(v4BindingProp2Changed())), v4BindingProp2Connections);
        QCOMPARE(receivers(SIGNAL(scriptBindingPropChanged())), scriptBindingPropConnections);
        QCOMPARE(receivers(SIGNAL(boundSignal())), boundSignalConnections);
        QCOMPARE(receivers(SIGNAL(unusedSignal())), unusedSignalConnections);
    }

protected:
    void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
        if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections++;
        if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections++;
        if (signal.name() == "unboundPropChanged") unboundPropConnections++;
        if (signal.name() == "v8BindingPropChanged") v8BindingPropConnections++;
        if (signal.name() == "v4BindingPropChanged") v4BindingPropConnections++;
        if (signal.name() == "v4BindingProp2Changed") v4BindingProp2Connections++;
        if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections++;
        if (signal.name() == "boundSignal")   boundSignalConnections++;
        if (signal.name() == "unusedSignal") unusedSignalConnections++;
        verifyReceiverCount();
        //qDebug() << Q_FUNC_INFO << this << signal.name();
    }

    void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE {
        if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections--;
        if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections--;
        if (signal.name() == "unboundPropChanged") unboundPropConnections--;
        if (signal.name() == "v8BindingPropChanged") v8BindingPropConnections--;
        if (signal.name() == "v4BindingPropChanged") v4BindingPropConnections--;
        if (signal.name() == "v4BindingProp2Changed") v4BindingProp2Connections--;
        if (signal.name() == "scriptBindingPropChanged") scriptBindingPropConnections--;
        if (signal.name() == "boundSignal")   boundSignalConnections--;
        if (signal.name() == "unusedSignal") unusedSignalConnections--;
        //qDebug() << Q_FUNC_INFO << this << signal.methodSignature();
    }

signals:
    void qmlObjectPropChanged();
    void cppObjectPropChanged();
    void unboundPropChanged();
    void v8BindingPropChanged();
    void v4BindingPropChanged();
    void v4BindingProp2Changed();
    void scriptBindingPropChanged();
    void boundSignal();
    void unusedSignal();
};

class tst_qqmlnotifier : public QQmlDataTest
{
    Q_OBJECT
public:
    tst_qqmlnotifier()
        : root(0), exportedClass(0), exportedObject(0)
    {}

private slots:
    void initTestCase() Q_DECL_OVERRIDE;
    void cleanupTestCase();
    void testConnectNotify();

    void removeV4Binding();
    void removeV4Binding2();
    void removeV8Binding();
    void removeScriptBinding();
    // No need to test value type proxy bindings - the user can't override disconnectNotify() anyway,
    // as the classes are private to the QML engine

    void readProperty();
    void propertyChange();
    void disconnectOnDestroy();

private:
    void createObjects();

    QQmlEngine engine;
    QObject *root;
    ExportedClass *exportedClass;
    ExportedClass *exportedObject;
};

void tst_qqmlnotifier::initTestCase()
{
    QQmlDataTest::initTestCase();
    qmlRegisterType<ExportedClass>("Test", 1, 0, "ExportedClass");
}

void tst_qqmlnotifier::createObjects()
{
    delete root;
    root = 0;
    exportedClass = exportedObject = 0;

    QQmlComponent component(&engine, testFileUrl("connectnotify.qml"));
    exportedObject = new ExportedClass();
    exportedObject->setObjectName("exportedObject");
    engine.rootContext()->setContextProperty("_exportedObject", exportedObject);
    root = component.create();
    QVERIFY(root != 0);

    exportedClass = qobject_cast<ExportedClass *>(
                root->findChild<ExportedClass*>("exportedClass"));
    QVERIFY(exportedClass != 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::cleanupTestCase()
{
    delete root;
    root = 0;
    delete exportedObject;
    exportedObject = 0;
}

void tst_qqmlnotifier::testConnectNotify()
{
    createObjects();

    QCOMPARE(exportedClass->qmlObjectPropConnections, 1);
    QCOMPARE(exportedClass->cppObjectPropConnections, 0);
    QCOMPARE(exportedClass->unboundPropConnections, 0);
    QCOMPARE(exportedClass->v8BindingPropConnections, 1);
    QCOMPARE(exportedClass->v4BindingPropConnections, 1);
    QCOMPARE(exportedClass->v4BindingProp2Connections, 2);
    QCOMPARE(exportedClass->scriptBindingPropConnections, 1);
    QCOMPARE(exportedClass->boundSignalConnections, 1);
    QCOMPARE(exportedClass->unusedSignalConnections, 0);
    exportedClass->verifyReceiverCount();

    QCOMPARE(exportedObject->qmlObjectPropConnections, 0);
    QCOMPARE(exportedObject->cppObjectPropConnections, 1);
    QCOMPARE(exportedObject->unboundPropConnections, 0);
    QCOMPARE(exportedObject->v8BindingPropConnections, 0);
    QCOMPARE(exportedObject->v4BindingPropConnections, 0);
    QCOMPARE(exportedObject->v4BindingProp2Connections, 0);
    QCOMPARE(exportedObject->scriptBindingPropConnections, 0);
    QCOMPARE(exportedObject->boundSignalConnections, 0);
    QCOMPARE(exportedObject->unusedSignalConnections, 0);
    exportedObject->verifyReceiverCount();
}

void tst_qqmlnotifier::removeV4Binding()
{
    createObjects();

    // Removing a binding should disconnect all of its guarded properties
    QVERIFY(QMetaObject::invokeMethod(root, "removeV4Binding"));
    QCOMPARE(exportedClass->v4BindingPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::removeV4Binding2()
{
    createObjects();

    // In this case, the v4BindingProp2 property is used by two v4 bindings.
    // Make sure that removing one binding doesn't by accident disconnect all.
    QVERIFY(QMetaObject::invokeMethod(root, "removeV4Binding2"));
    QCOMPARE(exportedClass->v4BindingProp2Connections, 1);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::removeV8Binding()
{
    createObjects();

    // Removing a binding should disconnect all of its guarded properties
    QVERIFY(QMetaObject::invokeMethod(root, "removeV8Binding"));
    QCOMPARE(exportedClass->v8BindingPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::removeScriptBinding()
{
    createObjects();

    // Removing a binding should disconnect all of its guarded properties
    QVERIFY(QMetaObject::invokeMethod(root, "removeScriptBinding"));
    QCOMPARE(exportedClass->scriptBindingPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::readProperty()
{
    createObjects();

    // Reading a property should not connect to it
    QVERIFY(QMetaObject::invokeMethod(root, "readProperty"));
    QCOMPARE(exportedClass->unboundPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::propertyChange()
{
    createObjects();

    // Changing the state will trigger the PropertyChange to overwrite a value with a binding.
    // For this, the new binding needs to be connected, and afterwards disconnected.
    QVERIFY(QMetaObject::invokeMethod(root, "changeState"));
    QCOMPARE(exportedClass->unboundPropConnections, 1);
    exportedClass->verifyReceiverCount();
    QVERIFY(QMetaObject::invokeMethod(root, "changeState"));
    QCOMPARE(exportedClass->unboundPropConnections, 0);
    exportedClass->verifyReceiverCount();
}

void tst_qqmlnotifier::disconnectOnDestroy()
{
    createObjects();

    // Deleting a QML object should remove all connections. For exportedClass, this is tested in
    // the destructor, and for exportedObject, it is tested below.
    delete root;
    root = 0;
    QCOMPARE(exportedObject->cppObjectPropConnections, 0);
    exportedObject->verifyReceiverCount();
}

QTEST_MAIN(tst_qqmlnotifier)

#include "tst_qqmlnotifier.moc"
<|endoftext|>


<commit_before>/**
 * Package: eVias Core unitary tests
 *
 * Copyright (c) 2010 - 2011 Grégory Saive
 *
 * For more informations about the licensing of this product, please refer
 * to the LICENCE file in the root application directory.
 *
 */

#include "../core/string_utils.hpp"
#include "../application/console.hpp"
#include "library_test_suite.hpp"

// unitary test classes include

#include <vector>
#include <string>

int main (int argc, char* args[])
{
	using namespace std;
    using evias::core::test::eviasTestSuite;
    using evias::core::test::testResult;
    using evias::application::consoleParser;
    using evias::core::in_vector;

    string project = "eVias C++ library unitary test suite";
    string usage = " \
        ./suite_execution.exe [--skip config,json,sqlobjects,views,dbobjects,network,regexp] \
                              [--only config,json,sqlobjects,views,dbobjects,network,regexp]  \
                              [--verbosity quiet|normal|verbose] \
    ";
    consoleParser* suiteCallArgs = new consoleParser(project, usage, argc, args);
    suiteCallArgs->canEmptyCall(true)
                 ->addAllowedArg("--skip")
                 ->addAllowedArg("--only")
                 ->addAllowedArg("--verbosity")
                 ->parseAll();

    map<string,string> callArgs = suiteCallArgs->readData();

    // suite execution call configuration

    // basically we test everything.
    bool testConfigFiles = true;
    bool testJson        = true;
    bool testSqlObjects  = true;
    bool testViews       = true;
    bool testDbObjects   = true;
    bool testNetwork     = true;
    bool testRegExp      = true;

    bool hasVerb = (callArgs.find("--verbosity") != callArgs.end());
    bool hasOnly = (callArgs.find("--only") != callArgs.end());
    bool hasSkip = (callArgs.find("--skip") != callArgs.end());

    // callArg[KEY] access facility
    string usingOption = "default";
    if (hasOnly && callArgs["--only"].size() > 0) {
        usingOption = "--only";
    }
    else if (hasSkip && callArgs["--skip"].size() > 0) {
        usingOption = "--skip";
    }

    // get verbosity configuration (or not)..
    int verbosity = evias::core::test::VERBOSE;
    if (hasVerb && callArgs["--verbosity"].size() > 0) {
        string sv = callArgs["--verbosity"];

        if (sv == "1") verbosity = evias::core::test::QUIET;
        else if (sv == "2") verbosity = evias::core::test::NORMAL;
    }

    // process call arguments
    if (usingOption == "--only" || usingOption == "--skip") {
        // we have a workable option (size > 0)

        vector<string> optionKeys;
        string optionData = callArgs[usingOption];

        evias::core::trim(optionData, " ");
        if (optionData.find(",") != string::npos)
            optionKeys = evias::core::split(optionData.append(","), ','); // multi key ',' separated
        else
            optionKeys.push_back(optionData); // single key

        // if we are in "skip mode" => we test everything except present key(s)
        // if we are in "only mode" => we test nothing but present key(s)
        bool initTest = true; // everything
        if (usingOption == "--only") {
            initTest = false;
        }

        testConfigFiles = testJson = testSqlObjects = testViews = testDbObjects = testNetwork = testRegExp = (initTest);

        // present in option key(s) means having to change the data
        if (in_vector("config", optionKeys))     testConfigFiles  = ! initTest;
        if (in_vector("json", optionKeys))       testJson         = ! initTest;
        if (in_vector("sqlobjects", optionKeys)) testSqlObjects   = ! initTest;
        if (in_vector("views", optionKeys))      testViews        = ! initTest;
        if (in_vector("dbobjects", optionKeys))  testDbObjects    = ! initTest;
        if (in_vector("network", optionKeys))    testNetwork      = ! initTest;
        if (in_vector("regexp", optionKeys))     testRegExp       = ! initTest;
    }

    // configure the test suite
    eviasTestSuite* librarySuite = new eviasTestSuite();

    // configure suite
    librarySuite->setVerbosity((evias::core::test::unitTestVerbosity)verbosity);
    librarySuite->setTestConfig(testConfigFiles)
                ->setTestJSON(testJson)
                ->setTestSQL(testSqlObjects)
                ->setTestViews(testViews)
                ->setTestDatabase(testDbObjects)
                ->setTestNetwork(testNetwork)
                ->setTestRegExp(testRegExp);

    // execute suite
    librarySuite->bootstrap(argc, args);
    int returnCode = librarySuite->execute();
    librarySuite->shutdown();

    delete librarySuite;

    return returnCode;
}

<commit_msg>change 'regexp' to 'regex' ; add --verbosity values, now 'quiet' and 'normal' are ok<commit_after>/**
 * Package: eVias Core unitary tests
 *
 * Copyright (c) 2010 - 2011 Grégory Saive
 *
 * For more informations about the licensing of this product, please refer
 * to the LICENCE file in the root application directory.
 *
 */

#include "../core/string_utils.hpp"
#include "../application/console.hpp"
#include "library_test_suite.hpp"

// unitary test classes include

#include <vector>
#include <string>

int main (int argc, char* args[])
{
	using namespace std;
    using evias::core::test::eviasTestSuite;
    using evias::core::test::testResult;
    using evias::application::consoleParser;
    using evias::core::in_vector;

    string project = "eVias C++ library unitary test suite";
    string usage = " \
        ./suite_execution.exe [--skip config,json,sqlobjects,views,dbobjects,network,regex] \
                              [--only config,json,sqlobjects,views,dbobjects,network,regex]  \
                              [--verbosity quiet|normal|verbose] \
    ";
    consoleParser* suiteCallArgs = new consoleParser(project, usage, argc, args);
    suiteCallArgs->canEmptyCall(true)
                 ->addAllowedArg("--skip")
                 ->addAllowedArg("--only")
                 ->addAllowedArg("--verbosity")
                 ->parseAll();

    map<string,string> callArgs = suiteCallArgs->readData();

    // suite execution call configuration

    // basically we test everything.
    bool testConfigFiles = true;
    bool testJson        = true;
    bool testSqlObjects  = true;
    bool testViews       = true;
    bool testDbObjects   = true;
    bool testNetwork     = true;
    bool testRegExp      = true;

    bool hasVerb = (callArgs.find("--verbosity") != callArgs.end());
    bool hasOnly = (callArgs.find("--only") != callArgs.end());
    bool hasSkip = (callArgs.find("--skip") != callArgs.end());

    // callArg[KEY] access facility
    string usingOption = "default";
    if (hasOnly && callArgs["--only"].size() > 0) {
        usingOption = "--only";
    }
    else if (hasSkip && callArgs["--skip"].size() > 0) {
        usingOption = "--skip";
    }

    // get verbosity configuration (or not)..
    int verbosity = evias::core::test::VERBOSE;
    if (hasVerb && callArgs["--verbosity"].size() > 0) {
        string sv = callArgs["--verbosity"];

        if (sv == "1" || sv == "quiet") verbosity = evias::core::test::QUIET;
        else if (sv == "2" || sv == "normal") verbosity = evias::core::test::NORMAL;
    }

    // process call arguments
    if (usingOption == "--only" || usingOption == "--skip") {
        // we have a workable option (size > 0)

        vector<string> optionKeys;
        string optionData = callArgs[usingOption];

        evias::core::trim(optionData, " ");
        if (optionData.find(",") != string::npos)
            optionKeys = evias::core::split(optionData.append(","), ','); // multi key ',' separated
        else
            optionKeys.push_back(optionData); // single key

        // if we are in "skip mode" => we test everything except present key(s)
        // if we are in "only mode" => we test nothing but present key(s)
        bool initTest = true; // everything
        if (usingOption == "--only") {
            initTest = false;
        }

        testConfigFiles = testJson = testSqlObjects = testViews = testDbObjects = testNetwork = testRegExp = (initTest);

        // present in option key(s) means having to change the data
        if (in_vector("config", optionKeys))     testConfigFiles  = ! initTest;
        if (in_vector("json", optionKeys))       testJson         = ! initTest;
        if (in_vector("sqlobjects", optionKeys)) testSqlObjects   = ! initTest;
        if (in_vector("views", optionKeys))      testViews        = ! initTest;
        if (in_vector("dbobjects", optionKeys))  testDbObjects    = ! initTest;
        if (in_vector("network", optionKeys))    testNetwork      = ! initTest;
        if (in_vector("regex", optionKeys))      testRegExp       = ! initTest;
    }

    // configure the test suite
    eviasTestSuite* librarySuite = new eviasTestSuite();

    // configure suite
    librarySuite->setVerbosity((evias::core::test::unitTestVerbosity)verbosity);
    librarySuite->setTestConfig(testConfigFiles)
                ->setTestJSON(testJson)
                ->setTestSQL(testSqlObjects)
                ->setTestViews(testViews)
                ->setTestDatabase(testDbObjects)
                ->setTestNetwork(testNetwork)
                ->setTestRegExp(testRegExp);

    // execute suite
    librarySuite->bootstrap(argc, args);
    int returnCode = librarySuite->execute();
    librarySuite->shutdown();

    delete librarySuite;

    return returnCode;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2013 Jeremie Roy. All rights reserved.
 * License: http://www.opensource.org/licenses/BSD-2-Clause
 */

#include "common.h"

#include <bgfx.h>
#include <bx/timer.h>
#include <bx/fpumath.h>

#include "font/font_manager.h"
#include "font/text_metrics.h"
#include "font/text_buffer_manager.h"
#include "imgui/imgui.h"

#include <stdio.h>
#include <string.h>

long int fsize(FILE* _file)
{
	long int pos = ftell(_file);
	fseek(_file, 0L, SEEK_END);
	long int size = ftell(_file);
	fseek(_file, pos, SEEK_SET);
	return size;
}

static char* loadText(const char* _filePath)
{
	FILE* file = fopen(_filePath, "rb");
	if (NULL != file)
	{
		uint32_t size = (uint32_t)fsize(file);
		char* mem = (char*)malloc(size+1);
		size_t ignore = fread(mem, 1, size, file);
		BX_UNUSED(ignore);
		fclose(file);
		mem[size-1] = '\0';
		return mem;
	}

	return NULL;
}

TrueTypeHandle loadTtf(FontManager* _fm, const char* _filePath)
{
	FILE* file = fopen(_filePath, "rb");
	if (NULL != file)
	{
		uint32_t size = (uint32_t)fsize(file);
		uint8_t* mem = (uint8_t*)malloc(size+1);
		size_t ignore = fread(mem, 1, size, file);
		BX_UNUSED(ignore);
		fclose(file);
		mem[size-1] = '\0';
		TrueTypeHandle handle = _fm->createTtf(mem, size);
		free(mem);
		return handle;
	}

	TrueTypeHandle invalid = BGFX_INVALID_HANDLE;
	return invalid;
}

int _main_(int /*_argc*/, char** /*_argv*/)
{
	uint32_t width = 1280;
	uint32_t height = 720;
	uint32_t debug = BGFX_DEBUG_TEXT;
	uint32_t reset = BGFX_RESET_VSYNC;

	bgfx::init();

	bgfx::reset(width, height, reset);

	// Enable debug text.
	bgfx::setDebug(debug);

	// Set view 0 clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT
		, 0x303030ff
		, 1.0f
		, 0
		);

	FILE* file = fopen("font/droidsans.ttf", "rb");
	uint32_t size = (uint32_t)fsize(file);
	void* data = malloc(size);
	size_t ignore = fread(data, 1, size, file);
	BX_UNUSED(ignore);
	fclose(file);

	imguiCreate(data);

	free(data);

	char* bigText = loadText( "text/sherlock_holmes_a_scandal_in_bohemia_arthur_conan_doyle.txt");

	// Init the text rendering system.
	FontManager* fontManager = new FontManager(512);
	TextBufferManager* textBufferManager = new TextBufferManager(fontManager);

	TrueTypeHandle font = loadTtf(fontManager, "font/special_elite.ttf");

	// Create a distance field font.
	FontHandle fontSdf = fontManager->createFontByPixelSize(font, 0, 48, FONT_TYPE_DISTANCE);

	// Create a scaled down version of the same font (without adding anything to the atlas).
	FontHandle fontScaled = fontManager->createScaledFontToPixelSize(fontSdf, 14);

	TextLineMetrics metrics(fontManager->getFontInfo(fontScaled) );
	uint32_t lineCount = metrics.getLineCount(bigText);

	float visibleLineCount = 20.0f;

	const char* textBegin = 0;
	const char* textEnd = 0;
	metrics.getSubText(bigText, 0, (uint32_t)visibleLineCount, textBegin, textEnd);

	TextBufferHandle scrollableBuffer = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, BufferType::Transient);
	textBufferManager->setTextColor(scrollableBuffer, 0xFFFFFFFF);

	textBufferManager->appendText(scrollableBuffer, fontScaled, textBegin, textEnd);

	entry::MouseState mouseState;
	int32_t scrollArea = 0;
	const int32_t guiPanelWidth = 250;
	const int32_t guiPanelHeight = 200;
	float textScroll = 0.0f;
	float textRotation = 0.0f;
	float textScale = 1.0f;
	float textSize = 14.0f;

	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
	{
		imguiBeginFrame(mouseState.m_mx
			, mouseState.m_my
			, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT  : 0)
			| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
			, 0
			, width
			, height
			);

		imguiBeginScrollArea("Text Area"
			, width - guiPanelWidth - 10
			, 10
			, guiPanelWidth
			, guiPanelHeight
			, &scrollArea
			);
		imguiSeparatorLine();

		bool recomputeVisibleText = false;
		recomputeVisibleText |= imguiSlider("Number of lines", visibleLineCount, 1.0f, 177.0f , 1.0f);
		if (imguiSlider("Font size", textSize, 6.0f, 64.0f , 1.0f) )
		{
			fontManager->destroyFont(fontScaled);
			fontScaled = fontManager->createScaledFontToPixelSize(fontSdf, (uint32_t) textSize);
			metrics = TextLineMetrics(fontManager->getFontInfo(fontScaled) );
			recomputeVisibleText = true;
		}

		recomputeVisibleText |= imguiSlider("Scroll", textScroll, 0.0f, (lineCount-visibleLineCount) , 1.0f);
		imguiSlider("Rotate", textRotation, 0.0f, bx::pi*2.0f , 0.1f);
		recomputeVisibleText |= imguiSlider("Scale", textScale, 0.1f, 10.0f , 0.1f);

		if (recomputeVisibleText)
		{
			textBufferManager->clearTextBuffer(scrollableBuffer);
			metrics.getSubText(bigText,(uint32_t)textScroll, (uint32_t)(textScroll+visibleLineCount), textBegin, textEnd);
			textBufferManager->appendText(scrollableBuffer, fontScaled, textBegin, textEnd);
		}

		imguiEndScrollArea();

		imguiEndFrame();

		// Set view 0 default viewport.
		bgfx::setViewRect(0, 0, 0, width, height);

		// This dummy draw call is here to make sure that view 0 is cleared
		// if no other draw calls are submitted to view 0.
		bgfx::submit(0);

		int64_t now = bx::getHPCounter();
		static int64_t last = now;
		const int64_t frameTime = now - last;
		last = now;
		const double freq = double(bx::getHPFrequency() );
		const double toMs = 1000.0 / freq;

		// Use debug font to print32_t information about this example.
		bgfx::dbgTextClear();
		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontsdf");
		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of various size.");
		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime) * toMs);

		float at[3]  = { 0, 0, 0.0f };
		float eye[3] = {0, 0, -1.0f };

		float view[16];
		bx::mtxLookAt(view, eye, at);

		const float centering = 0.5f;

		// Setup a top-left ortho matrix for screen space drawing.
		const bgfx::HMD* hmd = bgfx::getHMD();
		if (NULL != hmd)
		{
			float proj[16];
			bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f);

			static float time = 0.0f;
			time += 0.05f;

			const float dist = 10.0f;
			const float offset0 = -proj[8] + (hmd->eye[0].adjust[0] / dist * proj[0]);
			const float offset1 = -proj[8] + (hmd->eye[1].adjust[0] / dist * proj[0]);

			float ortho[2][16];
			const float viewOffset = width/4.0f;
			const float viewWidth  = width/2.0f;
			bx::mtxOrtho(ortho[0], centering + viewOffset, centering + viewOffset + viewWidth, height + centering, centering, -1.0f, 1.0f, offset0);
			bx::mtxOrtho(ortho[1], centering + viewOffset, centering + viewOffset + viewWidth, height + centering, centering, -1.0f, 1.0f, offset1);
			bgfx::setViewTransform(0, view, ortho[0], BGFX_VIEW_STEREO, ortho[1]);
			bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height);
		}
		else
		{
			float ortho[16];
			bx::mtxOrtho(ortho, centering, width + centering, height + centering, centering, -1.0f, 1.0f);
			bgfx::setViewTransform(0, view, ortho);
			bgfx::setViewRect(0, 0, 0, width, height);
		}

		//very crude approximation :(
		float textAreaWidth = 0.5f * 66.0f * fontManager->getFontInfo(fontScaled).maxAdvanceWidth;

		float textRotMat[16];
		float textCenterMat[16];
		float textScaleMat[16];
		float screenCenterMat[16];

		bx::mtxRotateZ(textRotMat, textRotation);
		bx::mtxTranslate(textCenterMat, -(textAreaWidth * 0.5f), (-visibleLineCount)*metrics.getLineHeight()*0.5f, 0);
		bx::mtxScale(textScaleMat, textScale, textScale, 1.0f);
		bx::mtxTranslate(screenCenterMat, ( (width) * 0.5f), ( (height) * 0.5f), 0);

		//first translate to text center, then scale, then rotate
		float tmpMat[16];
		bx::mtxMul(tmpMat, textCenterMat, textRotMat);

		float tmpMat2[16];
		bx::mtxMul(tmpMat2, tmpMat, textScaleMat);

		float tmpMat3[16];
		bx::mtxMul(tmpMat3, tmpMat2, screenCenterMat);

		// Set model matrix for rendering.
		bgfx::setTransform(tmpMat3);

		// Draw your text.
		textBufferManager->submitTextBuffer(scrollableBuffer, 0);

		// Advance to next frame. Rendering thread will be kicked to
		// process submitted rendering primitives.
		bgfx::frame();
	}

	imguiDestroy();

	free(bigText);

	fontManager->destroyTtf(font);
	// Destroy the fonts.
	fontManager->destroyFont(fontSdf);
	fontManager->destroyFont(fontScaled);

	textBufferManager->destroyTextBuffer(scrollableBuffer);

	delete textBufferManager;
	delete fontManager;

	// Shutdown bgfx.
	bgfx::shutdown();

	return 0;
}
<commit_msg>Fixed compile error.<commit_after>/*
 * Copyright 2013 Jeremie Roy. All rights reserved.
 * License: http://www.opensource.org/licenses/BSD-2-Clause
 */

#include "common.h"

#include <bgfx.h>
#include <bx/timer.h>
#include <bx/fpumath.h>

#include "font/font_manager.h"
#include "font/text_metrics.h"
#include "font/text_buffer_manager.h"
#include "imgui/imgui.h"

#include <stdio.h>
#include <string.h>

long int fsize(FILE* _file)
{
	long int pos = ftell(_file);
	fseek(_file, 0L, SEEK_END);
	long int size = ftell(_file);
	fseek(_file, pos, SEEK_SET);
	return size;
}

static char* loadText(const char* _filePath)
{
	FILE* file = fopen(_filePath, "rb");
	if (NULL != file)
	{
		uint32_t size = (uint32_t)fsize(file);
		char* mem = (char*)malloc(size+1);
		size_t ignore = fread(mem, 1, size, file);
		BX_UNUSED(ignore);
		fclose(file);
		mem[size-1] = '\0';
		return mem;
	}

	return NULL;
}

TrueTypeHandle loadTtf(FontManager* _fm, const char* _filePath)
{
	FILE* file = fopen(_filePath, "rb");
	if (NULL != file)
	{
		uint32_t size = (uint32_t)fsize(file);
		uint8_t* mem = (uint8_t*)malloc(size+1);
		size_t ignore = fread(mem, 1, size, file);
		BX_UNUSED(ignore);
		fclose(file);
		mem[size-1] = '\0';
		TrueTypeHandle handle = _fm->createTtf(mem, size);
		free(mem);
		return handle;
	}

	TrueTypeHandle invalid = BGFX_INVALID_HANDLE;
	return invalid;
}

int _main_(int /*_argc*/, char** /*_argv*/)
{
	uint32_t width = 1280;
	uint32_t height = 720;
	uint32_t debug = BGFX_DEBUG_TEXT;
	uint32_t reset = BGFX_RESET_VSYNC;

	bgfx::init();

	bgfx::reset(width, height, reset);

	// Enable debug text.
	bgfx::setDebug(debug);

	// Set view 0 clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT
		, 0x303030ff
		, 1.0f
		, 0
		);

	FILE* file = fopen("font/droidsans.ttf", "rb");
	uint32_t size = (uint32_t)fsize(file);
	void* data = malloc(size);
	size_t ignore = fread(data, 1, size, file);
	BX_UNUSED(ignore);
	fclose(file);

	imguiCreate(data);

	free(data);

	char* bigText = loadText( "text/sherlock_holmes_a_scandal_in_bohemia_arthur_conan_doyle.txt");

	// Init the text rendering system.
	FontManager* fontManager = new FontManager(512);
	TextBufferManager* textBufferManager = new TextBufferManager(fontManager);

	TrueTypeHandle font = loadTtf(fontManager, "font/special_elite.ttf");

	// Create a distance field font.
	FontHandle fontSdf = fontManager->createFontByPixelSize(font, 0, 48, FONT_TYPE_DISTANCE);

	// Create a scaled down version of the same font (without adding anything to the atlas).
	FontHandle fontScaled = fontManager->createScaledFontToPixelSize(fontSdf, 14);

	TextLineMetrics metrics(fontManager->getFontInfo(fontScaled) );
	uint32_t lineCount = metrics.getLineCount(bigText);

	float visibleLineCount = 20.0f;

	const char* textBegin = 0;
	const char* textEnd = 0;
	metrics.getSubText(bigText, 0, (uint32_t)visibleLineCount, textBegin, textEnd);

	TextBufferHandle scrollableBuffer = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, BufferType::Transient);
	textBufferManager->setTextColor(scrollableBuffer, 0xFFFFFFFF);

	textBufferManager->appendText(scrollableBuffer, fontScaled, textBegin, textEnd);

	entry::MouseState mouseState;
	int32_t scrollArea = 0;
	const int32_t guiPanelWidth = 250;
	const int32_t guiPanelHeight = 200;
	float textScroll = 0.0f;
	float textRotation = 0.0f;
	float textScale = 1.0f;
	float textSize = 14.0f;

	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
	{
		imguiBeginFrame(mouseState.m_mx
			, mouseState.m_my
			, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT  : 0)
			| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
			, 0
			, width
			, height
			);

		imguiBeginScrollArea("Text Area"
			, width - guiPanelWidth - 10
			, 10
			, guiPanelWidth
			, guiPanelHeight
			, &scrollArea
			);
		imguiSeparatorLine();

		bool recomputeVisibleText = false;
		recomputeVisibleText |= imguiSlider("Number of lines", visibleLineCount, 1.0f, 177.0f , 1.0f);
		if (imguiSlider("Font size", textSize, 6.0f, 64.0f , 1.0f) )
		{
			fontManager->destroyFont(fontScaled);
			fontScaled = fontManager->createScaledFontToPixelSize(fontSdf, (uint32_t) textSize);
			metrics = TextLineMetrics(fontManager->getFontInfo(fontScaled) );
			recomputeVisibleText = true;
		}

		recomputeVisibleText |= imguiSlider("Scroll", textScroll, 0.0f, (lineCount-visibleLineCount) , 1.0f);
		imguiSlider("Rotate", textRotation, 0.0f, bx::pi*2.0f , 0.1f);
		recomputeVisibleText |= imguiSlider("Scale", textScale, 0.1f, 10.0f , 0.1f);

		if (recomputeVisibleText)
		{
			textBufferManager->clearTextBuffer(scrollableBuffer);
			metrics.getSubText(bigText,(uint32_t)textScroll, (uint32_t)(textScroll+visibleLineCount), textBegin, textEnd);
			textBufferManager->appendText(scrollableBuffer, fontScaled, textBegin, textEnd);
		}

		imguiEndScrollArea();

		imguiEndFrame();

		// Set view 0 default viewport.
		bgfx::setViewRect(0, 0, 0, width, height);

		// This dummy draw call is here to make sure that view 0 is cleared
		// if no other draw calls are submitted to view 0.
		bgfx::submit(0);

		int64_t now = bx::getHPCounter();
		static int64_t last = now;
		const int64_t frameTime = now - last;
		last = now;
		const double freq = double(bx::getHPFrequency() );
		const double toMs = 1000.0 / freq;

		// Use debug font to print32_t information about this example.
		bgfx::dbgTextClear();
		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontsdf");
		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of various size.");
		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime) * toMs);

		float at[3]  = { 0, 0, 0.0f };
		float eye[3] = {0, 0, -1.0f };

		float view[16];
		bx::mtxLookAt(view, eye, at);

		const float centering = 0.5f;

		// Setup a top-left ortho matrix for screen space drawing.
		const bgfx::HMD* hmd = bgfx::getHMD();
		if (NULL != hmd)
		{
			float proj[16];
			bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 100.0f);

			static float time = 0.0f;
			time += 0.05f;

			const float dist = 10.0f;
			const float offset0 = -proj[8] + (hmd->eye[0].viewOffset[0] / dist * proj[0]);
			const float offset1 = -proj[8] + (hmd->eye[1].viewOffset[0] / dist * proj[0]);

			float ortho[2][16];
			const float viewOffset = width/4.0f;
			const float viewWidth  = width/2.0f;
			bx::mtxOrtho(ortho[0], centering + viewOffset, centering + viewOffset + viewWidth, height + centering, centering, -1.0f, 1.0f, offset0);
			bx::mtxOrtho(ortho[1], centering + viewOffset, centering + viewOffset + viewWidth, height + centering, centering, -1.0f, 1.0f, offset1);
			bgfx::setViewTransform(0, view, ortho[0], BGFX_VIEW_STEREO, ortho[1]);
			bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height);
		}
		else
		{
			float ortho[16];
			bx::mtxOrtho(ortho, centering, width + centering, height + centering, centering, -1.0f, 1.0f);
			bgfx::setViewTransform(0, view, ortho);
			bgfx::setViewRect(0, 0, 0, width, height);
		}

		//very crude approximation :(
		float textAreaWidth = 0.5f * 66.0f * fontManager->getFontInfo(fontScaled).maxAdvanceWidth;

		float textRotMat[16];
		float textCenterMat[16];
		float textScaleMat[16];
		float screenCenterMat[16];

		bx::mtxRotateZ(textRotMat, textRotation);
		bx::mtxTranslate(textCenterMat, -(textAreaWidth * 0.5f), (-visibleLineCount)*metrics.getLineHeight()*0.5f, 0);
		bx::mtxScale(textScaleMat, textScale, textScale, 1.0f);
		bx::mtxTranslate(screenCenterMat, ( (width) * 0.5f), ( (height) * 0.5f), 0);

		//first translate to text center, then scale, then rotate
		float tmpMat[16];
		bx::mtxMul(tmpMat, textCenterMat, textRotMat);

		float tmpMat2[16];
		bx::mtxMul(tmpMat2, tmpMat, textScaleMat);

		float tmpMat3[16];
		bx::mtxMul(tmpMat3, tmpMat2, screenCenterMat);

		// Set model matrix for rendering.
		bgfx::setTransform(tmpMat3);

		// Draw your text.
		textBufferManager->submitTextBuffer(scrollableBuffer, 0);

		// Advance to next frame. Rendering thread will be kicked to
		// process submitted rendering primitives.
		bgfx::frame();
	}

	imguiDestroy();

	free(bigText);

	fontManager->destroyTtf(font);
	// Destroy the fonts.
	fontManager->destroyFont(fontSdf);
	fontManager->destroyFont(fontScaled);

	textBufferManager->destroyTextBuffer(scrollableBuffer);

	delete textBufferManager;
	delete fontManager;

	// Shutdown bgfx.
	bgfx::shutdown();

	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#include <cmath>
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>

#include <franka/exception.h>
#include <franka/robot.h>

/**
 * @example execute_trajectory.cpp
 * An example showing how to execute a joint trajectory loaded from a CSV file.
 */

template <class T, size_t N>
std::ostream& operator<<(std::ostream& ostream, const std::array<T, N>& array) {
  ostream << "[";
  std::copy(array.cbegin(), array.cend() - 1, std::ostream_iterator<T>(ostream, ","));
  std::copy(array.cend() - 1, array.cend(), std::ostream_iterator<T>(ostream));
  ostream << "]";
  return ostream;
}

int main(int argc, char** argv) {
  if (argc != 4) {
    std::cerr << "Usage: " << argv[0] << " <robot-hostname> <trajectory-csv> <output>" << std::endl;
    return -1;
  }

  std::cout << "Loading csv trajectory" << std::endl;
  std::fstream csv_file_stream;
  csv_file_stream.open(argv[2], std::fstream::in);

  std::vector<std::array<double, 7>> samples;
  while (csv_file_stream) {
    std::array<double, 7> q;
    char delimiter;
    for (int i = 0; i < 7; i++) {
      csv_file_stream >> q[i] >> delimiter;
    }
    samples.push_back(q);
  }
  std::cout << "Read " << samples.size() << " samples" << std::endl;

  std::vector<franka::RobotState> states;
  try {
    franka::Robot robot(argv[1]);

    // Set additional parameters always before the control loop, NEVER in the control loop!
    // Set collision behavior.
    robot.setCollisionBehavior(
        {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}}, {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}},
        {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}}, {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}},
        {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}}, {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}},
        {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}}, {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}});

    // Set the joint impedance.
    robot.setJointImpedance({{3000, 3000, 3000, 2500, 2500, 2000, 2000}});

    size_t index = 0;
    robot.control([&](const franka::RobotState& robot_state,
                      franka::Duration time_step) -> franka::JointPositions {
      states.push_back(robot_state);

      index += time_step.toMSec();

      if (index >= samples.size() - 1) {
        return franka::MotionFinished(franka::JointPositions(samples.back()));
      }
      return samples[index];
    });
  } catch (const franka::ControlException& e) {
    std::cout << e.what() << std::endl;
  } catch (const franka::Exception& e) {
    std::cout << e.what() << std::endl;
    return -1;
  }

  std::cout << "Logging results to file: " << argv[3] << std::endl;
  std::fstream output_stream;
  output_stream.open(argv[3], std::fstream::out);
  for (size_t s = 0; s < states.size(); s++) {
    output_stream << "Sample: #" << s << std::endl;
    output_stream << "q_d: \t" << samples[s] << std::endl;
    output_stream << "Robot state:" << std::endl;
    output_stream << "q: \t" << states[s].q << std::endl;
    output_stream << "q_d: \t" << states[s].q_d << std::endl;
    output_stream << "dq: \t" << states[s].dq << std::endl;
    output_stream << "______" << std::endl;
  }

  return 0;
}
<commit_msg>adds velocity saturation to joint position interface<commit_after>// Copyright (c) 2017 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE
#include <cmath>
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>

#include <franka/exception.h>
#include <franka/robot.h>

/**
 * @example execute_trajectory.cpp
 * An example showing how to execute a joint trajectory loaded from a CSV file.
 */

std::array<double, 7> saturateDesiredJointVelocity(const std::array<double, 7>& max_joint_vel,
                                                   const std::array<double, 7>& q_d,
                                                   const std::array<double, 7>& last_q_d);

template <class T, size_t N>
std::ostream& operator<<(std::ostream& ostream, const std::array<T, N>& array) {
  ostream << "[";
  std::copy(array.cbegin(), array.cend() - 1, std::ostream_iterator<T>(ostream, ","));
  std::copy(array.cend() - 1, array.cend(), std::ostream_iterator<T>(ostream));
  ostream << "]";
  return ostream;
}

int main(int argc, char** argv) {
  if (argc != 4) {
    std::cerr << "Usage: " << argv[0] << " <robot-hostname> <trajectory-csv> <output>" << std::endl;
    return -1;
  }

  std::cout << "Loading csv trajectory" << std::endl;
  std::fstream csv_file_stream;
  csv_file_stream.open(argv[2], std::fstream::in);

  std::vector<std::array<double, 7>> samples;
  while (csv_file_stream) {
    std::array<double, 7> q;
    char delimiter;
    for (int i = 0; i < 7; i++) {
      csv_file_stream >> q[i] >> delimiter;
    }
    samples.push_back(q);
  }
  std::cout << "Read " << samples.size() << " samples" << std::endl;

  std::vector<franka::RobotState> states;
  try {
    franka::Robot robot(argv[1]);

    // Set additional parameters always before the control loop, NEVER in the control loop!
    // Set collision behavior.
    robot.setCollisionBehavior(
        {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}}, {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}},
        {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}}, {{20.0, 20.0, 18.0, 18.0, 16.0, 14.0, 12.0}},
        {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}}, {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}},
        {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}}, {{20.0, 20.0, 20.0, 25.0, 25.0, 25.0}});

    const std::array<double, 7>  max_joint_vel{{2.375, 2.375, 2.375, 2.375, 2.375, 2.375, 2.375}};
    // Set the joint impedance.
    robot.setJointImpedance({{3000, 3000, 3000, 2500, 2500, 2000, 2000}});

    size_t index = 0;
    robot.control([&](const franka::RobotState& robot_state,
                      franka::Duration time_step) -> franka::JointPositions {
      states.push_back(robot_state);

      index += time_step.toMSec();

      if (index >= samples.size() - 1) {
        return franka::MotionFinished(franka::JointPositions(samples.back()));
      }
      // state.q_d contains the last joint position command received by the robot.
      // In case of packet loss due to bad connection, even if your desired trajectory
      // is smooth discontinuities might occur.
      // Saturating the velocity computed with respect to the last command received
      // by the robot will prevent from getting discontinuity errors.
      return saturateDesiredJointVelocity(max_joint_vel,samples[index], robot_state.q_d);
    });
  } catch (const franka::ControlException& e) {
    std::cout << e.what() << std::endl;
  } catch (const franka::Exception& e) {
    std::cout << e.what() << std::endl;
    return -1;
  }

  std::cout << "Logging results to file: " << argv[3] << std::endl;
  std::fstream output_stream;
  output_stream.open(argv[3], std::fstream::out);
  for (size_t s = 0; s < states.size(); s++) {
    output_stream << "Sample: #" << s << std::endl;
    output_stream << "q_d: \t" << samples[s] << std::endl;
    output_stream << "Robot state:" << std::endl;
    output_stream << "q: \t" << states[s].q << std::endl;
    output_stream << "q_d: \t" << states[s].q_d << std::endl;
    output_stream << "dq: \t" << states[s].dq << std::endl;
    output_stream << "______" << std::endl;
  }

  return 0;
}

std::array<double, 7> saturateDesiredJointVelocity(const std::array<double, 7>& max_joint_vel,
                                                   const std::array<double, 7>& q_d,
                                                   const std::array<double, 7>& last_q_d) {
  std::array<double, 7> q_d_saturated{};
  for (size_t i = 1 ; i < 7 ; i ++) {
    double vel = (q_d[i] - last_q_d[i])/1e-3;
    q_d_saturated[i] = last_q_d[i] + std::max(std::min(vel, max_joint_vel[i]), -max_joint_vel[i])*1e-3;
  }
  return q_d_saturated;
};

<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "gfx/codec/png_codec.h"
#include "net/test/test_server.h"
#include "ui/base/clipboard/clipboard.h"

extern base::hash_map<std::string, int> g_test_timeout_overrides;

namespace {

// Include things like browser frame and scrollbar and make sure we're bigger
// than the test pdf document.
static const int kBrowserWidth = 1000;
static const int kBrowserHeight = 600;
static const int kLoadingTestTimeoutMs = 60000;

// The loading test is really a collection of tests, each one being a different
// PDF file.  But it would be busy work to add a different test for each file.
// Since we run them all in one test, we want a bigger timeout.
class IncreaseLoadingTimeout {
 public:
  IncreaseLoadingTimeout() {
    g_test_timeout_overrides["PDFBrowserTest.Loading"] = kLoadingTestTimeoutMs;
  }
};

IncreaseLoadingTimeout g_increase_loading_timeout;

class PDFBrowserTest : public InProcessBrowserTest,
                       public NotificationObserver {
 public:
  PDFBrowserTest()
      : snapshot_different_(true),
        next_dummy_search_value_(0),
        load_stop_notification_count_(0) {
    EnableDOMAutomation();

    pdf_test_server_.reset(new net::TestServer(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("pdf/test"))));
  }

 protected:
  // Use our own TestServer so that we can serve files from the pdf directory.
  net::TestServer* pdf_test_server() { return pdf_test_server_.get(); }

  int load_stop_notification_count() const {
    return load_stop_notification_count_;
  }

  FilePath GetPDFTestDir() {
    return FilePath(FilePath::kCurrentDirectory).AppendASCII("..").
        AppendASCII("..").AppendASCII("..").AppendASCII("pdf").
        AppendASCII("test");
  }

  void Load() {
    GURL url(ui_test_utils::GetTestUrl(
        GetPDFTestDir(),
        FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
    ui_test_utils::NavigateToURL(browser(), url);
    gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));

    scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info(
        WindowSizer::CreateDefaultMonitorInfoProvider());
    gfx::Rect screen_bounds = monitor_info->GetPrimaryMonitorBounds();
    ASSERT_GT(screen_bounds.width(), kBrowserWidth);
    ASSERT_GT(screen_bounds.height(), kBrowserHeight);

    browser()->window()->SetBounds(bounds);
  }

  void VerifySnapshot(const std::string& expected_filename) {
    snapshot_different_ = true;
    expected_filename_ = expected_filename;
    RenderViewHost* host =
        browser()->GetSelectedTabContents()->render_view_host();

    host->CaptureSnapshot();
    ui_test_utils::RegisterAndWait(this,
                                   NotificationType::TAB_SNAPSHOT_TAKEN,
                                   Source<RenderViewHost>(host));
    ASSERT_FALSE(snapshot_different_) << "Rendering didn't match, see result "
        "at " << snapshot_filename_.value().c_str();
  }

  void WaitForResponse() {
    // Even if the plugin has loaded the data or scrolled, because of how
    // pepper painting works, we might not have the data.  One way to force this
    // to be flushed is to do a find operation, since on this two-page test
    // document, it'll wait for us to flush the renderer message loop twice and
    // also the browser's once, at which point we're guaranteed to have updated
    // the backingstore.  Hacky, but it works.
    // Note that we need to change the text each time, because if we don't the
    // renderer code will think the second message is to go to next result, but
    // there are none so the plugin will assert.

    string16 query = UTF8ToUTF16(
        std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
    ASSERT_EQ(0, ui_test_utils::FindInPage(
        browser()->GetSelectedTabContents(), query, true, false, NULL));
  }

 private:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kForceInternalPDFPlugin);
  }

  // NotificationObserver
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::TAB_SNAPSHOT_TAKEN) {
      MessageLoopForUI::current()->Quit();
      FilePath reference = ui_test_utils::GetTestFilePath(
          GetPDFTestDir(),
          FilePath().AppendASCII(expected_filename_));
      base::PlatformFileInfo info;
      ASSERT_TRUE(file_util::GetFileInfo(reference, &info));
      int size = static_cast<size_t>(info.size);
      scoped_array<char> data(new char[size]);
      ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size));

      int w, h;
      std::vector<unsigned char> decoded;
      ASSERT_TRUE(gfx::PNGCodec::Decode(
          reinterpret_cast<unsigned char*>(data.get()), size,
          gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
      int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);

      const SkBitmap* bitmap = Details<const SkBitmap>(details).ptr();
      int32* pixels = static_cast<int32*>(bitmap->getPixels());

      // Get the background color, and use it to figure out the x-offsets in
      // each image.  The reason is that depending on the theme in the OS, the
      // same browser width can lead to slightly different plugin sizes, so the
      // pdf content will start at different x offsets.
      // Also note that the images we saved are cut off before the scrollbar, as
      // that'll change depending on the theme, and also cut off vertically so
      // that the ui controls don't show up, as those fade-in and so the timing
      // will affect their transparency.
      int32 bg_color = ref_pixels[0];
      int ref_x_offset, snapshot_x_offset;
      for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
        if (ref_pixels[ref_x_offset] != bg_color)
          break;
      }

      for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width();
           ++snapshot_x_offset) {
        if (pixels[snapshot_x_offset] != bg_color)
          break;
      }

      int x_max = std::min(
          w - ref_x_offset, bitmap->width() - snapshot_x_offset);
      int y_max = std::min(h, bitmap->height());
      int stride = bitmap->rowBytes();
      snapshot_different_ = false;
      for (int y = 0; y < y_max && !snapshot_different_; ++y) {
        for (int x = 0; x < x_max && !snapshot_different_; ++x) {
          if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
              ref_pixels[y * w + x + ref_x_offset])
            snapshot_different_ = true;
        }
      }

      if (snapshot_different_) {
        std::vector<unsigned char> png_data;
        gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data);
        if (file_util::CreateTemporaryFile(&snapshot_filename_)) {
          file_util::WriteFile(snapshot_filename_,
              reinterpret_cast<char*>(&png_data[0]), png_data.size());
        }
      }
    } else if (type == NotificationType::LOAD_STOP) {
      load_stop_notification_count_++;
    }
  }

  // True if the snapshot differed from the expected value.
  bool snapshot_different_;
  // Internal variable used to synchronize to the renderer.
  int next_dummy_search_value_;
  // The filename of the bitmap to compare the snapshot to.
  std::string expected_filename_;
  // If the snapshot is different, holds the location where it's saved.
  FilePath snapshot_filename_;
  // How many times we've seen NotificationType::LOAD_STOP.
  int load_stop_notification_count_;

  scoped_ptr<net::TestServer> pdf_test_server_;
};

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_Basic FLAKY_Basic
#else
#define MAYBE_Basic Basic
#endif

// Tests basic PDF rendering.  This can be broken depending on bad merges with
// the vendor, so it's important that we have basic sanity checking.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Basic) {

  ASSERT_NO_FATAL_FAILURE(Load());
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest.png"));
}

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_Scroll FLAKY_Scroll
#else
#define MAYBE_Scroll Scroll
#endif

// Tests that scrolling works.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Scroll) {
  ASSERT_NO_FATAL_FAILURE(Load());

  // We use wheel mouse event since that's the only one we can easily push to
  // the renderer.  There's no way to push a cross-platform keyboard event at
  // the moment.
  WebKit::WebMouseWheelEvent wheel_event;
  wheel_event.type = WebKit::WebInputEvent::MouseWheel;
  wheel_event.deltaY = -200;
  wheel_event.wheelTicksY = -2;
  TabContents* tab_contents = browser()->GetSelectedTabContents();
  tab_contents->render_view_host()->ForwardWheelEvent(wheel_event);
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest_scroll.png"));
}

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_FindAndCopy FLAKY_FindAndCopy
#else
#define MAYBE_FindAndCopy FindAndCopy
#endif

IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_FindAndCopy) {
  ASSERT_NO_FATAL_FAILURE(Load());
  // Verifies that find in page works.
  ASSERT_EQ(3, ui_test_utils::FindInPage(
      browser()->GetSelectedTabContents(), UTF8ToUTF16("adipiscing"), true,
      false, NULL));

  // Verify that copying selected text works.
  ui::Clipboard clipboard;
  // Reset the clipboard first.
  ui::Clipboard::ObjectMap objects;
  ui::Clipboard::ObjectMapParams params;
  params.push_back(std::vector<char>());
  objects[Clipboard::CBF_TEXT] = params;
  clipboard.WriteObjects(objects);

  browser()->GetSelectedTabContents()->render_view_host()->Copy();
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  std::string text;
  clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text);
  ASSERT_EQ("adipiscing", text);
}

// Tests that loading async pdfs works correctly (i.e. document fully loads).
// This also loads all documents that used to crash, to ensure we don't have
// regressions.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, Loading) {
  ASSERT_TRUE(pdf_test_server()->Start());

  NavigationController* controller =
      &(browser()->GetSelectedTabContents()->controller());
  NotificationRegistrar registrar;
  registrar.Add(this,
                NotificationType::LOAD_STOP,
                Source<NavigationController>(controller));
  std::string base_url = std::string("files/");

  file_util::FileEnumerator file_enumerator(
      ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()),
      false,
      file_util::FileEnumerator::FILES,
      FILE_PATH_LITERAL("*.pdf"));
  for (FilePath file_path = file_enumerator.Next();
       !file_path.empty();
       file_path = file_enumerator.Next()) {
    std::string filename = WideToASCII(file_path.BaseName().ToWStringHack());

#if defined(OS_MACOSX) || defined(OS_LINUX)
    if (filename == "sample.pdf")
      continue;  // Crashes on Mac and Linux.  http://crbug.com/63549
#endif

    LOG(WARNING) << "PDFBrowserTest.Loading: " << filename;

    GURL url = pdf_test_server()->GetURL(base_url + filename);
    ui_test_utils::NavigateToURL(browser(), url);

    while (true) {
      int last_count = load_stop_notification_count();
      // We might get extraneous NotificationType::LOAD_STOP notifications when
      // doing async loading.  This happens when the first loader is cancelled
      // and before creating a byte-range request loader.
      bool complete = false;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
          browser()->GetSelectedTabContents()->render_view_host(),
          std::wstring(),
          L"window.domAutomationController.send(plugin.documentLoadComplete())",
          &complete));
      if (complete)
        break;

      // Check if the LOAD_STOP notification could have come while we run a
      // nested message loop for the JS call.
      if (last_count != load_stop_notification_count())
        continue;
      ui_test_utils::WaitForLoadStop(controller);
    }
  }
}

}  // namespace
<commit_msg>Fix build break.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "gfx/codec/png_codec.h"
#include "net/test/test_server.h"
#include "ui/base/clipboard/clipboard.h"

extern base::hash_map<std::string, int> g_test_timeout_overrides;

namespace {

// Include things like browser frame and scrollbar and make sure we're bigger
// than the test pdf document.
static const int kBrowserWidth = 1000;
static const int kBrowserHeight = 600;
static const int kLoadingTestTimeoutMs = 60000;

// The loading test is really a collection of tests, each one being a different
// PDF file.  But it would be busy work to add a different test for each file.
// Since we run them all in one test, we want a bigger timeout.
class IncreaseLoadingTimeout {
 public:
  IncreaseLoadingTimeout() {
    g_test_timeout_overrides["PDFBrowserTest.Loading"] = kLoadingTestTimeoutMs;
  }
};

IncreaseLoadingTimeout g_increase_loading_timeout;

class PDFBrowserTest : public InProcessBrowserTest,
                       public NotificationObserver {
 public:
  PDFBrowserTest()
      : snapshot_different_(true),
        next_dummy_search_value_(0),
        load_stop_notification_count_(0) {
    EnableDOMAutomation();

    pdf_test_server_.reset(new net::TestServer(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("pdf/test"))));
  }

 protected:
  // Use our own TestServer so that we can serve files from the pdf directory.
  net::TestServer* pdf_test_server() { return pdf_test_server_.get(); }

  int load_stop_notification_count() const {
    return load_stop_notification_count_;
  }

  FilePath GetPDFTestDir() {
    return FilePath(FilePath::kCurrentDirectory).AppendASCII("..").
        AppendASCII("..").AppendASCII("..").AppendASCII("pdf").
        AppendASCII("test");
  }

  void Load() {
    GURL url(ui_test_utils::GetTestUrl(
        GetPDFTestDir(),
        FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
    ui_test_utils::NavigateToURL(browser(), url);
    gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));

    scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info(
        WindowSizer::CreateDefaultMonitorInfoProvider());
    gfx::Rect screen_bounds = monitor_info->GetPrimaryMonitorBounds();
    ASSERT_GT(screen_bounds.width(), kBrowserWidth);
    ASSERT_GT(screen_bounds.height(), kBrowserHeight);

    browser()->window()->SetBounds(bounds);
  }

  void VerifySnapshot(const std::string& expected_filename) {
    snapshot_different_ = true;
    expected_filename_ = expected_filename;
    RenderViewHost* host =
        browser()->GetSelectedTabContents()->render_view_host();

    host->CaptureSnapshot();
    ui_test_utils::RegisterAndWait(this,
                                   NotificationType::TAB_SNAPSHOT_TAKEN,
                                   Source<RenderViewHost>(host));
    ASSERT_FALSE(snapshot_different_) << "Rendering didn't match, see result "
        "at " << snapshot_filename_.value().c_str();
  }

  void WaitForResponse() {
    // Even if the plugin has loaded the data or scrolled, because of how
    // pepper painting works, we might not have the data.  One way to force this
    // to be flushed is to do a find operation, since on this two-page test
    // document, it'll wait for us to flush the renderer message loop twice and
    // also the browser's once, at which point we're guaranteed to have updated
    // the backingstore.  Hacky, but it works.
    // Note that we need to change the text each time, because if we don't the
    // renderer code will think the second message is to go to next result, but
    // there are none so the plugin will assert.

    string16 query = UTF8ToUTF16(
        std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
    ASSERT_EQ(0, ui_test_utils::FindInPage(
        browser()->GetSelectedTabContents(), query, true, false, NULL));
  }

 private:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kForceInternalPDFPlugin);
  }

  // NotificationObserver
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::TAB_SNAPSHOT_TAKEN) {
      MessageLoopForUI::current()->Quit();
      FilePath reference = ui_test_utils::GetTestFilePath(
          GetPDFTestDir(),
          FilePath().AppendASCII(expected_filename_));
      base::PlatformFileInfo info;
      ASSERT_TRUE(file_util::GetFileInfo(reference, &info));
      int size = static_cast<size_t>(info.size);
      scoped_array<char> data(new char[size]);
      ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size));

      int w, h;
      std::vector<unsigned char> decoded;
      ASSERT_TRUE(gfx::PNGCodec::Decode(
          reinterpret_cast<unsigned char*>(data.get()), size,
          gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
      int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);

      const SkBitmap* bitmap = Details<const SkBitmap>(details).ptr();
      int32* pixels = static_cast<int32*>(bitmap->getPixels());

      // Get the background color, and use it to figure out the x-offsets in
      // each image.  The reason is that depending on the theme in the OS, the
      // same browser width can lead to slightly different plugin sizes, so the
      // pdf content will start at different x offsets.
      // Also note that the images we saved are cut off before the scrollbar, as
      // that'll change depending on the theme, and also cut off vertically so
      // that the ui controls don't show up, as those fade-in and so the timing
      // will affect their transparency.
      int32 bg_color = ref_pixels[0];
      int ref_x_offset, snapshot_x_offset;
      for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
        if (ref_pixels[ref_x_offset] != bg_color)
          break;
      }

      for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width();
           ++snapshot_x_offset) {
        if (pixels[snapshot_x_offset] != bg_color)
          break;
      }

      int x_max = std::min(
          w - ref_x_offset, bitmap->width() - snapshot_x_offset);
      int y_max = std::min(h, bitmap->height());
      int stride = bitmap->rowBytes();
      snapshot_different_ = false;
      for (int y = 0; y < y_max && !snapshot_different_; ++y) {
        for (int x = 0; x < x_max && !snapshot_different_; ++x) {
          if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
              ref_pixels[y * w + x + ref_x_offset])
            snapshot_different_ = true;
        }
      }

      if (snapshot_different_) {
        std::vector<unsigned char> png_data;
        gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data);
        if (file_util::CreateTemporaryFile(&snapshot_filename_)) {
          file_util::WriteFile(snapshot_filename_,
              reinterpret_cast<char*>(&png_data[0]), png_data.size());
        }
      }
    } else if (type == NotificationType::LOAD_STOP) {
      load_stop_notification_count_++;
    }
  }

  // True if the snapshot differed from the expected value.
  bool snapshot_different_;
  // Internal variable used to synchronize to the renderer.
  int next_dummy_search_value_;
  // The filename of the bitmap to compare the snapshot to.
  std::string expected_filename_;
  // If the snapshot is different, holds the location where it's saved.
  FilePath snapshot_filename_;
  // How many times we've seen NotificationType::LOAD_STOP.
  int load_stop_notification_count_;

  scoped_ptr<net::TestServer> pdf_test_server_;
};

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_Basic FLAKY_Basic
#else
#define MAYBE_Basic Basic
#endif

// Tests basic PDF rendering.  This can be broken depending on bad merges with
// the vendor, so it's important that we have basic sanity checking.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Basic) {

  ASSERT_NO_FATAL_FAILURE(Load());
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest.png"));
}

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_Scroll FLAKY_Scroll
#else
#define MAYBE_Scroll Scroll
#endif

// Tests that scrolling works.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Scroll) {
  ASSERT_NO_FATAL_FAILURE(Load());

  // We use wheel mouse event since that's the only one we can easily push to
  // the renderer.  There's no way to push a cross-platform keyboard event at
  // the moment.
  WebKit::WebMouseWheelEvent wheel_event;
  wheel_event.type = WebKit::WebInputEvent::MouseWheel;
  wheel_event.deltaY = -200;
  wheel_event.wheelTicksY = -2;
  TabContents* tab_contents = browser()->GetSelectedTabContents();
  tab_contents->render_view_host()->ForwardWheelEvent(wheel_event);
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest_scroll.png"));
}

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_FindAndCopy FLAKY_FindAndCopy
#else
#define MAYBE_FindAndCopy FindAndCopy
#endif

IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_FindAndCopy) {
  ASSERT_NO_FATAL_FAILURE(Load());
  // Verifies that find in page works.
  ASSERT_EQ(3, ui_test_utils::FindInPage(
      browser()->GetSelectedTabContents(), UTF8ToUTF16("adipiscing"), true,
      false, NULL));

  // Verify that copying selected text works.
  ui::Clipboard clipboard;
  // Reset the clipboard first.
  ui::Clipboard::ObjectMap objects;
  ui::Clipboard::ObjectMapParams params;
  params.push_back(std::vector<char>());
  objects[ui::Clipboard::CBF_TEXT] = params;
  clipboard.WriteObjects(objects);

  browser()->GetSelectedTabContents()->render_view_host()->Copy();
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  std::string text;
  clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text);
  ASSERT_EQ("adipiscing", text);
}

// Tests that loading async pdfs works correctly (i.e. document fully loads).
// This also loads all documents that used to crash, to ensure we don't have
// regressions.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, Loading) {
  ASSERT_TRUE(pdf_test_server()->Start());

  NavigationController* controller =
      &(browser()->GetSelectedTabContents()->controller());
  NotificationRegistrar registrar;
  registrar.Add(this,
                NotificationType::LOAD_STOP,
                Source<NavigationController>(controller));
  std::string base_url = std::string("files/");

  file_util::FileEnumerator file_enumerator(
      ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()),
      false,
      file_util::FileEnumerator::FILES,
      FILE_PATH_LITERAL("*.pdf"));
  for (FilePath file_path = file_enumerator.Next();
       !file_path.empty();
       file_path = file_enumerator.Next()) {
    std::string filename = WideToASCII(file_path.BaseName().ToWStringHack());

#if defined(OS_MACOSX) || defined(OS_LINUX)
    if (filename == "sample.pdf")
      continue;  // Crashes on Mac and Linux.  http://crbug.com/63549
#endif

    LOG(WARNING) << "PDFBrowserTest.Loading: " << filename;

    GURL url = pdf_test_server()->GetURL(base_url + filename);
    ui_test_utils::NavigateToURL(browser(), url);

    while (true) {
      int last_count = load_stop_notification_count();
      // We might get extraneous NotificationType::LOAD_STOP notifications when
      // doing async loading.  This happens when the first loader is cancelled
      // and before creating a byte-range request loader.
      bool complete = false;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
          browser()->GetSelectedTabContents()->render_view_host(),
          std::wstring(),
          L"window.domAutomationController.send(plugin.documentLoadComplete())",
          &complete));
      if (complete)
        break;

      // Check if the LOAD_STOP notification could have come while we run a
      // nested message loop for the JS call.
      if (last_count != load_stop_notification_count())
        continue;
      ui_test_utils::WaitForLoadStop(controller);
    }
  }
}

}  // namespace
<|endoftext|>


<commit_before>// RUN: cat %s | %cling | FileCheck %s

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

cling::Value V;
V // CHECK: (cling::Value) <<<invalid>>> @0x{{.*}}

gCling->evaluate("1;", &V);
V // CHECK: (cling::Value) boxes [(int) 1]

long LongV = 17;
gCling->evaluate("LongV;", &V);
V // CHECK: (cling::Value) boxes [(long) 17]

int* IntP = (int*)0x12;
gCling->evaluate("IntP;", &V);
V // CHECK: (cling::Value) boxes [(int *) 0x12]

cling::Value Result;
Result.value = llvm::PTOGV(&V); // SRet
gCling->evaluate("V", &Result);
Result // CHECK: (cling::Value) boxes [(cling::Value) ]
V // CHECK: (cling::Value) boxes [(int *) 0x12]

// Savannah #96277
gCling->evaluate("double sin(double); double one = sin(3.141/2);", &V);
one // CHECK: (double) 1.000000e+00
<commit_msg>When a C/C++ function returns result LLVM represents it as call to function, which first argument is the actual storage, where LLVM will put the return result. Our intent is to be able to call that low-level LLVM function and pass in an object where it can store the return result of the function (Axel did the work).<commit_after>// RUN: cat %s | %cling | FileCheck %s
// XFAIL: i686-pc-linux-gnu
// Expected to fail on 32 bit machine because we need to pass the storage object
// in a proper way for 32 bit machines.

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

cling::Value V;
V // CHECK: (cling::Value) <<<invalid>>> @0x{{.*}}

gCling->evaluate("1;", &V);
V // CHECK: (cling::Value) boxes [(int) 1]

long LongV = 17;
gCling->evaluate("LongV;", &V);
V // CHECK: (cling::Value) boxes [(long) 17]

int* IntP = (int*)0x12;
gCling->evaluate("IntP;", &V);
V // CHECK: (cling::Value) boxes [(int *) 0x12]

cling::Value Result;
Result.value = llvm::PTOGV(&V); // SRet
gCling->evaluate("V", &Result);
Result // CHECK: (cling::Value) boxes [(cling::Value) ]
V // CHECK: (cling::Value) boxes [(int *) 0x12]

// Savannah #96277
gCling->evaluate("double sin(double); double one = sin(3.141/2);", &V);
one // CHECK: (double) 1.000000e+00
<|endoftext|>