<commit_before>#ifndef _SERVER_HPP_
#define _SERVER_HPP_

#include <string>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>

#include "./connection.hpp"
#include "./connection_manager.hpp"
#include "./iserver.hpp"

namespace asio = boost::asio;
namespace ip = asio::ip;
namespace placeholders = asio::placeholders;
namespace sys = boost::system;

class Server
    : public IServer
{
public:

    Server(
        std::string const & port
    );

    void run() override;

    void disconnect(
        IConnectionPtr const & sender
    ) override;

    #ifdef SERVER_SSL
        ssl::context & getSSLContext() override;
    #endif

protected:

    virtual void setupSignals();

    virtual std::string getLocalHostIp();

    virtual std::string getPort();

    virtual ip::tcp::endpoint resolve();

    virtual bool reuseAddress();

    virtual void runThreadPool();

    virtual unsigned getThreadNumber();

    virtual void startAccept();

    virtual void onAccepted(
        sys::error_code const & errorCode
    );

    IConnectionPtr createConnection() override;

    virtual ITaskPtr createTask() = 0;

    virtual void stop();

    #ifdef SERVER_SSL

        virtual void sslInit();
        virtual int getSslOptions();
        virtual std::string passwordCallback(
            std::size_t size,
            std::size_t purppose
        );
        virtual std::string getCertificateChainFileName();
        virtual std::string getPrivateKeyFileName();

    #endif

protected:

    std::string m_port;
    asio::io_service m_ioService;
    asio::io_service::strand m_strand;
    asio::ip::tcp::acceptor m_acceptor;
    asio::signal_set m_signals;
    IConnectionPtr m_newConnection;
    ConnectionManager m_connectionManager;

#ifdef SERVER_SSL
    ssl::context m_sslContext;
#endif
};

Server::Server(
    std::string const & port
)
    : m_port( port )
    , m_strand( m_ioService )
    , m_acceptor( m_ioService )
    , m_signals( m_ioService )

    #ifdef SERVER_SSL
        , m_sslContext( ssl::context::sslv23 )
    #endif
{
}

void Server::setupSignals()
{
    m_signals.add( SIGINT );
    m_signals.add( SIGTERM );
    m_signals.add( SIGQUIT );

    m_signals.async_wait(
        boost::bind( & Server::stop, this )
    );
}

std::string Server::getLocalHostIp()
{
    return "127.0.0.1";
}

std::string Server::getPort()
{
    return m_port;
}

bool Server::reuseAddress()
{
    return true;
}

IConnectionPtr Server::createConnection()
{
    return IConnectionPtr( new Connection( m_ioService, this, createTask() ) );
}

ip::tcp::endpoint Server::resolve()
{
    ip::tcp::resolver resolver( m_ioService );
    ip::tcp::resolver::query query( getLocalHostIp(), getPort() );
    return * resolver.resolve( query );
}

unsigned Server::getThreadNumber()
{
    return 4;
}

void Server::runThreadPool()
{
    boost::thread_group threadGroup;

    auto const threadBody = boost::bind(
        & asio::io_service::run,
        & m_ioService
    );

    for(
        unsigned i = 0, threadNumber = getThreadNumber();
        i < threadNumber;
        ++ i
    )
    {
        threadGroup.create_thread( threadBody );
    }

    threadGroup.join_all();
}

void Server::run()
{
    setupSignals();

    auto const endpoint = resolve();

    m_acceptor.open( endpoint.protocol() );
    m_acceptor.set_option( ip::tcp::acceptor::reuse_address( reuseAddress() ) );
    m_acceptor.bind( endpoint );
    m_acceptor.listen();

#ifdef SERVER_SSL
    sslInit();
#endif

    startAccept();

    runThreadPool();
}

void Server::disconnect(
    IConnectionPtr const & sender
)
{
    m_connectionManager.remove( sender );
}

void Server::startAccept()
{
    m_newConnection = createConnection();

    auto const onAccepted = boost::bind(
        & Server::onAccepted,
        this,
        placeholders::error
    );

    m_acceptor.async_accept(

        #ifdef SERVER_SSL
            m_newConnection->socket().lowest_layer(),
        #else
            m_newConnection->socket(),
        #endif

        onAccepted
    );
}

void Server::onAccepted(
    sys::error_code const & errorCode
)
{
    if( ! errorCode )
    {
        m_connectionManager.add( m_newConnection );

        m_newConnection->start( m_newConnection->getStartAction() );
    }

    startAccept();
}

void Server::stop()
{
    m_ioService.stop();
}

#ifdef SERVER_SSL
    ssl::context & Server::getSSLContext()
    {
        return m_sslContext;
    }

    int Server::getSslOptions()
    {
        return ssl::context::default_workarounds
            | ssl::context::no_sslv2
            | ssl::context::single_dh_use;
    }

    std::string Server::passwordCallback(
        std::size_t size,
        std::size_t purppose
    )
    {
        return "test";
    }

    std::string Server::getCertificateChainFileName()
    {
        return "../pem/server.pem";
    }

    std::string Server::getPrivateKeyFileName()
    {
        return "../pem/server-key.pem";
    }

    void Server::sslInit()
    {
        m_sslContext.set_options( getSslOptions() );

        m_sslContext.set_password_callback(
            [ & ]( std::size_t size, std::size_t purpose )
            {
                return this->passwordCallback( size, purpose );
            }
        );

        m_sslContext.use_certificate_chain_file( getCertificateChainFileName() );
        m_sslContext.use_private_key_file( getPrivateKeyFileName(), ssl::context::pem );
    }
#endif // SERVER_SSL

#endif // _SERVER_HPP_

<commit_msg>default number of threads is the same as number of cores<commit_after>#ifndef _SERVER_HPP_
#define _SERVER_HPP_

#include <string>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>

#include "./connection.hpp"
#include "./connection_manager.hpp"
#include "./iserver.hpp"

namespace asio = boost::asio;
namespace ip = asio::ip;
namespace placeholders = asio::placeholders;
namespace sys = boost::system;

class Server
    : public IServer
{
public:

    Server(
        std::string const & port
    );

    void run() override;

    void disconnect(
        IConnectionPtr const & sender
    ) override;

    #ifdef SERVER_SSL
        ssl::context & getSSLContext() override;
    #endif

protected:

    virtual void setupSignals();

    virtual std::string getLocalHostIp();

    virtual std::string getPort();

    virtual ip::tcp::endpoint resolve();

    virtual bool reuseAddress();

    virtual void runThreadPool();

    virtual unsigned getThreadNumber();

    virtual void startAccept();

    virtual void onAccepted(
        sys::error_code const & errorCode
    );

    IConnectionPtr createConnection() override;

    virtual ITaskPtr createTask() = 0;

    virtual void stop();

    #ifdef SERVER_SSL

        virtual void sslInit();
        virtual int getSslOptions();
        virtual std::string passwordCallback(
            std::size_t size,
            std::size_t purppose
        );
        virtual std::string getCertificateChainFileName();
        virtual std::string getPrivateKeyFileName();

    #endif

protected:

    std::string m_port;
    asio::io_service m_ioService;
    asio::io_service::strand m_strand;
    asio::ip::tcp::acceptor m_acceptor;
    asio::signal_set m_signals;
    IConnectionPtr m_newConnection;
    ConnectionManager m_connectionManager;

#ifdef SERVER_SSL
    ssl::context m_sslContext;
#endif
};

Server::Server(
    std::string const & port
)
    : m_port( port )
    , m_strand( m_ioService )
    , m_acceptor( m_ioService )
    , m_signals( m_ioService )

    #ifdef SERVER_SSL
        , m_sslContext( ssl::context::sslv23 )
    #endif
{
}

void Server::setupSignals()
{
    m_signals.add( SIGINT );
    m_signals.add( SIGTERM );
    m_signals.add( SIGQUIT );

    m_signals.async_wait(
        boost::bind( & Server::stop, this )
    );
}

std::string Server::getLocalHostIp()
{
    return "127.0.0.1";
}

std::string Server::getPort()
{
    return m_port;
}

bool Server::reuseAddress()
{
    return true;
}

IConnectionPtr Server::createConnection()
{
    return IConnectionPtr( new Connection( m_ioService, this, createTask() ) );
}

ip::tcp::endpoint Server::resolve()
{
    ip::tcp::resolver resolver( m_ioService );
    ip::tcp::resolver::query query( getLocalHostIp(), getPort() );
    return * resolver.resolve( query );
}

unsigned Server::getThreadNumber()
{
    return boost::thread::hardware_concurrency();
}

void Server::runThreadPool()
{
    boost::thread_group threadGroup;

    auto const threadBody = boost::bind(
        & asio::io_service::run,
        & m_ioService
    );

    for(
        unsigned i = 0, threadNumber = getThreadNumber();
        i < threadNumber;
        ++ i
    )
    {
        threadGroup.create_thread( threadBody );
    }

    threadGroup.join_all();
}

void Server::run()
{
    setupSignals();

    auto const endpoint = resolve();

    m_acceptor.open( endpoint.protocol() );
    m_acceptor.set_option( ip::tcp::acceptor::reuse_address( reuseAddress() ) );
    m_acceptor.bind( endpoint );
    m_acceptor.listen();

#ifdef SERVER_SSL
    sslInit();
#endif

    startAccept();

    runThreadPool();
}

void Server::disconnect(
    IConnectionPtr const & sender
)
{
    m_connectionManager.remove( sender );
}

void Server::startAccept()
{
    m_newConnection = createConnection();

    auto const onAccepted = boost::bind(
        & Server::onAccepted,
        this,
        placeholders::error
    );

    m_acceptor.async_accept(

        #ifdef SERVER_SSL
            m_newConnection->socket().lowest_layer(),
        #else
            m_newConnection->socket(),
        #endif

        onAccepted
    );
}

void Server::onAccepted(
    sys::error_code const & errorCode
)
{
    if( ! errorCode )
    {
        m_connectionManager.add( m_newConnection );

        m_newConnection->start( m_newConnection->getStartAction() );
    }

    startAccept();
}

void Server::stop()
{
    m_ioService.stop();
}

#ifdef SERVER_SSL
    ssl::context & Server::getSSLContext()
    {
        return m_sslContext;
    }

    int Server::getSslOptions()
    {
        return ssl::context::default_workarounds
            | ssl::context::no_sslv2
            | ssl::context::single_dh_use;
    }

    std::string Server::passwordCallback(
        std::size_t size,
        std::size_t purppose
    )
    {
        return "test";
    }

    std::string Server::getCertificateChainFileName()
    {
        return "../pem/server.pem";
    }

    std::string Server::getPrivateKeyFileName()
    {
        return "../pem/server-key.pem";
    }

    void Server::sslInit()
    {
        m_sslContext.set_options( getSslOptions() );

        m_sslContext.set_password_callback(
            [ & ]( std::size_t size, std::size_t purpose )
            {
                return this->passwordCallback( size, purpose );
            }
        );

        m_sslContext.use_certificate_chain_file( getCertificateChainFileName() );
        m_sslContext.use_private_key_file( getPrivateKeyFileName(), ssl::context::pem );
    }
#endif // SERVER_SSL

#endif // _SERVER_HPP_

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2014 Jolla Ltd.
** Contact: Raine Makelainen <raine.makelainen@jolla.com>
**
****************************************************************************/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "webpagequeue.h"
#include "declarativewebpage.h"

#include <QObject>
#include <QRectF>

#ifndef DEBUG_LOGS
#define DEBUG_LOGS 0
#endif

#if DEBUG_LOGS
#include <QDebug>
#endif

WebPageQueue::WebPageQueue()
    : m_maxLiveCount(5)
    , m_livePagePrepended(false)
{
}

WebPageQueue::~WebPageQueue()
{
    clear();
}

int WebPageQueue::count() const
{
    int count = 0;
    for (; count < m_queue.count() && m_queue.at(count)->webPage; ++count) {}
    return count;
}

bool WebPageQueue::alive(int tabId) const
{
    int index = -1;
    WebPageQueue::WebPageEntry *webPageEntry = find(tabId, index);
    return index >= 0 && webPageEntry && webPageEntry->webPage;
}

bool WebPageQueue::active(int tabId) const
{
    if (!m_queue.isEmpty()) {
        WebPageQueue::WebPageEntry *firstEntry = m_queue.at(0);
        return firstEntry
                && firstEntry->webPage
                && firstEntry->webPage->tabId() == tabId;
    }
    return false;
}

DeclarativeWebPage *WebPageQueue::activate(int tabId)
{
    int index = -1;
    WebPageEntry *pageEntry = find(tabId, index);
    // No need to change position for the first index.
    if (index > 0) {
        m_queue.removeAt(index);
        m_queue.prepend(pageEntry);
    }

    return pageEntry ? pageEntry->webPage : 0;
}

DeclarativeWebPage *WebPageQueue::activeWebPage() const
{
    return !m_queue.isEmpty() ? m_queue.at(0)->webPage : 0;;
}

void WebPageQueue::release(int tabId,  bool virtualize)
{
    int index = -1;
    WebPageEntry *pageEntry = find(tabId, index);
#if DEBUG_LOGS
    qDebug() << "--- beginning: " << tabId << virtualize << pageEntry << (pageEntry ? pageEntry->webPage : 0);
    dumpPages();
#endif
    if (pageEntry) {
        if (pageEntry->webPage) {
            if (virtualize) {
                pageEntry->cssContentRect = new QRectF(pageEntry->webPage->contentRect());
            }
            if (pageEntry->webPage->completed()) {
                pageEntry->webPage->setParent(0);
                delete pageEntry->webPage;
            } else {
                QObject::connect(pageEntry->webPage.data(), &DeclarativeWebPage::completedChanged,
                                 pageEntry->webPage.data(), &QObject::deleteLater);
            }
        }

        pageEntry->webPage = 0;
        if (!virtualize && index >= 0) {
            delete pageEntry;
            m_queue.removeAt(index);
        }
    }

#if DEBUG_LOGS
    qDebug() << "--- end ---";
    dumpPages();
#endif
}

void WebPageQueue::prepend(int tabId, DeclarativeWebPage *webPage)
{
    int index = -1;
    WebPageQueue::WebPageEntry *pageEntry = find(tabId, index);
    if (!pageEntry) {
        pageEntry = new WebPageEntry(webPage, 0);
    } else {
        pageEntry->webPage = webPage;
        pageEntry->tabId = tabId;
        pageEntry->parentId = webPage->parentId();
        pageEntry->uniqueId = webPage->uniqueId();
        pageEntry->webPage->setResurrectedContentRect(*pageEntry->cssContentRect);
        if (pageEntry->cssContentRect) {
            delete pageEntry->cssContentRect;
            pageEntry->cssContentRect = 0;
        }
        m_queue.removeAt(index);
    }

    m_queue.prepend(pageEntry);
    updateLivePages();
    m_livePagePrepended = true;
}

void WebPageQueue::clear()
{
    int count = m_queue.count();
    for (int i = 0; i < count; ++i) {
        WebPageEntry *pageEntry = m_queue.at(i);
        pageEntry->allowPageDelete = true;
        delete pageEntry;
    }
    m_queue.clear();
}

int WebPageQueue::parentTabId(int tabId) const
{
    // TODO: This should be stored to the declarativewebpage to avoid loops.
    // This guarantees that child-parent relationship exists and it should
    // be taken into account if/when moved to declarativewebpage.
    // Ported from webpages.cpp.
    int index = 0;
    WebPageEntry *childPageEntry = find(tabId, index);
    if (childPageEntry) {
        int parentId = childPageEntry->parentId;
        for (int i = 0; i < m_queue.count(); ++i) {
            WebPageEntry *parentPageEntry = m_queue.at(i);
            if (parentPageEntry && (int)parentPageEntry->uniqueId == parentId) {
                return parentPageEntry->tabId;
            }
        }
    }
    return 0;
}

int WebPageQueue::tabId(uint32_t uniqueId) const
{
    for (int i = 0; i < m_queue.count(); ++i) {
        WebPageEntry *pageEntry = m_queue.at(i);
        if (pageEntry && pageEntry->webPage && pageEntry->webPage->uniqueId() == uniqueId) {
            return pageEntry->tabId;
        }
    }
    return 0;
}

bool WebPageQueue::setMaxLivePages(int count)
{
    if (m_maxLiveCount != count && count > 0) {
        m_maxLiveCount = count;
        updateLivePages();
        return true;
    }
    return false;
}

int WebPageQueue::maxLivePages() const
{
    return m_maxLiveCount;
}

bool WebPageQueue::virtualizeInactive()
{
    if (!m_livePagePrepended || m_queue.isEmpty() || !m_queue.at(0)->webPage || !m_queue.at(0)->webPage->completed()) {
        // no need to iterate through the queue if only one page alive or zero live pages
        return false;
    }

    DeclarativeWebPage* livePage = m_queue.at(0)->webPage;

    for (int i = 1; i < m_queue.count(); ++i) {
        DeclarativeWebPage* page = m_queue.at(i)->webPage;
        if (page &&
                (livePage->parentId() != (int)page->uniqueId() || (int)livePage->uniqueId() != page->parentId())) {
            release(m_queue.at(i)->tabId, true);
        }
    }

    m_livePagePrepended = false;
    return true;
}

void WebPageQueue::dumpPages() const
{
    qDebug() << "---- start ----";
    for (int i = 0; i < m_queue.count(); ++i) {
        WebPageEntry *pageEntry = m_queue.at(i);
        qDebug() << "tabId: " << pageEntry->tabId;
        qDebug() << "    page: " << pageEntry->webPage;
        qDebug() << "    cssContentRect:" << pageEntry->cssContentRect;
    }
    qDebug() << "---- end ------";
}

void WebPageQueue::updateLivePages()
{
    if (m_queue.count() > m_maxLiveCount && m_maxLiveCount > 1) {
        for (int i = m_maxLiveCount; i < m_queue.count(); ++i) {
            release(m_queue.at(i)->tabId, true);
        }
    }
}

WebPageQueue::WebPageEntry *WebPageQueue::find(int tabId, int &index) const
{
    int count = m_queue.count();
    for (int i = 0; i < count; ++i) {
        if (m_queue.at(i)->tabId == tabId) {
            index = i;
            return m_queue.at(i);
        }
    }
    index = -1;
    return 0;
}

WebPageQueue::WebPageEntry::WebPageEntry(DeclarativeWebPage *webPage, QRectF *cssContentRect)
    : webPage(webPage)
    , tabId(webPage ? webPage->tabId() : 0)
    , uniqueId(webPage ? webPage->uniqueId() : 0)
    , parentId(webPage ? webPage->parentId() : 0)
    , cssContentRect(cssContentRect)
    , allowPageDelete(false)
{
}

WebPageQueue::WebPageEntry::~WebPageEntry()
{
    if (cssContentRect) {
        delete cssContentRect;
    }

    if (webPage && (webPage->completed() || allowPageDelete)) {
        webPage->setParent(0);
        delete webPage;
    }

    cssContentRect = 0;
    webPage = 0;
}
<commit_msg>Cleanup unnecessary casting from webpagequeue<commit_after>/****************************************************************************
**
** Copyright (c) 2014 Jolla Ltd.
** Contact: Raine Makelainen <raine.makelainen@jolla.com>
**
****************************************************************************/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "webpagequeue.h"
#include "declarativewebpage.h"

#include <QObject>
#include <QRectF>

#ifndef DEBUG_LOGS
#define DEBUG_LOGS 0
#endif

#if DEBUG_LOGS
#include <QDebug>
#endif

WebPageQueue::WebPageQueue()
    : m_maxLiveCount(5)
    , m_livePagePrepended(false)
{
}

WebPageQueue::~WebPageQueue()
{
    clear();
}

int WebPageQueue::count() const
{
    int count = 0;
    for (; count < m_queue.count() && m_queue.at(count)->webPage; ++count) {}
    return count;
}

bool WebPageQueue::alive(int tabId) const
{
    int index = -1;
    WebPageQueue::WebPageEntry *webPageEntry = find(tabId, index);
    return index >= 0 && webPageEntry && webPageEntry->webPage;
}

bool WebPageQueue::active(int tabId) const
{
    if (!m_queue.isEmpty()) {
        WebPageQueue::WebPageEntry *firstEntry = m_queue.at(0);
        return firstEntry
                && firstEntry->webPage
                && firstEntry->webPage->tabId() == tabId;
    }
    return false;
}

DeclarativeWebPage *WebPageQueue::activate(int tabId)
{
    int index = -1;
    WebPageEntry *pageEntry = find(tabId, index);
    // No need to change position for the first index.
    if (index > 0) {
        m_queue.removeAt(index);
        m_queue.prepend(pageEntry);
    }

    return pageEntry ? pageEntry->webPage : 0;
}

DeclarativeWebPage *WebPageQueue::activeWebPage() const
{
    return !m_queue.isEmpty() ? m_queue.at(0)->webPage : 0;;
}

void WebPageQueue::release(int tabId,  bool virtualize)
{
    int index = -1;
    WebPageEntry *pageEntry = find(tabId, index);
#if DEBUG_LOGS
    qDebug() << "--- beginning: " << tabId << virtualize << pageEntry << (pageEntry ? pageEntry->webPage : 0);
    dumpPages();
#endif
    if (pageEntry) {
        if (pageEntry->webPage) {
            if (virtualize) {
                pageEntry->cssContentRect = new QRectF(pageEntry->webPage->contentRect());
            }
            if (pageEntry->webPage->completed()) {
                pageEntry->webPage->setParent(0);
                delete pageEntry->webPage;
            } else {
                QObject::connect(pageEntry->webPage.data(), &DeclarativeWebPage::completedChanged,
                                 pageEntry->webPage.data(), &QObject::deleteLater);
            }
        }

        pageEntry->webPage = 0;
        if (!virtualize && index >= 0) {
            delete pageEntry;
            m_queue.removeAt(index);
        }
    }

#if DEBUG_LOGS
    qDebug() << "--- end ---";
    dumpPages();
#endif
}

void WebPageQueue::prepend(int tabId, DeclarativeWebPage *webPage)
{
    int index = -1;
    WebPageQueue::WebPageEntry *pageEntry = find(tabId, index);
    if (!pageEntry) {
        pageEntry = new WebPageEntry(webPage, 0);
    } else {
        pageEntry->webPage = webPage;
        pageEntry->tabId = tabId;
        pageEntry->parentId = webPage->parentId();
        pageEntry->uniqueId = webPage->uniqueId();
        pageEntry->webPage->setResurrectedContentRect(*pageEntry->cssContentRect);
        if (pageEntry->cssContentRect) {
            delete pageEntry->cssContentRect;
            pageEntry->cssContentRect = 0;
        }
        m_queue.removeAt(index);
    }

    m_queue.prepend(pageEntry);
    updateLivePages();
    m_livePagePrepended = true;
}

void WebPageQueue::clear()
{
    int count = m_queue.count();
    for (int i = 0; i < count; ++i) {
        WebPageEntry *pageEntry = m_queue.at(i);
        pageEntry->allowPageDelete = true;
        delete pageEntry;
    }
    m_queue.clear();
}

int WebPageQueue::parentTabId(int tabId) const
{
    // TODO: This should be stored to the declarativewebpage to avoid loops.
    // This guarantees that child-parent relationship exists and it should
    // be taken into account if/when moved to declarativewebpage.
    // Ported from webpages.cpp.
    int index = 0;
    WebPageEntry *childPageEntry = find(tabId, index);
    if (childPageEntry) {
        int parentId = childPageEntry->parentId;
        for (int i = 0; i < m_queue.count(); ++i) {
            WebPageEntry *parentPageEntry = m_queue.at(i);
            if (parentPageEntry && parentPageEntry->uniqueId == parentId) {
                return parentPageEntry->tabId;
            }
        }
    }
    return 0;
}

int WebPageQueue::tabId(uint32_t uniqueId) const
{
    for (int i = 0; i < m_queue.count(); ++i) {
        WebPageEntry *pageEntry = m_queue.at(i);
        if (pageEntry && pageEntry->webPage && pageEntry->webPage->uniqueId() == uniqueId) {
            return pageEntry->tabId;
        }
    }
    return 0;
}

bool WebPageQueue::setMaxLivePages(int count)
{
    if (m_maxLiveCount != count && count > 0) {
        m_maxLiveCount = count;
        updateLivePages();
        return true;
    }
    return false;
}

int WebPageQueue::maxLivePages() const
{
    return m_maxLiveCount;
}

bool WebPageQueue::virtualizeInactive()
{
    if (!m_livePagePrepended || m_queue.isEmpty() || !m_queue.at(0)->webPage || !m_queue.at(0)->webPage->completed()) {
        // no need to iterate through the queue if only one page alive or zero live pages
        return false;
    }

    DeclarativeWebPage* livePage = m_queue.at(0)->webPage;

    for (int i = 1; i < m_queue.count(); ++i) {
        DeclarativeWebPage* page = m_queue.at(i)->webPage;
        if (page &&
                (livePage->parentId() != (int)page->uniqueId() || (int)livePage->uniqueId() != page->parentId())) {
            release(m_queue.at(i)->tabId, true);
        }
    }

    m_livePagePrepended = false;
    return true;
}

void WebPageQueue::dumpPages() const
{
    qDebug() << "---- start ----";
    for (int i = 0; i < m_queue.count(); ++i) {
        WebPageEntry *pageEntry = m_queue.at(i);
        qDebug() << "tabId: " << pageEntry->tabId;
        qDebug() << "    page: " << pageEntry->webPage;
        qDebug() << "    cssContentRect:" << pageEntry->cssContentRect;
    }
    qDebug() << "---- end ------";
}

void WebPageQueue::updateLivePages()
{
    if (m_queue.count() > m_maxLiveCount && m_maxLiveCount > 1) {
        for (int i = m_maxLiveCount; i < m_queue.count(); ++i) {
            release(m_queue.at(i)->tabId, true);
        }
    }
}

WebPageQueue::WebPageEntry *WebPageQueue::find(int tabId, int &index) const
{
    int count = m_queue.count();
    for (int i = 0; i < count; ++i) {
        if (m_queue.at(i)->tabId == tabId) {
            index = i;
            return m_queue.at(i);
        }
    }
    index = -1;
    return 0;
}

WebPageQueue::WebPageEntry::WebPageEntry(DeclarativeWebPage *webPage, QRectF *cssContentRect)
    : webPage(webPage)
    , tabId(webPage ? webPage->tabId() : 0)
    , uniqueId(webPage ? webPage->uniqueId() : 0)
    , parentId(webPage ? webPage->parentId() : 0)
    , cssContentRect(cssContentRect)
    , allowPageDelete(false)
{
}

WebPageQueue::WebPageEntry::~WebPageEntry()
{
    if (cssContentRect) {
        delete cssContentRect;
    }

    if (webPage && (webPage->completed() || allowPageDelete)) {
        webPage->setParent(0);
        delete webPage;
    }

    cssContentRect = 0;
    webPage = 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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 "chrome/browser/chromeos/login/owner_manager.h"

#include <string>
#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/login/signed_settings_temp_storage.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"

namespace chromeos {

OwnerManager::OwnerManager()
    : private_key_(NULL),
      public_key_(NULL),
      utils_(OwnerKeyUtils::Create()) {
}

OwnerManager::~OwnerManager() {}

void OwnerManager::LoadOwnerKey() {
  BootTimesLoader::Get()->AddLoginTimeMarker("LoadOwnerKeyStart", false);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  VLOG(1) << "Loading owner key";
  NotificationType result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED;

  // If |public_key_| isn't empty, we already have the key, so don't
  // try to import again.
  if (public_key_.empty() &&
      !utils_->ImportPublicKey(utils_->GetOwnerKeyFilePath(), &public_key_)) {
    result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_FAILED;
  }

  // Whether we loaded the public key or not, send a notification indicating
  // that we're done with this attempt.
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(this,
                        &OwnerManager::SendNotification,
                        result,
                        NotificationService::NoDetails()));
}

bool OwnerManager::EnsurePublicKey() {
  if (public_key_.empty())
    LoadOwnerKey();

  return !public_key_.empty();
}

bool OwnerManager::EnsurePrivateKey() {
  if (!EnsurePublicKey())
    return false;

  if (!private_key_.get())
    private_key_.reset(utils_->FindPrivateKey(public_key_));

  return private_key_.get() != NULL;
}

void OwnerManager::Sign(const BrowserThread::ID thread_id,
                        const std::string& data,
                        Delegate* d) {
  BootTimesLoader::Get()->AddLoginTimeMarker("SignStart", false);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  // If it's not the case that we can get both keys...
  if (!(EnsurePublicKey() && EnsurePrivateKey())) {
    BrowserThread::PostTask(
        thread_id, FROM_HERE,
        NewRunnableMethod(this,
                          &OwnerManager::CallDelegate,
                          d, KEY_UNAVAILABLE, std::vector<uint8>()));
    BootTimesLoader::Get()->AddLoginTimeMarker("SignEnd", false);
    return;
  }

  VLOG(1) << "Starting signing attempt";
  KeyOpCode return_code = SUCCESS;
  std::vector<uint8> signature;
  if (!utils_->Sign(data, &signature, private_key_.get())) {
    return_code = OPERATION_FAILED;
  }

  BrowserThread::PostTask(
      thread_id, FROM_HERE,
      NewRunnableMethod(this,
                        &OwnerManager::CallDelegate,
                        d, return_code, signature));
  BootTimesLoader::Get()->AddLoginTimeMarker("SignEnd", false);
}

void OwnerManager::Verify(const BrowserThread::ID thread_id,
                          const std::string& data,
                          const std::vector<uint8>& signature,
                          Delegate* d) {
  BootTimesLoader::Get()->AddLoginTimeMarker("VerifyStart", false);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  if (!EnsurePublicKey()) {
    BrowserThread::PostTask(
        thread_id, FROM_HERE,
        NewRunnableMethod(this,
                          &OwnerManager::CallDelegate,
                          d, KEY_UNAVAILABLE, std::vector<uint8>()));
    BootTimesLoader::Get()->AddLoginTimeMarker("VerifyEnd", false);
    return;
  }

  VLOG(1) << "Starting verify attempt";
  KeyOpCode return_code = SUCCESS;
  if (!utils_->Verify(data, signature, public_key_)) {
    return_code = OPERATION_FAILED;
  }
  BrowserThread::PostTask(
      thread_id, FROM_HERE,
      NewRunnableMethod(this,
                        &OwnerManager::CallDelegate,
                        d, return_code, std::vector<uint8>()));
  BootTimesLoader::Get()->AddLoginTimeMarker("VerifyEnd", false);
}

void OwnerManager::SendNotification(NotificationType type,
                                    const NotificationDetails& details) {
  NotificationService::current()->Notify(
      type,
      NotificationService::AllSources(),
      details);
}

}  // namespace chromeos
<commit_msg>public_key_ is a std::vector<uint8>, initialize with 0 instead of NULL. Review URL: http://codereview.chromium.org/6693043<commit_after>// Copyright (c) 2011 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 "chrome/browser/chromeos/login/owner_manager.h"

#include <string>
#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/login/signed_settings_temp_storage.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"

namespace chromeos {

OwnerManager::OwnerManager()
    : private_key_(NULL),
      public_key_(0),
      utils_(OwnerKeyUtils::Create()) {
}

OwnerManager::~OwnerManager() {}

void OwnerManager::LoadOwnerKey() {
  BootTimesLoader::Get()->AddLoginTimeMarker("LoadOwnerKeyStart", false);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  VLOG(1) << "Loading owner key";
  NotificationType result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED;

  // If |public_key_| isn't empty, we already have the key, so don't
  // try to import again.
  if (public_key_.empty() &&
      !utils_->ImportPublicKey(utils_->GetOwnerKeyFilePath(), &public_key_)) {
    result = NotificationType::OWNER_KEY_FETCH_ATTEMPT_FAILED;
  }

  // Whether we loaded the public key or not, send a notification indicating
  // that we're done with this attempt.
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(this,
                        &OwnerManager::SendNotification,
                        result,
                        NotificationService::NoDetails()));
}

bool OwnerManager::EnsurePublicKey() {
  if (public_key_.empty())
    LoadOwnerKey();

  return !public_key_.empty();
}

bool OwnerManager::EnsurePrivateKey() {
  if (!EnsurePublicKey())
    return false;

  if (!private_key_.get())
    private_key_.reset(utils_->FindPrivateKey(public_key_));

  return private_key_.get() != NULL;
}

void OwnerManager::Sign(const BrowserThread::ID thread_id,
                        const std::string& data,
                        Delegate* d) {
  BootTimesLoader::Get()->AddLoginTimeMarker("SignStart", false);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  // If it's not the case that we can get both keys...
  if (!(EnsurePublicKey() && EnsurePrivateKey())) {
    BrowserThread::PostTask(
        thread_id, FROM_HERE,
        NewRunnableMethod(this,
                          &OwnerManager::CallDelegate,
                          d, KEY_UNAVAILABLE, std::vector<uint8>()));
    BootTimesLoader::Get()->AddLoginTimeMarker("SignEnd", false);
    return;
  }

  VLOG(1) << "Starting signing attempt";
  KeyOpCode return_code = SUCCESS;
  std::vector<uint8> signature;
  if (!utils_->Sign(data, &signature, private_key_.get())) {
    return_code = OPERATION_FAILED;
  }

  BrowserThread::PostTask(
      thread_id, FROM_HERE,
      NewRunnableMethod(this,
                        &OwnerManager::CallDelegate,
                        d, return_code, signature));
  BootTimesLoader::Get()->AddLoginTimeMarker("SignEnd", false);
}

void OwnerManager::Verify(const BrowserThread::ID thread_id,
                          const std::string& data,
                          const std::vector<uint8>& signature,
                          Delegate* d) {
  BootTimesLoader::Get()->AddLoginTimeMarker("VerifyStart", false);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  if (!EnsurePublicKey()) {
    BrowserThread::PostTask(
        thread_id, FROM_HERE,
        NewRunnableMethod(this,
                          &OwnerManager::CallDelegate,
                          d, KEY_UNAVAILABLE, std::vector<uint8>()));
    BootTimesLoader::Get()->AddLoginTimeMarker("VerifyEnd", false);
    return;
  }

  VLOG(1) << "Starting verify attempt";
  KeyOpCode return_code = SUCCESS;
  if (!utils_->Verify(data, signature, public_key_)) {
    return_code = OPERATION_FAILED;
  }
  BrowserThread::PostTask(
      thread_id, FROM_HERE,
      NewRunnableMethod(this,
                        &OwnerManager::CallDelegate,
                        d, return_code, std::vector<uint8>()));
  BootTimesLoader::Get()->AddLoginTimeMarker("VerifyEnd", false);
}

void OwnerManager::SendNotification(NotificationType type,
                                    const NotificationDetails& details) {
  NotificationService::current()->Notify(
      type,
      NotificationService::AllSources(),
      details);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2009 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 "chrome/browser/gtk/browser_toolbar_view_gtk.h"

#include "base/logging.h"
#include "base/base_paths_linux.h"
#include "base/path_service.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/back_forward_menu_model_gtk.h"
#include "chrome/browser/gtk/standard_menus.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

const int BrowserToolbarGtk::kToolbarHeight = 38;
// For the back/forward dropdown menus, the time in milliseconds between
// when the user clicks and the popup menu appears.
static const int kMenuTimerDelay = 500;

BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser)
    : toolbar_(NULL),
      entry_(NULL),
      model_(browser->toolbar_model()),
      browser_(browser),
      profile_(NULL),
      show_menu_factory_(this) {
  browser_->command_updater()->AddCommandObserver(IDC_BACK, this);
  browser_->command_updater()->AddCommandObserver(IDC_FORWARD, this);
  browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this);
  browser_->command_updater()->AddCommandObserver(IDC_HOME, this);
  browser_->command_updater()->AddCommandObserver(IDC_STAR, this);

  back_menu_model_.reset(new BackForwardMenuModelGtk(
      browser, BackForwardMenuModel::BACKWARD_MENU_DELEGATE));
  forward_menu_model_.reset(new BackForwardMenuModelGtk(
      browser, BackForwardMenuModel::FORWARD_MENU_DELEGATE));
}

BrowserToolbarGtk::~BrowserToolbarGtk() {
}

void BrowserToolbarGtk::Init(Profile* profile) {
  show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this);

  toolbar_ = gtk_hbox_new(FALSE, 0);
  gtk_container_set_border_width(GTK_CONTAINER(toolbar_), 4);
  // TODO(evanm): this setting of the x-size to 0 makes it so the window
  // can be resized arbitrarily small.  We should figure out what we want
  // with respect to resizing before engineering around it, though.
  gtk_widget_set_size_request(toolbar_, 0, kToolbarHeight);

  toolbar_tooltips_ = gtk_tooltips_new();

  back_.reset(BuildBackForwardButton(IDR_BACK, IDR_BACK_P, IDR_BACK_H,
              IDR_BACK_D,
              l10n_util::GetString(IDS_TOOLTIP_BACK)));
  forward_.reset(BuildBackForwardButton(IDR_FORWARD, IDR_FORWARD_P,
                 IDR_FORWARD_H, IDR_FORWARD_D,
                 l10n_util::GetString(IDS_TOOLTIP_FORWARD)));

  gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);

  reload_.reset(BuildToolbarButton(IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0,
      l10n_util::GetString(IDS_TOOLTIP_RELOAD)));

  // TODO(port): we need to dynamically react to changes in show_home_button_
  // and hide/show home appropriately.  But we don't have a UI for it yet.
  if (*show_home_button_)
    home_.reset(MakeHomeButton());

  gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new("  "), FALSE, FALSE, 0);

  star_.reset(BuildToolbarButton(IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D,
      l10n_util::GetString(IDS_TOOLTIP_STAR)));

  entry_ = gtk_entry_new();
  gtk_widget_set_size_request(entry_, 0, 27);
  g_signal_connect(G_OBJECT(entry_), "activate",
                   G_CALLBACK(OnEntryActivate), this);
  gtk_box_pack_start(GTK_BOX(toolbar_), entry_, TRUE, TRUE, 0);

  go_.reset(BuildToolbarButton(IDR_GO, IDR_GO_P, IDR_GO_H, 0, L""));

  gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);

  page_menu_button_.reset(BuildToolbarMenuButton(IDR_MENU_PAGE,
      l10n_util::GetString(IDS_PAGEMENU_TOOLTIP)));
  app_menu_button_.reset(BuildToolbarMenuButton(IDR_MENU_CHROME,
      l10n_util::GetStringF(IDS_APPMENU_TOOLTIP,
                            l10n_util::GetString(IDS_PRODUCT_NAME))));

  SetProfile(profile);
}

void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) {
  gtk_box_pack_start(GTK_BOX(box), toolbar_, FALSE, FALSE, 0);
}

void BrowserToolbarGtk::EnabledStateChangedForCommand(int id, bool enabled) {
  GtkWidget* widget = NULL;
  switch (id) {
    case IDC_BACK:
      widget = back_->widget();
      break;
    case IDC_FORWARD:
      widget = forward_->widget();
      break;
    case IDC_RELOAD:
      widget = reload_->widget();
      break;
    case IDC_HOME:
      if (home_.get())
        widget = home_->widget();
      break;
    case IDC_STAR:
      widget = star_->widget();
      break;
  }
  if (widget)
    gtk_widget_set_sensitive(widget, enabled);
}

bool BrowserToolbarGtk::IsCommandEnabled(int command_id) const {
  return browser_->command_updater()->IsCommandEnabled(command_id);
}

bool BrowserToolbarGtk::IsItemChecked(int id) const {
  if (!profile_)
    return false;
  if (id == IDC_SHOW_BOOKMARK_BAR)
    return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
  // TODO(port): Fix this when we get some items that want checking!
  return false;
}

void BrowserToolbarGtk::ExecuteCommand(int id) {
  browser_->ExecuteCommand(id);
}

void BrowserToolbarGtk::Observe(NotificationType type,
                                const NotificationSource& source,
                                const NotificationDetails& details) {
  if (type == NotificationType::PREF_CHANGED) {
    std::wstring* pref_name = Details<std::wstring>(details).ptr();
    if (*pref_name == prefs::kShowHomeButton) {
      // TODO(port): add/remove home button.
      NOTIMPLEMENTED();
    }
  }
}

void BrowserToolbarGtk::SetProfile(Profile* profile) {
  if (profile == profile_)
    return;

  profile_ = profile;
  // TODO(erg): location_bar_ is a normal gtk text box right now. Change this
  // when we get omnibox support.
  //  location_bar_->SetProfile(profile);
}

void BrowserToolbarGtk::UpdateTabContents(TabContents* contents,
                                          bool should_restore_state) {
  // Extract the UTF-8 representation of the URL.
  gtk_entry_set_text(GTK_ENTRY(entry_),
                     contents->GetURL().possibly_invalid_spec().c_str());
}

CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton(
    int normal_id, int active_id, int highlight_id, int depressed_id,
    const std::wstring& localized_tooltip) {
  CustomDrawButton* button = new CustomDrawButton(normal_id, active_id,
      highlight_id, depressed_id);

  gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
                       GTK_WIDGET(button->widget()),
                       WideToUTF8(localized_tooltip).c_str(),
                       WideToUTF8(localized_tooltip).c_str());
  g_signal_connect(G_OBJECT(button->widget()), "clicked",
                   G_CALLBACK(OnButtonClick), this);

  gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
  return button;
}

CustomContainerButton* BrowserToolbarGtk::BuildToolbarMenuButton(
    int icon_id,
    const std::wstring& localized_tooltip) {
  CustomContainerButton* button = new CustomContainerButton;

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  gtk_container_set_border_width(GTK_CONTAINER(button->widget()), 2);
  gtk_container_add(GTK_CONTAINER(button->widget()),
                    gtk_image_new_from_pixbuf(rb.LoadPixbuf(icon_id)));

  gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
                       GTK_WIDGET(button->widget()),
                       WideToUTF8(localized_tooltip).c_str(),
                       WideToUTF8(localized_tooltip).c_str());
  g_signal_connect(G_OBJECT(button->widget()), "button-press-event",
                   G_CALLBACK(OnMenuButtonPressEvent), this);

  gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);

  return button;
}

// static
void BrowserToolbarGtk::OnEntryActivate(GtkEntry *entry,
                                        BrowserToolbarGtk* toolbar) {
  GURL dest(URLFixerUpper::FixupURL(std::string(gtk_entry_get_text(entry)),
                                    std::string()));
  toolbar->browser_->GetSelectedTabContents()->
      OpenURL(dest, GURL(), CURRENT_TAB, PageTransition::TYPED);
}

/* static */
void BrowserToolbarGtk::OnButtonClick(GtkWidget* button,
                                      BrowserToolbarGtk* toolbar) {
  int tag = -1;
  if (button == toolbar->back_->widget())
    tag = IDC_BACK;
  else if (button == toolbar->forward_->widget())
    tag = IDC_FORWARD;
  else if (button == toolbar->reload_->widget())
    tag = IDC_RELOAD;
  else if (toolbar->home_.get() && button == toolbar->home_->widget())
    tag = IDC_HOME;
  else if (button == toolbar->star_->widget())
    tag = IDC_STAR;

  if (tag == IDC_BACK || tag == IDC_FORWARD)
    toolbar->show_menu_factory_.RevokeAll();

  DCHECK(tag != -1) << "Impossible button click callback";
  toolbar->browser_->ExecuteCommand(tag);
}

// static
gboolean BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button,
                                                   GdkEvent* event,
                                                   BrowserToolbarGtk* toolbar) {
  // TODO(port): this never puts the button into the "active" state,
  // which means we never display the button-pressed-down graphics.  I
  // suspect a better way to do it is just to use a real GtkMenuShell
  // with our custom drawing.
  if (event->type == GDK_BUTTON_PRESS) {
    GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
    if (event_button->button == 1) {
      // We have a button press we should respond to.
      if (button == toolbar->page_menu_button_->widget()) {
        toolbar->RunPageMenu(event);
        return TRUE;
      } else if (button == toolbar->app_menu_button_->widget()) {
        toolbar->RunAppMenu(event);
        return TRUE;
      }
    }
  }

  return FALSE;
}

CustomDrawButton* BrowserToolbarGtk::BuildBackForwardButton(
    int normal_id,
    int active_id,
    int highlight_id,
    int depressed_id,
    const std::wstring& localized_tooltip) {
  CustomDrawButton* button = new CustomDrawButton(normal_id, active_id,
                                                  highlight_id, depressed_id);

  // TODO(erg): Mismatch between wstring and string.
  // gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
  //                      GTK_WIDGET(back_),
  //                      localized_tooltip, localized_tooltip);

  g_signal_connect(G_OBJECT(button->widget()), "button-press-event",
                   G_CALLBACK(OnBackForwardPressEvent), this);
  g_signal_connect(G_OBJECT(button->widget()), "clicked",
                   G_CALLBACK(OnButtonClick), this);

  gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
  // Popup the menu as left-aligned relative to this widget rather than the
  // default of right aligned.
  g_object_set_data(G_OBJECT(button->widget()), "left-align-popup",
                    reinterpret_cast<void*>(true));
  return button;
}

// static
gboolean BrowserToolbarGtk::OnBackForwardPressEvent(GtkWidget* widget,
    GdkEventButton* event,
    BrowserToolbarGtk* toolbar) {
  // TODO(port): only allow left clicks to open the menu.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      toolbar->show_menu_factory_.NewRunnableMethod(
          &BrowserToolbarGtk::ShowBackForwardMenu,
          widget, event->button),
      kMenuTimerDelay);
  return FALSE;
}

void BrowserToolbarGtk::ShowBackForwardMenu(GtkWidget* widget,
                                            gint button_type) {
  if (widget == back_->widget()) {
    back_forward_menu_.reset(new MenuGtk(back_menu_model_.get()));
  } else {
    back_forward_menu_.reset(new MenuGtk(forward_menu_model_.get()));
  }

  back_forward_menu_->Popup(widget, button_type, gtk_get_current_event_time());
}

void BrowserToolbarGtk::RunPageMenu(GdkEvent* button_press_event) {
  if (page_menu_ == NULL) {
    page_menu_.reset(new MenuGtk(this, GetStandardPageMenu()));
  }

  page_menu_->Popup(page_menu_button_->widget(), button_press_event);
}

void BrowserToolbarGtk::RunAppMenu(GdkEvent* button_press_event) {
  if (app_menu_ == NULL) {
    app_menu_.reset(new MenuGtk(this, GetStandardAppMenu()));
  }

  app_menu_->Popup(app_menu_button_->widget(), button_press_event);
}

CustomDrawButton* BrowserToolbarGtk::MakeHomeButton() {
  return BuildToolbarButton(IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0,
                            l10n_util::GetString(IDS_TOOLTIP_HOME));
}
<commit_msg>Add the IDC_GO mapping for the go button widget.<commit_after>// Copyright (c) 2009 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 "chrome/browser/gtk/browser_toolbar_view_gtk.h"

#include "base/logging.h"
#include "base/base_paths_linux.h"
#include "base/path_service.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/back_forward_menu_model_gtk.h"
#include "chrome/browser/gtk/standard_menus.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

const int BrowserToolbarGtk::kToolbarHeight = 38;
// For the back/forward dropdown menus, the time in milliseconds between
// when the user clicks and the popup menu appears.
static const int kMenuTimerDelay = 500;

BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser)
    : toolbar_(NULL),
      entry_(NULL),
      model_(browser->toolbar_model()),
      browser_(browser),
      profile_(NULL),
      show_menu_factory_(this) {
  browser_->command_updater()->AddCommandObserver(IDC_BACK, this);
  browser_->command_updater()->AddCommandObserver(IDC_FORWARD, this);
  browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this);
  browser_->command_updater()->AddCommandObserver(IDC_HOME, this);
  browser_->command_updater()->AddCommandObserver(IDC_STAR, this);

  back_menu_model_.reset(new BackForwardMenuModelGtk(
      browser, BackForwardMenuModel::BACKWARD_MENU_DELEGATE));
  forward_menu_model_.reset(new BackForwardMenuModelGtk(
      browser, BackForwardMenuModel::FORWARD_MENU_DELEGATE));
}

BrowserToolbarGtk::~BrowserToolbarGtk() {
}

void BrowserToolbarGtk::Init(Profile* profile) {
  show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this);

  toolbar_ = gtk_hbox_new(FALSE, 0);
  gtk_container_set_border_width(GTK_CONTAINER(toolbar_), 4);
  // TODO(evanm): this setting of the x-size to 0 makes it so the window
  // can be resized arbitrarily small.  We should figure out what we want
  // with respect to resizing before engineering around it, though.
  gtk_widget_set_size_request(toolbar_, 0, kToolbarHeight);

  toolbar_tooltips_ = gtk_tooltips_new();

  back_.reset(BuildBackForwardButton(IDR_BACK, IDR_BACK_P, IDR_BACK_H,
              IDR_BACK_D,
              l10n_util::GetString(IDS_TOOLTIP_BACK)));
  forward_.reset(BuildBackForwardButton(IDR_FORWARD, IDR_FORWARD_P,
                 IDR_FORWARD_H, IDR_FORWARD_D,
                 l10n_util::GetString(IDS_TOOLTIP_FORWARD)));

  gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);

  reload_.reset(BuildToolbarButton(IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0,
      l10n_util::GetString(IDS_TOOLTIP_RELOAD)));

  // TODO(port): we need to dynamically react to changes in show_home_button_
  // and hide/show home appropriately.  But we don't have a UI for it yet.
  if (*show_home_button_)
    home_.reset(MakeHomeButton());

  gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new("  "), FALSE, FALSE, 0);

  star_.reset(BuildToolbarButton(IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D,
      l10n_util::GetString(IDS_TOOLTIP_STAR)));

  entry_ = gtk_entry_new();
  gtk_widget_set_size_request(entry_, 0, 27);
  g_signal_connect(G_OBJECT(entry_), "activate",
                   G_CALLBACK(OnEntryActivate), this);
  gtk_box_pack_start(GTK_BOX(toolbar_), entry_, TRUE, TRUE, 0);

  go_.reset(BuildToolbarButton(IDR_GO, IDR_GO_P, IDR_GO_H, 0, L""));

  gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);

  page_menu_button_.reset(BuildToolbarMenuButton(IDR_MENU_PAGE,
      l10n_util::GetString(IDS_PAGEMENU_TOOLTIP)));
  app_menu_button_.reset(BuildToolbarMenuButton(IDR_MENU_CHROME,
      l10n_util::GetStringF(IDS_APPMENU_TOOLTIP,
                            l10n_util::GetString(IDS_PRODUCT_NAME))));

  SetProfile(profile);
}

void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) {
  gtk_box_pack_start(GTK_BOX(box), toolbar_, FALSE, FALSE, 0);
}

void BrowserToolbarGtk::EnabledStateChangedForCommand(int id, bool enabled) {
  GtkWidget* widget = NULL;
  switch (id) {
    case IDC_BACK:
      widget = back_->widget();
      break;
    case IDC_FORWARD:
      widget = forward_->widget();
      break;
    case IDC_RELOAD:
      widget = reload_->widget();
      break;
    case IDC_GO:
      widget = go_->widget();
      break;
    case IDC_HOME:
      if (home_.get())
        widget = home_->widget();
      break;
    case IDC_STAR:
      widget = star_->widget();
      break;
  }
  if (widget)
    gtk_widget_set_sensitive(widget, enabled);
}

bool BrowserToolbarGtk::IsCommandEnabled(int command_id) const {
  return browser_->command_updater()->IsCommandEnabled(command_id);
}

bool BrowserToolbarGtk::IsItemChecked(int id) const {
  if (!profile_)
    return false;
  if (id == IDC_SHOW_BOOKMARK_BAR)
    return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
  // TODO(port): Fix this when we get some items that want checking!
  return false;
}

void BrowserToolbarGtk::ExecuteCommand(int id) {
  browser_->ExecuteCommand(id);
}

void BrowserToolbarGtk::Observe(NotificationType type,
                                const NotificationSource& source,
                                const NotificationDetails& details) {
  if (type == NotificationType::PREF_CHANGED) {
    std::wstring* pref_name = Details<std::wstring>(details).ptr();
    if (*pref_name == prefs::kShowHomeButton) {
      // TODO(port): add/remove home button.
      NOTIMPLEMENTED();
    }
  }
}

void BrowserToolbarGtk::SetProfile(Profile* profile) {
  if (profile == profile_)
    return;

  profile_ = profile;
  // TODO(erg): location_bar_ is a normal gtk text box right now. Change this
  // when we get omnibox support.
  //  location_bar_->SetProfile(profile);
}

void BrowserToolbarGtk::UpdateTabContents(TabContents* contents,
                                          bool should_restore_state) {
  // Extract the UTF-8 representation of the URL.
  gtk_entry_set_text(GTK_ENTRY(entry_),
                     contents->GetURL().possibly_invalid_spec().c_str());
}

CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton(
    int normal_id, int active_id, int highlight_id, int depressed_id,
    const std::wstring& localized_tooltip) {
  CustomDrawButton* button = new CustomDrawButton(normal_id, active_id,
      highlight_id, depressed_id);

  gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
                       GTK_WIDGET(button->widget()),
                       WideToUTF8(localized_tooltip).c_str(),
                       WideToUTF8(localized_tooltip).c_str());
  g_signal_connect(G_OBJECT(button->widget()), "clicked",
                   G_CALLBACK(OnButtonClick), this);

  gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
  return button;
}

CustomContainerButton* BrowserToolbarGtk::BuildToolbarMenuButton(
    int icon_id,
    const std::wstring& localized_tooltip) {
  CustomContainerButton* button = new CustomContainerButton;

  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  gtk_container_set_border_width(GTK_CONTAINER(button->widget()), 2);
  gtk_container_add(GTK_CONTAINER(button->widget()),
                    gtk_image_new_from_pixbuf(rb.LoadPixbuf(icon_id)));

  gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
                       GTK_WIDGET(button->widget()),
                       WideToUTF8(localized_tooltip).c_str(),
                       WideToUTF8(localized_tooltip).c_str());
  g_signal_connect(G_OBJECT(button->widget()), "button-press-event",
                   G_CALLBACK(OnMenuButtonPressEvent), this);

  gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);

  return button;
}

// static
void BrowserToolbarGtk::OnEntryActivate(GtkEntry *entry,
                                        BrowserToolbarGtk* toolbar) {
  GURL dest(URLFixerUpper::FixupURL(std::string(gtk_entry_get_text(entry)),
                                    std::string()));
  toolbar->browser_->GetSelectedTabContents()->
      OpenURL(dest, GURL(), CURRENT_TAB, PageTransition::TYPED);
}

/* static */
void BrowserToolbarGtk::OnButtonClick(GtkWidget* button,
                                      BrowserToolbarGtk* toolbar) {
  int tag = -1;
  if (button == toolbar->back_->widget())
    tag = IDC_BACK;
  else if (button == toolbar->forward_->widget())
    tag = IDC_FORWARD;
  else if (button == toolbar->reload_->widget())
    tag = IDC_RELOAD;
  else if (button == toolbar->go_->widget())
    tag = IDC_GO;
  else if (toolbar->home_.get() && button == toolbar->home_->widget())
    tag = IDC_HOME;
  else if (button == toolbar->star_->widget())
    tag = IDC_STAR;

  if (tag == IDC_BACK || tag == IDC_FORWARD)
    toolbar->show_menu_factory_.RevokeAll();

  DCHECK(tag != -1) << "Impossible button click callback";
  toolbar->browser_->ExecuteCommand(tag);
}

// static
gboolean BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button,
                                                   GdkEvent* event,
                                                   BrowserToolbarGtk* toolbar) {
  // TODO(port): this never puts the button into the "active" state,
  // which means we never display the button-pressed-down graphics.  I
  // suspect a better way to do it is just to use a real GtkMenuShell
  // with our custom drawing.
  if (event->type == GDK_BUTTON_PRESS) {
    GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
    if (event_button->button == 1) {
      // We have a button press we should respond to.
      if (button == toolbar->page_menu_button_->widget()) {
        toolbar->RunPageMenu(event);
        return TRUE;
      } else if (button == toolbar->app_menu_button_->widget()) {
        toolbar->RunAppMenu(event);
        return TRUE;
      }
    }
  }

  return FALSE;
}

CustomDrawButton* BrowserToolbarGtk::BuildBackForwardButton(
    int normal_id,
    int active_id,
    int highlight_id,
    int depressed_id,
    const std::wstring& localized_tooltip) {
  CustomDrawButton* button = new CustomDrawButton(normal_id, active_id,
                                                  highlight_id, depressed_id);

  // TODO(erg): Mismatch between wstring and string.
  // gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
  //                      GTK_WIDGET(back_),
  //                      localized_tooltip, localized_tooltip);

  g_signal_connect(G_OBJECT(button->widget()), "button-press-event",
                   G_CALLBACK(OnBackForwardPressEvent), this);
  g_signal_connect(G_OBJECT(button->widget()), "clicked",
                   G_CALLBACK(OnButtonClick), this);

  gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
  // Popup the menu as left-aligned relative to this widget rather than the
  // default of right aligned.
  g_object_set_data(G_OBJECT(button->widget()), "left-align-popup",
                    reinterpret_cast<void*>(true));
  return button;
}

// static
gboolean BrowserToolbarGtk::OnBackForwardPressEvent(GtkWidget* widget,
    GdkEventButton* event,
    BrowserToolbarGtk* toolbar) {
  // TODO(port): only allow left clicks to open the menu.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      toolbar->show_menu_factory_.NewRunnableMethod(
          &BrowserToolbarGtk::ShowBackForwardMenu,
          widget, event->button),
      kMenuTimerDelay);
  return FALSE;
}

void BrowserToolbarGtk::ShowBackForwardMenu(GtkWidget* widget,
                                            gint button_type) {
  if (widget == back_->widget()) {
    back_forward_menu_.reset(new MenuGtk(back_menu_model_.get()));
  } else {
    back_forward_menu_.reset(new MenuGtk(forward_menu_model_.get()));
  }

  back_forward_menu_->Popup(widget, button_type, gtk_get_current_event_time());
}

void BrowserToolbarGtk::RunPageMenu(GdkEvent* button_press_event) {
  if (page_menu_ == NULL) {
    page_menu_.reset(new MenuGtk(this, GetStandardPageMenu()));
  }

  page_menu_->Popup(page_menu_button_->widget(), button_press_event);
}

void BrowserToolbarGtk::RunAppMenu(GdkEvent* button_press_event) {
  if (app_menu_ == NULL) {
    app_menu_.reset(new MenuGtk(this, GetStandardAppMenu()));
  }

  app_menu_->Popup(app_menu_button_->widget(), button_press_event);
}

CustomDrawButton* BrowserToolbarGtk::MakeHomeButton() {
  return BuildToolbarButton(IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0,
                            l10n_util::GetString(IDS_TOOLTIP_HOME));
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  TextureSetupTest.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "UnitTest++/src/UnitTest++.h"
#include "Gfx/Setup/TextureSetup.h"

using namespace Oryol;

TEST(TextureSetupTest) {

    // setup as absolute-size render target, no depth buffer
    auto rt = TextureSetup::RenderTarget(320, 256);
    rt.Locator = Locator("absSize");
    rt.ColorFormat = PixelFormat::RGB8;
    CHECK(!rt.ShouldSetupFromFile());
    CHECK(!rt.ShouldSetupFromImageFileData());
    CHECK(!rt.ShouldSetupFromPixelData());
    CHECK(rt.ShouldSetupAsRenderTarget());
    CHECK(!rt.IsRelSizeRenderTarget());
    CHECK(!rt.HasSharedDepth());
    CHECK(!rt.HasDepth());
    CHECK(rt.Locator.Location() == "absSize");
    CHECK(rt.Width == 320);
    CHECK(rt.Height == 256);
    CHECK(rt.RelWidth == 0.0f);
    CHECK(rt.RelHeight == 0.0f);
    CHECK(rt.ColorFormat == PixelFormat::RGB8);
    CHECK(rt.DepthFormat == PixelFormat::InvalidPixelFormat);
    CHECK(!rt.DepthRenderTarget.IsValid());
    CHECK(rt.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as absolute-size render target, with depth buffer
    auto rt0 = TextureSetup::RenderTarget(320, 256);
    rt0.ColorFormat = PixelFormat::RGBA8;
    rt0.DepthFormat = PixelFormat::D24S8;
    CHECK(!rt0.ShouldSetupFromFile());
    CHECK(!rt0.ShouldSetupFromImageFileData());
    CHECK(!rt0.ShouldSetupFromPixelData());
    CHECK(rt0.ShouldSetupAsRenderTarget());
    CHECK(!rt0.IsRelSizeRenderTarget());
    CHECK(!rt0.HasSharedDepth());
    CHECK(rt0.HasDepth());
    CHECK(rt0.Locator == Locator::NonShared());
    CHECK(rt0.Width == 320);
    CHECK(rt0.Height == 256);
    CHECK(rt0.RelWidth == 0.0f);
    CHECK(rt0.RelHeight == 0.0f);
    CHECK(rt0.ColorFormat == PixelFormat::RGBA8);
    CHECK(rt0.DepthFormat == PixelFormat::D24S8);
    CHECK(!rt0.DepthRenderTarget.IsValid());
    CHECK(rt0.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt0.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt0.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt0.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as relative-size render target, no depth buffer
    auto rt1 = TextureSetup::RelSizeRenderTarget(0.5f, 0.25f);
    rt1.ColorFormat = PixelFormat::R5G6B5;
    CHECK(!rt1.ShouldSetupFromFile());
    CHECK(!rt1.ShouldSetupFromImageFileData());
    CHECK(!rt1.ShouldSetupFromPixelData());
    CHECK(rt1.ShouldSetupAsRenderTarget());
    CHECK(rt1.IsRelSizeRenderTarget());
    CHECK(!rt1.HasSharedDepth());
    CHECK(!rt1.HasDepth());
    CHECK(rt1.Locator == Locator::NonShared());
    CHECK(rt1.Width == 0);
    CHECK(rt1.Height == 0);
    CHECK(rt1.RelWidth == 0.5f);
    CHECK(rt1.RelHeight == 0.25f);
    CHECK(rt1.ColorFormat == PixelFormat::R5G6B5);
    CHECK(rt1.DepthFormat == PixelFormat::InvalidPixelFormat);
    CHECK(!rt1.DepthRenderTarget.IsValid());
    CHECK(rt1.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt1.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt1.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt1.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as relative-size render target, with depth buffer
    auto rt2 = TextureSetup::RelSizeRenderTarget(0.5f, 0.25f);
    rt2.ColorFormat = PixelFormat::RGBA4;
    rt2.DepthFormat = PixelFormat::D16;
    CHECK(!rt2.ShouldSetupFromFile());
    CHECK(!rt2.ShouldSetupFromImageFileData());
    CHECK(!rt2.ShouldSetupFromPixelData());
    CHECK(rt2.ShouldSetupAsRenderTarget());
    CHECK(rt2.IsRelSizeRenderTarget());
    CHECK(!rt2.HasSharedDepth());
    CHECK(rt2.HasDepth());
    CHECK(rt2.Locator == Locator::NonShared());
    CHECK(rt2.Width == 0);
    CHECK(rt2.Height == 0);
    CHECK(rt2.RelWidth == 0.5f);
    CHECK(rt2.RelHeight == 0.25f);
    CHECK(rt2.ColorFormat == PixelFormat::RGBA4);
    CHECK(rt2.DepthFormat == PixelFormat::D16);
    CHECK(!rt2.DepthRenderTarget.IsValid());
    CHECK(rt2.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt2.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt2.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt2.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as shared-depth render target
    auto rt3 = TextureSetup::SharedDepthRenderTarget(Id(1, 2, GfxResourceType::Texture));
    rt3.ColorFormat = PixelFormat::RGBA32F;
    CHECK(!rt3.ShouldSetupFromFile());
    CHECK(!rt3.ShouldSetupFromImageFileData());
    CHECK(!rt3.ShouldSetupFromPixelData());
    CHECK(rt3.ShouldSetupAsRenderTarget());
    CHECK(!rt3.IsRelSizeRenderTarget());
    CHECK(rt3.HasSharedDepth());
    CHECK(rt3.HasDepth());
    CHECK(rt3.Width == 0);
    CHECK(rt3.Height == 0);
    CHECK(rt3.RelWidth == 0.0f);
    CHECK(rt3.RelHeight == 0.0f);
    CHECK(rt3.ColorFormat == PixelFormat::RGBA32F);
    CHECK(rt3.DepthFormat == PixelFormat::InvalidPixelFormat);
    CHECK(rt3.DepthRenderTarget.SlotIndex == 2);
    CHECK(rt3.DepthRenderTarget.Type == GfxResourceType::Texture);
    CHECK(rt3.DepthRenderTarget.UniqueStamp == 1);
    CHECK(rt3.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt3.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt3.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt3.Sampler.MinFilter == TextureFilterMode::Nearest);
}

<commit_msg>Fixed Gfx TextureSetupTest<commit_after>//------------------------------------------------------------------------------
//  TextureSetupTest.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "UnitTest++/src/UnitTest++.h"
#include "Gfx/Setup/TextureSetup.h"

using namespace Oryol;

TEST(TextureSetupTest) {

    // setup as absolute-size render target, no depth buffer
    auto rt = TextureSetup::RenderTarget(320, 256);
    rt.Locator = Locator("absSize");
    rt.ColorFormat = PixelFormat::RGB8;
    CHECK(!rt.ShouldSetupFromFile());
    CHECK(!rt.ShouldSetupFromPixelData());
    CHECK(rt.ShouldSetupAsRenderTarget());
    CHECK(!rt.IsRelSizeRenderTarget());
    CHECK(!rt.HasSharedDepth());
    CHECK(!rt.HasDepth());
    CHECK(rt.Locator.Location() == "absSize");
    CHECK(rt.Width == 320);
    CHECK(rt.Height == 256);
    CHECK(rt.RelWidth == 0.0f);
    CHECK(rt.RelHeight == 0.0f);
    CHECK(rt.ColorFormat == PixelFormat::RGB8);
    CHECK(rt.DepthFormat == PixelFormat::InvalidPixelFormat);
    CHECK(!rt.DepthRenderTarget.IsValid());
    CHECK(rt.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as absolute-size render target, with depth buffer
    auto rt0 = TextureSetup::RenderTarget(320, 256);
    rt0.ColorFormat = PixelFormat::RGBA8;
    rt0.DepthFormat = PixelFormat::D24S8;
    CHECK(!rt0.ShouldSetupFromFile());
    CHECK(!rt0.ShouldSetupFromPixelData());
    CHECK(rt0.ShouldSetupAsRenderTarget());
    CHECK(!rt0.IsRelSizeRenderTarget());
    CHECK(!rt0.HasSharedDepth());
    CHECK(rt0.HasDepth());
    CHECK(rt0.Locator == Locator::NonShared());
    CHECK(rt0.Width == 320);
    CHECK(rt0.Height == 256);
    CHECK(rt0.RelWidth == 0.0f);
    CHECK(rt0.RelHeight == 0.0f);
    CHECK(rt0.ColorFormat == PixelFormat::RGBA8);
    CHECK(rt0.DepthFormat == PixelFormat::D24S8);
    CHECK(!rt0.DepthRenderTarget.IsValid());
    CHECK(rt0.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt0.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt0.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt0.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as relative-size render target, no depth buffer
    auto rt1 = TextureSetup::RelSizeRenderTarget(0.5f, 0.25f);
    rt1.ColorFormat = PixelFormat::R5G6B5;
    CHECK(!rt1.ShouldSetupFromFile());
    CHECK(!rt1.ShouldSetupFromPixelData());
    CHECK(rt1.ShouldSetupAsRenderTarget());
    CHECK(rt1.IsRelSizeRenderTarget());
    CHECK(!rt1.HasSharedDepth());
    CHECK(!rt1.HasDepth());
    CHECK(rt1.Locator == Locator::NonShared());
    CHECK(rt1.Width == 0);
    CHECK(rt1.Height == 0);
    CHECK(rt1.RelWidth == 0.5f);
    CHECK(rt1.RelHeight == 0.25f);
    CHECK(rt1.ColorFormat == PixelFormat::R5G6B5);
    CHECK(rt1.DepthFormat == PixelFormat::InvalidPixelFormat);
    CHECK(!rt1.DepthRenderTarget.IsValid());
    CHECK(rt1.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt1.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt1.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt1.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as relative-size render target, with depth buffer
    auto rt2 = TextureSetup::RelSizeRenderTarget(0.5f, 0.25f);
    rt2.ColorFormat = PixelFormat::RGBA4;
    rt2.DepthFormat = PixelFormat::D16;
    CHECK(!rt2.ShouldSetupFromFile());
    CHECK(!rt2.ShouldSetupFromPixelData());
    CHECK(rt2.ShouldSetupAsRenderTarget());
    CHECK(rt2.IsRelSizeRenderTarget());
    CHECK(!rt2.HasSharedDepth());
    CHECK(rt2.HasDepth());
    CHECK(rt2.Locator == Locator::NonShared());
    CHECK(rt2.Width == 0);
    CHECK(rt2.Height == 0);
    CHECK(rt2.RelWidth == 0.5f);
    CHECK(rt2.RelHeight == 0.25f);
    CHECK(rt2.ColorFormat == PixelFormat::RGBA4);
    CHECK(rt2.DepthFormat == PixelFormat::D16);
    CHECK(!rt2.DepthRenderTarget.IsValid());
    CHECK(rt2.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt2.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt2.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt2.Sampler.MinFilter == TextureFilterMode::Nearest);

    // setup as shared-depth render target
    auto rt3 = TextureSetup::SharedDepthRenderTarget(Id(1, 2, GfxResourceType::Texture));
    rt3.ColorFormat = PixelFormat::RGBA32F;
    CHECK(!rt3.ShouldSetupFromFile());
    CHECK(!rt3.ShouldSetupFromPixelData());
    CHECK(rt3.ShouldSetupAsRenderTarget());
    CHECK(!rt3.IsRelSizeRenderTarget());
    CHECK(rt3.HasSharedDepth());
    CHECK(rt3.HasDepth());
    CHECK(rt3.Width == 0);
    CHECK(rt3.Height == 0);
    CHECK(rt3.RelWidth == 0.0f);
    CHECK(rt3.RelHeight == 0.0f);
    CHECK(rt3.ColorFormat == PixelFormat::RGBA32F);
    CHECK(rt3.DepthFormat == PixelFormat::InvalidPixelFormat);
    CHECK(rt3.DepthRenderTarget.SlotIndex == 2);
    CHECK(rt3.DepthRenderTarget.Type == GfxResourceType::Texture);
    CHECK(rt3.DepthRenderTarget.UniqueStamp == 1);
    CHECK(rt3.Sampler.WrapU == TextureWrapMode::ClampToEdge);
    CHECK(rt3.Sampler.WrapV == TextureWrapMode::ClampToEdge);
    CHECK(rt3.Sampler.MagFilter == TextureFilterMode::Nearest);
    CHECK(rt3.Sampler.MinFilter == TextureFilterMode::Nearest);
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Marc Boris Duerner, Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "addrinfo.h"
#include "tcpsocketimpl.h"
#include "tcpserverimpl.h"
#include "cxxtools/tcpserver.h"
#include "cxxtools/tcpsocket.h"
#include "cxxtools/systemerror.h"
#include "cxxtools/ioerror.h"
#include "cxxtools/log.h"
#include "config.h"
#include <cerrno>
#include <cstring>
#include <cassert>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

log_define("cxxtools.net.tcp")

namespace {

    void formatIp(const sockaddr_storage& addr, std::string& str)
    {
#ifndef HAVE_INET_NTOP
        static cxxtools::Mutex monitor;
        cxxtools::MutexLock lock(monitor);

        const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(&addr);
        const char* p = inet_ntoa(sa->sin_addr);
        if (p)
            str = p;
        else
            str.clear();
#else
        const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(&addr);
        char strbuf[INET6_ADDRSTRLEN + 1];
        const char* p = inet_ntop(sa->sin_family, &sa->sin_addr, strbuf, sizeof(strbuf));
        str = (p == 0 ? "-" : strbuf);
#endif
    }
}

namespace cxxtools {

namespace net {

TcpSocketImpl::TcpSocketImpl(TcpSocket& socket)
: IODeviceImpl(socket)
, _socket(socket)
, _isConnected(false)
, _timeout(Selectable::WaitInfinite)
{
}

TcpSocketImpl::~TcpSocketImpl()
{
    assert(_pfd == 0);
}

void TcpSocketImpl::close()
{
    log_debug("close socket " << _fd);
    IODeviceImpl::close();
    _isConnected = false;
}

std::string TcpSocketImpl::getSockAddr() const
{
    return "";
}

void TcpSocketImpl::connect(const std::string& ipaddr, unsigned short int port)
{
    log_debug("connect to " << ipaddr << " port " << port);
    this->beginConnect(ipaddr, port);
    this->endConnect();
}

bool TcpSocketImpl::beginConnect(const std::string& ipaddr, unsigned short int port)
{
    log_debug("begin connect to " << ipaddr << " port " << port);

    AddrInfo ai(ipaddr, port);

    log_debug("checking address information");
    for (AddrInfo::const_iterator it = ai.begin(); it != ai.end(); ++it)
    {
        int fd = ::socket(it->ai_family, SOCK_STREAM, 0);
        if (fd < 0)
            continue;

        IODeviceImpl::open(fd, true);

        std::memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);

        log_debug("created socket " << _fd << " max: " << FD_SETSIZE);

        if( ::connect(this->fd(), it->ai_addr, it->ai_addrlen) == 0 )
        {
            _isConnected = true;
            log_debug("connected successfuly");
            return true;
        }

        if(errno != EINPROGRESS)
        {
            close();
            throw SystemError("connect failed");
        }

        log_debug("connect in progress");
        memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);
        return false;
    }

    throw SystemError("invalid address information");
}

void TcpSocketImpl::endConnect()
{
    log_debug("ending connect");

    if(_pfd && ! _socket.wbuf())
    {
        _pfd->events &= ~POLLOUT;
    }

    if( ! _isConnected )
    {
        try
        {
            pollfd pfd;
            pfd.fd = this->fd();
            pfd.revents = 0;
            pfd.events = POLLOUT;

            bool ret = this->wait(_timeout, pfd);
            if(false == ret)
            {
                throw IOTimeout();
            }

            int sockerr;
            socklen_t optlen = sizeof(sockerr);
            if( ::getsockopt(this->fd(), SOL_SOCKET, SO_ERROR, &sockerr, &optlen) != 0 )
            {
                throw SystemError("getsockopt");
            }

            if(sockerr != 0)
            {
                throw SystemError("connect");
            }

            _isConnected = true;
        }
        catch(...)
        {
            close();
            throw;
        }
    }
}

void TcpSocketImpl::accept(TcpServer& server)
{
    socklen_t peeraddr_len = sizeof(_peeraddr);

    log_debug( "accept " << server.impl().fd() );
    _fd = ::accept(server.impl().fd(), reinterpret_cast <struct sockaddr*>(&_peeraddr), &peeraddr_len);
    if( _fd < 0 )
      throw SystemError("accept");

    //TODO ECONNABORTED EINTR EPERM

    _isConnected = true;
    log_debug( "accepted " << server.impl().fd() << " => " << _fd );
}

/*
size_t TcpSocketImpl::beginRead(char* buffer, size_t n, bool& eof)
{
    return 0;
}

size_t TcpSocketImpl::endRead(bool& eof)
{
    return 0;
}

size_t TcpSocketImpl::read(char* buffer, size_t count, bool& eof)
{
    return 0;
}

size_t TcpSocketImpl::beginWrite(const char* buffer, size_t n)
{
    return 0;
}

size_t TcpSocketImpl::endWrite()
{
    return 0;
}

size_t TcpSocketImpl::write(const char* buffer, size_t count)
{
    return 0;
}
*/

void TcpSocketImpl::initWait(pollfd& pfd)
{
    IODeviceImpl::initWait(pfd);

    if( ! _isConnected )
    {
        log_debug("not connected, setting POLLOUT ");
        pfd.events = POLLOUT;
    }
}

std::size_t TcpSocketImpl::initializePoll(pollfd* pfd, std::size_t pollSize)
{
    assert(pfd != 0);
    assert(pollSize >= 1);

    log_debug("TcpSocketImpl::initializePoll " << pollSize);

    std::size_t ret = IODeviceImpl::initializePoll(pfd, pollSize);
    assert(ret == 1);

    if( ! _isConnected )
    {
        log_debug("not connected, setting POLLOUT ");
        pfd->events = POLLOUT;
    }

    return ret;
}

bool TcpSocketImpl::checkPollEvent()
{
    assert(_pfd != 0);

    log_debug("checkPollEvent " << _pfd->revents);

    if( _pfd->revents & POLLOUT )
    {
        if( ! _isConnected )
        {
            _socket.connected.send(_socket);
            return true;
        }
    }

    return IODeviceImpl::checkPollEvent();
}

} // namespace net

} // namespace cxxtools
<commit_msg>implemented getSockAddr<commit_after>/*
 * Copyright (C) 2009 Marc Boris Duerner, Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "addrinfo.h"
#include "tcpsocketimpl.h"
#include "tcpserverimpl.h"
#include "cxxtools/tcpserver.h"
#include "cxxtools/tcpsocket.h"
#include "cxxtools/systemerror.h"
#include "cxxtools/ioerror.h"
#include "cxxtools/log.h"
#include "config.h"
#include <cerrno>
#include <cstring>
#include <cassert>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

log_define("cxxtools.net.tcp")

namespace {

    void formatIp(const sockaddr_storage& addr, std::string& str)
    {
#ifndef HAVE_INET_NTOP
        static cxxtools::Mutex monitor;
        cxxtools::MutexLock lock(monitor);

        const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(&addr);
        const char* p = inet_ntoa(sa->sin_addr);
        if (p)
            str = p;
        else
            str.clear();
#else
        const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(&addr);
        char strbuf[INET6_ADDRSTRLEN + 1];
        const char* p = inet_ntop(sa->sin_family, &sa->sin_addr, strbuf, sizeof(strbuf));
        str = (p == 0 ? "-" : strbuf);
#endif
    }
}

namespace cxxtools {

namespace net {

TcpSocketImpl::TcpSocketImpl(TcpSocket& socket)
: IODeviceImpl(socket)
, _socket(socket)
, _isConnected(false)
, _timeout(Selectable::WaitInfinite)
{
}

TcpSocketImpl::~TcpSocketImpl()
{
    assert(_pfd == 0);
}

void TcpSocketImpl::close()
{
    log_debug("close socket " << _fd);
    IODeviceImpl::close();
    _isConnected = false;
}

std::string TcpSocketImpl::getSockAddr() const
{
    struct sockaddr_storage addr;

    socklen_t slen = sizeof(addr);
    if (::getsockname(fd(), reinterpret_cast<struct sockaddr*>(&addr), &slen) < 0)
        throw SystemError("getsockname");

    std::string ret;
    formatIp(addr, ret);
    return ret;
}

void TcpSocketImpl::connect(const std::string& ipaddr, unsigned short int port)
{
    log_debug("connect to " << ipaddr << " port " << port);
    this->beginConnect(ipaddr, port);
    this->endConnect();
}

bool TcpSocketImpl::beginConnect(const std::string& ipaddr, unsigned short int port)
{
    log_debug("begin connect to " << ipaddr << " port " << port);

    AddrInfo ai(ipaddr, port);

    log_debug("checking address information");
    for (AddrInfo::const_iterator it = ai.begin(); it != ai.end(); ++it)
    {
        int fd = ::socket(it->ai_family, SOCK_STREAM, 0);
        if (fd < 0)
            continue;

        IODeviceImpl::open(fd, true);

        std::memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);

        log_debug("created socket " << _fd << " max: " << FD_SETSIZE);

        if( ::connect(this->fd(), it->ai_addr, it->ai_addrlen) == 0 )
        {
            _isConnected = true;
            log_debug("connected successfuly");
            return true;
        }

        if(errno != EINPROGRESS)
        {
            close();
            throw SystemError("connect failed");
        }

        log_debug("connect in progress");
        memmove(&_peeraddr, it->ai_addr, it->ai_addrlen);
        return false;
    }

    throw SystemError("invalid address information");
}

void TcpSocketImpl::endConnect()
{
    log_debug("ending connect");

    if(_pfd && ! _socket.wbuf())
    {
        _pfd->events &= ~POLLOUT;
    }

    if( ! _isConnected )
    {
        try
        {
            pollfd pfd;
            pfd.fd = this->fd();
            pfd.revents = 0;
            pfd.events = POLLOUT;

            bool ret = this->wait(_timeout, pfd);
            if(false == ret)
            {
                throw IOTimeout();
            }

            int sockerr;
            socklen_t optlen = sizeof(sockerr);
            if( ::getsockopt(this->fd(), SOL_SOCKET, SO_ERROR, &sockerr, &optlen) != 0 )
            {
                throw SystemError("getsockopt");
            }

            if(sockerr != 0)
            {
                throw SystemError("connect");
            }

            _isConnected = true;
        }
        catch(...)
        {
            close();
            throw;
        }
    }
}

void TcpSocketImpl::accept(TcpServer& server)
{
    socklen_t peeraddr_len = sizeof(_peeraddr);

    log_debug( "accept " << server.impl().fd() );
    _fd = ::accept(server.impl().fd(), reinterpret_cast <struct sockaddr*>(&_peeraddr), &peeraddr_len);
    if( _fd < 0 )
      throw SystemError("accept");

    //TODO ECONNABORTED EINTR EPERM

    _isConnected = true;
    log_debug( "accepted " << server.impl().fd() << " => " << _fd );
}

/*
size_t TcpSocketImpl::beginRead(char* buffer, size_t n, bool& eof)
{
    return 0;
}

size_t TcpSocketImpl::endRead(bool& eof)
{
    return 0;
}

size_t TcpSocketImpl::read(char* buffer, size_t count, bool& eof)
{
    return 0;
}

size_t TcpSocketImpl::beginWrite(const char* buffer, size_t n)
{
    return 0;
}

size_t TcpSocketImpl::endWrite()
{
    return 0;
}

size_t TcpSocketImpl::write(const char* buffer, size_t count)
{
    return 0;
}
*/

void TcpSocketImpl::initWait(pollfd& pfd)
{
    IODeviceImpl::initWait(pfd);

    if( ! _isConnected )
    {
        log_debug("not connected, setting POLLOUT ");
        pfd.events = POLLOUT;
    }
}

std::size_t TcpSocketImpl::initializePoll(pollfd* pfd, std::size_t pollSize)
{
    assert(pfd != 0);
    assert(pollSize >= 1);

    log_debug("TcpSocketImpl::initializePoll " << pollSize);

    std::size_t ret = IODeviceImpl::initializePoll(pfd, pollSize);
    assert(ret == 1);

    if( ! _isConnected )
    {
        log_debug("not connected, setting POLLOUT ");
        pfd->events = POLLOUT;
    }

    return ret;
}

bool TcpSocketImpl::checkPollEvent()
{
    assert(_pfd != 0);

    log_debug("checkPollEvent " << _pfd->revents);

    if( _pfd->revents & POLLOUT )
    {
        if( ! _isConnected )
        {
            _socket.connected.send(_socket);
            return true;
        }
    }

    return IODeviceImpl::checkPollEvent();
}

} // namespace net

} // namespace cxxtools
<|endoftext|>