<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "subscriber_ws.h"

#include <vector>

#include "atomic.h"
#include "logging.h"
#include "messages.h"
#include "url.h"
#include "util/pointer.h"
#include "util/string.h"

namespace {

const LogFacilities& kLogInfo = DefaultLogging::info;
const LogFacilities& kLogError = DefaultLogging::error;

const unsigned char kPingToken = 123;
const int kPingInterval = 50000000;  // 50 sec

const int kWsLogLevel = LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_USER;

void LogWs(int level, const char* line) {
  int dest = kLogDebug;
  if (level & LLL_ERR) {
    dest = kLogError;
  }

  LogCvmfs(kLogCvmfs, dest, line);
}

struct Settings {
  std::string protocol;
  std::string host;
  std::string path;
  int port;
  std::string topic;
};

struct PerSessionStorage {
  std::string* message;
  bool send_ping;
};

struct ContextData {
  struct lws_context* context;
  struct lws_vhost* vhost;
  struct lws* client_wsi;

  notify::SubscriberWS* subscriber;

  bool* should_stop;

  Settings settings;
};

int ConnectClient(ContextData* cd) {
  struct lws_client_connect_info i;
  memset(&i, 0, sizeof(i));

  const std::string host =
      cd->settings.host + ":" + StringifyUint(cd->settings.port);

  i.context = cd->context;
  i.port = cd->settings.port;
  i.address = cd->settings.host.c_str();
  i.path = cd->settings.path.c_str();
  i.host = host.c_str();
  i.origin = host.c_str();
  i.ssl_connection = 0;
  i.vhost = cd->vhost;
  i.pwsi = &(cd->client_wsi);

  return !lws_client_connect_via_info(&i);
}

void ScheduleCallback(struct lws* wsi, int reason, int secs) {
  lws_timed_callback_vh_protocol(lws_get_vhost(wsi), lws_get_protocol(wsi),
                                 reason, secs);
}

}  // namespace

namespace notify {

SubscriberWS::SubscriberWS(const std::string& server_url)
    : server_url_(server_url) {}

SubscriberWS::~SubscriberWS() {}

bool SubscriberWS::Subscribe(const std::string& topic) {
  lws_set_log_level(kWsLogLevel, &LogWs);

  UniquePtr<Url> url(Url::Parse(server_url_));
  if (!url.IsValid()) {
    LogCvmfs(kLogCvmfs, kLogError,
             "SubscriberWS - could not parse notification server url",
             server_url_.c_str());
    return true;
  }

  Settings settings;
  settings.protocol = url->protocol();
  settings.host = url->host();
  settings.path = url->path();
  settings.port = url->port();
  settings.topic = topic;

  // C-style structs needed to initialize the libwebsockets session
  const struct lws_protocols protocols[] = {
      {"cvmfs", SubscriberWS::WSCallback, sizeof(PerSessionStorage), 1024, 0,
       NULL, 0},
      {NULL, NULL, 0, 0}};

  bool should_stop = false;

  const struct lws_protocol_vhost_options pvo_should_stop = {
      NULL, NULL, "should_stop", reinterpret_cast<char*>(&should_stop)};
  const struct lws_protocol_vhost_options pvo_subscriber = {
      &pvo_should_stop, NULL, "subscriber", reinterpret_cast<char*>(this)};
  const struct lws_protocol_vhost_options pvo_settings = {
      &pvo_subscriber, NULL, "settings", reinterpret_cast<char*>(&settings)};
  const struct lws_protocol_vhost_options pvo = {NULL, &pvo_settings, "cvmfs",
                                                 ""};

  struct lws_context_creation_info info;
  memset(&info, 0, sizeof info);
  info.port = CONTEXT_PORT_NO_LISTEN;
  info.protocols = protocols;
  info.pvo = &pvo;
  info.pt_serv_buf_size = 32 * 1024;
  info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;

  struct lws_context* context = lws_create_context(&info);
  if (!context) {
    LogCvmfs(kLogCvmfs, kLogError,
             "SubscriberWS - could not create libwebsocket context.");
    return false;
  }

  int err = 0;
  while (!err && !should_stop) {
    err = lws_service(context, 1000);
  }

  bool ret = true;
  if (err) {
    LogCvmfs(kLogCvmfs, kLogError,
             "SubscriberWS - event loop finished with error: %d", err);
    ret = false;
  }

  lws_context_destroy(context);

  return ret;
}

int SubscriberWS::WSCallback(struct lws* wsi, enum lws_callback_reasons reason,
                             void* user, void* in, size_t len) {
  PerSessionStorage* pss = static_cast<PerSessionStorage*>(user);
  ContextData* cd = static_cast<ContextData*>(
      lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)));

  switch (reason) {
    case LWS_CALLBACK_PROTOCOL_INIT: {
      cd = static_cast<ContextData*>(lws_protocol_vh_priv_zalloc(
          lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(ContextData)));
      if (!cd) return -1;

      cd->context = lws_get_context(wsi);
      cd->vhost = lws_get_vhost(wsi);

      // Note: libwebsockets is a C library. Passing parameters into the
      //       connection context is done with a link list storing generic
      //       pointers (void*) to the parameter values. C-style casts back
      //       to the original value types are needed. See:
      //
      //   https://libwebsockets.org/git/libwebsockets/tree/minimal-examples
      //
      //       Using C++-style casts would not increase readability in this
      //       case, since each C-style cast would need to be replaced with
      //       a const_cast, followed by a reinterpret_cast.
      cd->subscriber =
          (SubscriberWS*)(lws_pvo_search(  // NOLINT(readability/casting)
                              (const struct lws_protocol_vhost_options*)in,
                              "subscriber")
                              ->value);

      cd->should_stop =
          (bool*)(lws_pvo_search(  // NOLINT(readability/casting)
            (const struct lws_protocol_vhost_options*) in, "should_stop")
                      ->value);

      cd->settings =
          *((Settings*)lws_pvo_search(  // NOLINT(readability/casting)
                (const struct lws_protocol_vhost_options*)in, "settings")
                ->value);
      if (ConnectClient(cd)) {
        ScheduleCallback(wsi, LWS_CALLBACK_USER, 1);
      }
      break;
    }
    case LWS_CALLBACK_CLIENT_ESTABLISHED: {
      pss->message = new std::string();
      pss->send_ping = false;
      lws_callback_on_writable(wsi);
      break;
    }
    case LWS_CALLBACK_CLIENT_WRITEABLE: {
      // Send a Websocket PING
      if (pss->send_ping) {
        unsigned char token = kPingToken;
        lws_write(wsi, &token, 1, LWS_WRITE_PING);
        lws_set_timer_usecs(wsi, kPingInterval);
        break;
      }

      // Send initial subscription request
      std::string buf(LWS_PRE, '0');
      buf += "{\"version\":" + StringifyInt(notify::msg::kProtocolVersion) +
             ",\"repository\":\"" + cd->settings.topic + "\"}";
      int body_size = buf.size() - LWS_PRE;
      int bytes_sent =
          lws_write(wsi, reinterpret_cast<unsigned char*>(&buf[LWS_PRE]),
                    body_size, LWS_WRITE_BINARY);
      if (bytes_sent != body_size) {
        LogCvmfs(kLogCvmfs, kLogError, "Could not send subscription request.");
        return -1;
      }
      lws_set_timer_usecs(wsi, kPingInterval);
      pss->send_ping = true;
      break;
    }
    case LWS_CALLBACK_CLIENT_RECEIVE: {
      // Only handling binary frames
      if (!lws_frame_is_binary(wsi)) {
        break;
      }

      if (lws_is_first_fragment(wsi)) {
        pss->message->resize(0);
      }

      size_t current_size = pss->message->size();
      pss->message->resize(current_size + len);
      memcpy(&(*pss->message)[current_size], in, len);

      if (lws_is_final_fragment(wsi)) {
        if (!cd->subscriber->Consume(cd->settings.topic, *(pss->message))) {
          *(cd->should_stop) = true;
          delete pss->message;
          pss->message = NULL;
          return 0;
        }
      }

      break;
    }
    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
      ScheduleCallback(wsi, LWS_CALLBACK_USER, 1);
      if (pss->message) {
        delete pss->message;
        pss->message = NULL;
      }
      lws_cancel_service(lws_get_context(wsi));
      break;
    }
    case LWS_CALLBACK_CLIENT_CLOSED: {
      if (pss->message) {
        delete pss->message;
        pss->message = NULL;
      }
      lws_cancel_service(lws_get_context(wsi));
      break;
    }
    case LWS_CALLBACK_TIMER: {
      lws_callback_on_writable(wsi);
      break;
    }
    case LWS_CALLBACK_USER: {
      if (ConnectClient(cd)) {
        ScheduleCallback(wsi, LWS_CALLBACK_USER, 1);
      }
      break;
    }
    default:
      // LogCvmfs(kLogCvmfs, kLogDebug,
      //          "Unhandled websocket event: %d", reason);
      break;
  }

  return 0;
}

}  // namespace notify
<commit_msg>Renaming private data types in subscriber_ws.cc<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "subscriber_ws.h"

#include <vector>

#include "atomic.h"
#include "logging.h"
#include "messages.h"
#include "url.h"
#include "util/pointer.h"
#include "util/string.h"

namespace {

const LogFacilities& kLogInfo = DefaultLogging::info;
const LogFacilities& kLogError = DefaultLogging::error;

const unsigned char kPingToken = 123;
const int kPingInterval = 50000000;  // 50 sec

const int kWsLogLevel = LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_USER;

void LogWs(int level, const char* line) {
  int dest = kLogDebug;
  if (level & LLL_ERR) {
    dest = kLogError;
  }

  LogCvmfs(kLogCvmfs, dest, line);
}

struct Settings {
  std::string protocol;
  std::string host;
  std::string path;
  int port;
  std::string topic;
};

struct SessionState {
  std::string* message;
  bool send_ping;
};

struct Context {
  struct lws_context* context;
  struct lws_vhost* vhost;
  struct lws* client_wsi;

  notify::SubscriberWS* subscriber;

  bool* should_stop;

  Settings settings;
};

int ConnectClient(Context* cd) {
  struct lws_client_connect_info i;
  memset(&i, 0, sizeof(i));

  const std::string host =
      cd->settings.host + ":" + StringifyUint(cd->settings.port);

  i.context = cd->context;
  i.port = cd->settings.port;
  i.address = cd->settings.host.c_str();
  i.path = cd->settings.path.c_str();
  i.host = host.c_str();
  i.origin = host.c_str();
  i.ssl_connection = 0;
  i.vhost = cd->vhost;
  i.pwsi = &(cd->client_wsi);

  return !lws_client_connect_via_info(&i);
}

void ScheduleCallback(struct lws* wsi, int reason, int secs) {
  lws_timed_callback_vh_protocol(lws_get_vhost(wsi), lws_get_protocol(wsi),
                                 reason, secs);
}

}  // namespace

namespace notify {

SubscriberWS::SubscriberWS(const std::string& server_url)
    : server_url_(server_url) {}

SubscriberWS::~SubscriberWS() {}

bool SubscriberWS::Subscribe(const std::string& topic) {
  lws_set_log_level(kWsLogLevel, &LogWs);

  UniquePtr<Url> url(Url::Parse(server_url_));
  if (!url.IsValid()) {
    LogCvmfs(kLogCvmfs, kLogError,
             "SubscriberWS - could not parse notification server url",
             server_url_.c_str());
    return true;
  }

  Settings settings;
  settings.protocol = url->protocol();
  settings.host = url->host();
  settings.path = url->path();
  settings.port = url->port();
  settings.topic = topic;

  // C-style structs needed to initialize the libwebsockets session
  const struct lws_protocols protocols[] = {
      {"cvmfs", SubscriberWS::WSCallback, sizeof(SessionState), 1024, 0, NULL,
       0},
      {NULL, NULL, 0, 0}};

  bool should_stop = false;

  const struct lws_protocol_vhost_options pvo_should_stop = {
      NULL, NULL, "should_stop", reinterpret_cast<char*>(&should_stop)};
  const struct lws_protocol_vhost_options pvo_subscriber = {
      &pvo_should_stop, NULL, "subscriber", reinterpret_cast<char*>(this)};
  const struct lws_protocol_vhost_options pvo_settings = {
      &pvo_subscriber, NULL, "settings", reinterpret_cast<char*>(&settings)};
  const struct lws_protocol_vhost_options pvo = {NULL, &pvo_settings, "cvmfs",
                                                 ""};

  struct lws_context_creation_info info;
  memset(&info, 0, sizeof info);
  info.port = CONTEXT_PORT_NO_LISTEN;
  info.protocols = protocols;
  info.pvo = &pvo;
  info.pt_serv_buf_size = 32 * 1024;
  info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;

  struct lws_context* context = lws_create_context(&info);
  if (!context) {
    LogCvmfs(kLogCvmfs, kLogError,
             "SubscriberWS - could not create libwebsocket context.");
    return false;
  }

  int err = 0;
  while (!err && !should_stop) {
    err = lws_service(context, 1000);
  }

  bool ret = true;
  if (err) {
    LogCvmfs(kLogCvmfs, kLogError,
             "SubscriberWS - event loop finished with error: %d", err);
    ret = false;
  }

  lws_context_destroy(context);

  return ret;
}

int SubscriberWS::WSCallback(struct lws* wsi, enum lws_callback_reasons reason,
                             void* user, void* in, size_t len) {
  SessionState* pss = static_cast<SessionState*>(user);
  Context* cd = static_cast<Context*>(
      lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)));

  switch (reason) {
    case LWS_CALLBACK_PROTOCOL_INIT: {
      cd = static_cast<Context*>(lws_protocol_vh_priv_zalloc(
          lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(Context)));
      if (!cd) return -1;

      cd->context = lws_get_context(wsi);
      cd->vhost = lws_get_vhost(wsi);

      // Note: libwebsockets is a C library. Passing parameters into the
      //       connection context is done with a link list storing generic
      //       pointers (void*) to the parameter values. C-style casts back
      //       to the original value types are needed. See:
      //
      //   https://libwebsockets.org/git/libwebsockets/tree/minimal-examples
      //
      //       Using C++-style casts would not increase readability in this
      //       case, since each C-style cast would need to be replaced with
      //       a const_cast, followed by a reinterpret_cast.
      cd->subscriber =
          (SubscriberWS*)(lws_pvo_search(  // NOLINT(readability/casting)
                              (const struct lws_protocol_vhost_options*)in,
                              "subscriber")
                              ->value);

      cd->should_stop =
          (bool*)(lws_pvo_search(  // NOLINT(readability/casting)
                      (const struct lws_protocol_vhost_options*)in,
                      "should_stop")
                      ->value);

      cd->settings =
          *((Settings*)lws_pvo_search(  // NOLINT(readability/casting)
                (const struct lws_protocol_vhost_options*)in, "settings")
                ->value);
      if (ConnectClient(cd)) {
        ScheduleCallback(wsi, LWS_CALLBACK_USER, 1);
      }
      break;
    }
    case LWS_CALLBACK_CLIENT_ESTABLISHED: {
      pss->message = new std::string();
      pss->send_ping = false;
      lws_callback_on_writable(wsi);
      break;
    }
    case LWS_CALLBACK_CLIENT_WRITEABLE: {
      // Send a Websocket PING
      if (pss->send_ping) {
        unsigned char token = kPingToken;
        lws_write(wsi, &token, 1, LWS_WRITE_PING);
        lws_set_timer_usecs(wsi, kPingInterval);
        break;
      }

      // Send initial subscription request
      std::string buf(LWS_PRE, '0');
      buf += "{\"version\":" + StringifyInt(notify::msg::kProtocolVersion) +
             ",\"repository\":\"" + cd->settings.topic + "\"}";
      int body_size = buf.size() - LWS_PRE;
      int bytes_sent =
          lws_write(wsi, reinterpret_cast<unsigned char*>(&buf[LWS_PRE]),
                    body_size, LWS_WRITE_BINARY);
      if (bytes_sent != body_size) {
        LogCvmfs(kLogCvmfs, kLogError, "Could not send subscription request.");
        return -1;
      }
      lws_set_timer_usecs(wsi, kPingInterval);
      pss->send_ping = true;
      break;
    }
    case LWS_CALLBACK_CLIENT_RECEIVE: {
      // Only handling binary frames
      if (!lws_frame_is_binary(wsi)) {
        break;
      }

      if (lws_is_first_fragment(wsi)) {
        pss->message->resize(0);
      }

      size_t current_size = pss->message->size();
      pss->message->resize(current_size + len);
      memcpy(&(*pss->message)[current_size], in, len);

      if (lws_is_final_fragment(wsi)) {
        if (!cd->subscriber->Consume(cd->settings.topic, *(pss->message))) {
          *(cd->should_stop) = true;
          delete pss->message;
          pss->message = NULL;
          return 0;
        }
      }

      break;
    }
    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
      ScheduleCallback(wsi, LWS_CALLBACK_USER, 1);
      if (pss->message) {
        delete pss->message;
        pss->message = NULL;
      }
      lws_cancel_service(lws_get_context(wsi));
      break;
    }
    case LWS_CALLBACK_CLIENT_CLOSED: {
      if (pss->message) {
        delete pss->message;
        pss->message = NULL;
      }
      lws_cancel_service(lws_get_context(wsi));
      break;
    }
    case LWS_CALLBACK_TIMER: {
      lws_callback_on_writable(wsi);
      break;
    }
    case LWS_CALLBACK_USER: {
      if (ConnectClient(cd)) {
        ScheduleCallback(wsi, LWS_CALLBACK_USER, 1);
      }
      break;
    }
    default:
      // LogCvmfs(kLogCvmfs, kLogDebug,
      //          "Unhandled websocket event: %d", reason);
      break;
  }

  return 0;
}

}  // namespace notify
<|endoftext|>


<commit_before>/***********************************************************************
 * Software License Agreement (BSD License)
 *
 * Copyright 2008-2009  Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
 * Copyright 2008-2009  David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
 *
 * THE BSD LICENSE
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *************************************************************************/

#ifndef FLANN_HPP_
#define FLANN_HPP_

#include <vector>
#include <string>
#include <cassert>
#include <cstdio>

#include "flann/flann.h"
#include "flann/general.h"
#include "flann/util/matrix.h"
#include "flann/util/result_set.h"
#include "flann/nn/index_testing.h"
#include "flann/util/object_factory.h"
#include "flann/util/saving.h"
#include "flann/util/pair_iterator.hpp"

#include "flann/algorithms/all_indices.h"

namespace flann
{

/**
Sets the log level used for all flann functions

Params:
    level = verbosity level
*/
FLANN_EXPORT void log_verbosity(int level);

struct SavedIndexParams : public IndexParams {
    SavedIndexParams(std::string filename_) : IndexParams(FLANN_INDEX_SAVED), filename(filename_) {}

    std::string filename;  // filename of the stored index

    void fromParameters(const FLANNParameters& p) {
        assert(p.algorithm == algorithm);
        //filename = p.filename;
    };

    void toParameters(FLANNParameters& p) const {
        p.algorithm = algorithm;
        //p.filename = filename.c_str();
    };

    void print() const {
        logger.info("Index type: %d\n", (int)algorithm);
        logger.info("Filename: %s\n", filename.c_str());
    }
};

template<typename Distance>
class Index
{
    typedef typename Distance::ElementType ElementType;
    typedef typename Distance::ResultType DistanceType;
    Distance distance;
    NNIndex<Distance>* nnIndex;
    bool built;

public:
    Index(const Matrix<ElementType>& features, const IndexParams& params, Distance d = Distance() );

    ~Index();

    void buildIndex();

    void knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& params);

    int radiusSearch(const Matrix<ElementType>& query, Matrix<int>& indices, Matrix<DistanceType>& dists, float radius, const SearchParams& params);

    void save(std::string filename);

    int veclen() const;

    int size() const;

    NNIndex<Distance>* getIndex() {
        return nnIndex;
    }

    const IndexParams* getIndexParameters() {
        return nnIndex->getParameters();
    }
};

template<typename Distance>
NNIndex<Distance>* load_saved_index(const Matrix<typename Distance::ElementType>& dataset, const std::string& filename, Distance distance)
{
    typedef typename Distance::ElementType ElementType;

    FILE* fin = fopen(filename.c_str(), "rb");
    if (fin == NULL) {
        return NULL;
    }
    IndexHeader header = load_header(fin);
    if (header.data_type != Datatype<ElementType>::type()) {
        throw FLANNException("Datatype of saved index is different than of the one to be created.");
    }
    if (size_t(header.rows) != dataset.rows || size_t(header.cols) != dataset.cols) {
        throw FLANNException("The index saved belongs to a different dataset");
    }

    IndexParams* params = ParamsFactory::instance().create(header.index_type);
    NNIndex<Distance>* nnIndex = create_index_by_type<Distance>(dataset, *params, distance);
    nnIndex->loadIndex(fin);
    fclose(fin);

    return nnIndex;
}

template<typename Distance>
Index<Distance>::Index(const Matrix<ElementType>& dataset, const IndexParams& params, Distance d ) : distance (d)
{
    flann_algorithm_t index_type = params.getIndexType();
    built = false;

    if (index_type == FLANN_INDEX_SAVED) {
        nnIndex = load_saved_index<Distance>(dataset, ((const SavedIndexParams&)params).filename, distance);
        built = true;
    }
    else {
        nnIndex = create_index_by_type<Distance>(dataset, params, distance);
    }
}

template<typename Distance>
Index<Distance>::~Index()
{
    delete nnIndex;
}

template<typename Distance>
void Index<Distance>::buildIndex()
{
    if (!built) {
        nnIndex->buildIndex();
        built = true;
    }
}

template<typename Distance>
void Index<Distance>::knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& searchParams)
{
    if (!built) {
        throw FLANNException("You must build the index before searching.");
    }
    assert(queries.cols == nnIndex->veclen());
    assert(indices.rows >= queries.rows);
    assert(dists.rows >= queries.rows);
    assert(int(indices.cols) >= knn);
    assert(int(dists.cols) >= knn);

    KNNResultSet<DistanceType> resultSet(knn);
    for (size_t i = 0; i < queries.rows; i++) {
        resultSet.init(indices[i], dists[i]);
        nnIndex->findNeighbors(resultSet, queries[i], searchParams);
    }
}

template<typename Distance>
int Index<Distance>::radiusSearch(const Matrix<ElementType>& query, Matrix<int>& indices, Matrix<DistanceType>& dists, float radius, const SearchParams& searchParams)
{
    if (!built) {
        throw FLANNException("You must build the index before searching.");
    }
    if (query.rows != 1) {
        fprintf(stderr, "I can only search one feature at a time for range search\n");
        return -1;
    }
    assert(query.cols == nnIndex->veclen());
    assert(indices.cols == dists.cols);

    int n = 0;
    int* indices_ptr = NULL;
    DistanceType* dists_ptr = NULL;
    if (indices.cols > 0) {
        n = indices.cols;
        indices_ptr = indices[0];
        dists_ptr = dists[0];
    }
    RadiusResultSet<DistanceType> result_set(radius, indices_ptr, dists_ptr, n);
    nnIndex->findNeighbors(result_set, query[0], searchParams);
    size_t cnt = result_set.size();
    if (n > 0 && searchParams.sorted) {
        std::sort(make_pair_iterator(dists_ptr, indices_ptr),
                  make_pair_iterator(dists_ptr + cnt, indices_ptr + cnt),
                  pair_iterator_compare<DistanceType*, int*>());
    }

    return cnt;
}

template<typename Distance>
void Index<Distance>::save(std::string filename)
{
    FILE* fout = fopen(filename.c_str(), "wb");
    if (fout == NULL) {
        throw FLANNException("Cannot open file");
    }
    save_header(fout, *nnIndex);
    nnIndex->saveIndex(fout);
    fclose(fout);
}

template<typename Distance>
int Index<Distance>::size() const
{
    return nnIndex->size();
}

template<typename Distance>
int Index<Distance>::veclen() const
{
    return nnIndex->veclen();
}

template <typename Distance>
int hierarchicalClustering(const Matrix<typename Distance::ElementType>& features, Matrix<typename Distance::ResultType>& centers,
                           const KMeansIndexParams& params, Distance d = Distance())
{
    KMeansIndex<Distance> kmeans(features, params, d);
    kmeans.buildIndex();

    int clusterNum = kmeans.getClusterCenters(centers);
    return clusterNum;
}

}
#endif /* FLANN_HPP_ */
<commit_msg>Bug fix. (thanks Frédéric Devernay)<commit_after>/***********************************************************************
 * Software License Agreement (BSD License)
 *
 * Copyright 2008-2009  Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
 * Copyright 2008-2009  David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
 *
 * THE BSD LICENSE
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *************************************************************************/

#ifndef FLANN_HPP_
#define FLANN_HPP_

#include <vector>
#include <string>
#include <cassert>
#include <cstdio>

#include "flann/flann.h"
#include "flann/general.h"
#include "flann/util/matrix.h"
#include "flann/util/result_set.h"
#include "flann/nn/index_testing.h"
#include "flann/util/object_factory.h"
#include "flann/util/saving.h"
#include "flann/util/pair_iterator.hpp"

#include "flann/algorithms/all_indices.h"

namespace flann
{

/**
Sets the log level used for all flann functions

Params:
    level = verbosity level
*/
FLANN_EXPORT void log_verbosity(int level);

struct SavedIndexParams : public IndexParams {
    SavedIndexParams(std::string filename_) : IndexParams(FLANN_INDEX_SAVED), filename(filename_) {}

    std::string filename;  // filename of the stored index

    void fromParameters(const FLANNParameters& p) {
        assert(p.algorithm == algorithm);
        //filename = p.filename;
    };

    void toParameters(FLANNParameters& p) const {
        p.algorithm = algorithm;
        //p.filename = filename.c_str();
    };

    void print() const {
        logger.info("Index type: %d\n", (int)algorithm);
        logger.info("Filename: %s\n", filename.c_str());
    }
};

template<typename Distance>
class Index
{
    typedef typename Distance::ElementType ElementType;
    typedef typename Distance::ResultType DistanceType;
    Distance distance;
    NNIndex<Distance>* nnIndex;
    bool built;

public:
    Index(const Matrix<ElementType>& features, const IndexParams& params, Distance d = Distance() );

    ~Index();

    void buildIndex();

    void knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& params);

    int radiusSearch(const Matrix<ElementType>& query, Matrix<int>& indices, Matrix<DistanceType>& dists, float radius, const SearchParams& params);

    void save(std::string filename);

    int veclen() const;

    int size() const;

    NNIndex<Distance>* getIndex() {
        return nnIndex;
    }

    const IndexParams* getIndexParameters() {
        return nnIndex->getParameters();
    }
};

template<typename Distance>
NNIndex<Distance>* load_saved_index(const Matrix<typename Distance::ElementType>& dataset, const std::string& filename, Distance distance)
{
    typedef typename Distance::ElementType ElementType;

    FILE* fin = fopen(filename.c_str(), "rb");
    if (fin == NULL) {
        return NULL;
    }
    IndexHeader header = load_header(fin);
    if (header.data_type != Datatype<ElementType>::type()) {
        throw FLANNException("Datatype of saved index is different than of the one to be created.");
    }
    if (size_t(header.rows) != dataset.rows || size_t(header.cols) != dataset.cols) {
        throw FLANNException("The index saved belongs to a different dataset");
    }

    IndexParams* params = ParamsFactory::instance().create(header.index_type);
    NNIndex<Distance>* nnIndex = create_index_by_type<Distance>(dataset, *params, distance);
    nnIndex->loadIndex(fin);
    fclose(fin);

    return nnIndex;
}

template<typename Distance>
Index<Distance>::Index(const Matrix<ElementType>& dataset, const IndexParams& params, Distance d ) : distance (d)
{
    flann_algorithm_t index_type = params.getIndexType();
    built = false;

    if (index_type == FLANN_INDEX_SAVED) {
        nnIndex = load_saved_index<Distance>(dataset, ((const SavedIndexParams&)params).filename, distance);
        built = true;
    }
    else {
        nnIndex = create_index_by_type<Distance>(dataset, params, distance);
    }
}

template<typename Distance>
Index<Distance>::~Index()
{
    delete nnIndex;
}

template<typename Distance>
void Index<Distance>::buildIndex()
{
    if (!built) {
        nnIndex->buildIndex();
        built = true;
    }
}

template<typename Distance>
void Index<Distance>::knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& searchParams)
{
    if (!built) {
        throw FLANNException("You must build the index before searching.");
    }
    assert(queries.cols == nnIndex->veclen());
    assert(indices.rows >= queries.rows);
    assert(dists.rows >= queries.rows);
    assert(int(indices.cols) >= knn);
    assert(int(dists.cols) >= knn);

    KNNResultSet<DistanceType> resultSet(knn);
    for (size_t i = 0; i < queries.rows; i++) {
        resultSet.init(indices[i], dists[i]);
        nnIndex->findNeighbors(resultSet, queries[i], searchParams);
    }
}

template<typename Distance>
int Index<Distance>::radiusSearch(const Matrix<ElementType>& query, Matrix<int>& indices, Matrix<DistanceType>& dists, float radius, const SearchParams& searchParams)
{
    if (!built) {
        throw FLANNException("You must build the index before searching.");
    }
    if (query.rows != 1) {
        fprintf(stderr, "I can only search one feature at a time for range search\n");
        return -1;
    }
    assert(query.cols == nnIndex->veclen());
    assert(indices.cols == dists.cols);

    int n = 0;
    int* indices_ptr = NULL;
    DistanceType* dists_ptr = NULL;
    if (indices.cols > 0) {
        n = indices.cols;
        indices_ptr = indices[0];
        dists_ptr = dists[0];
    }
    RadiusResultSet<DistanceType> result_set(radius, indices_ptr, dists_ptr, n);
    nnIndex->findNeighbors(result_set, query[0], searchParams);
    size_t cnt = std::min(result_set.size(), (size_t)n);
    if (n > 0 && searchParams.sorted) {
        std::sort(make_pair_iterator(dists_ptr, indices_ptr),
                  make_pair_iterator(dists_ptr + cnt, indices_ptr + cnt),
                  pair_iterator_compare<DistanceType*, int*>());
    }

    return cnt;
}

template<typename Distance>
void Index<Distance>::save(std::string filename)
{
    FILE* fout = fopen(filename.c_str(), "wb");
    if (fout == NULL) {
        throw FLANNException("Cannot open file");
    }
    save_header(fout, *nnIndex);
    nnIndex->saveIndex(fout);
    fclose(fout);
}

template<typename Distance>
int Index<Distance>::size() const
{
    return nnIndex->size();
}

template<typename Distance>
int Index<Distance>::veclen() const
{
    return nnIndex->veclen();
}

template <typename Distance>
int hierarchicalClustering(const Matrix<typename Distance::ElementType>& features, Matrix<typename Distance::ResultType>& centers,
                           const KMeansIndexParams& params, Distance d = Distance())
{
    KMeansIndex<Distance> kmeans(features, params, d);
    kmeans.buildIndex();

    int clusterNum = kmeans.getClusterCenters(centers);
    return clusterNum;
}

}
#endif /* FLANN_HPP_ */
<|endoftext|>


<commit_before>/// \file ROOT/TPad.hxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2017-07-06
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_TPad
#define ROOT7_TPad

#include <memory>
#include <vector>

#include "ROOT/TDrawable.hxx"
#include "ROOT/TFrame.hxx"
#include "ROOT/TPadExtent.hxx"
#include "ROOT/TPadPos.hxx"
#include "ROOT/TypeTraits.hxx"

namespace ROOT {
namespace Experimental {

class TPad;

namespace Internal {
class TVirtualCanvasPainter;
}

namespace Internal {

/** \class ROOT::Experimental::Internal::TPadBase
  Base class for graphic containers for `TDrawable`-s.
  */

class TPadBase {
public:
   using Primitives_t = std::vector<std::unique_ptr<TDrawable>>;

private:
   /// Content of the pad.
   Primitives_t fPrimitives;

   /// TFrame with user coordinate system, if used by this pad.
   std::unique_ptr<TFrame> fFrame;

   /// Disable copy construction.
   TPadBase(const TPadBase &) = delete;

   /// Disable assignment.
   TPadBase &operator=(const TPadBase &) = delete;

   template <class DRAWABLE>
   DRAWABLE &AddDrawable(std::unique_ptr<DRAWABLE> &&uPtr)
   {
      DRAWABLE &drw = *uPtr;
      fPrimitives.emplace_back(std::move(uPtr));
      return drw;
   }

protected:
   /// Allow derived classes to default construct a TPadBase.
   TPadBase() = default;

public:
   virtual ~TPadBase();

   /// Divide this pad into a grid of subpad with padding in between.
   /// \param nHoriz Number of horizontal pads.
   /// \param nVert Number of vertical pads.
   /// \param padding Padding between pads.
   /// \returns vector of vector (ret[x][y]) of created pads.
   std::vector<std::vector<TPad *>> Divide(int nHoriz, int nVert, const TPadExtent &padding = {});

   /// Add something to be painted.
   /// The pad observes what's lifetime through a weak pointer.
   template <class T>
   auto &Draw(const std::shared_ptr<T> &what)
   {
      // Requires GetDrawable(what) to be known!
      return AddDrawable(GetDrawable(what));
   }

   /// Add something to be painted, with options.
   /// The pad observes what's lifetime through a weak pointer.
   template <class T, class OPTIONS>
   auto &Draw(const std::shared_ptr<T> &what, const OPTIONS &options)
   {
      // Requires GetDrawable(what, options) to be known!
      return AddDrawable(GetDrawable(what, options));
   }

   /// Add something to be painted. The pad claims ownership.
   template <class T>
   auto &Draw(std::unique_ptr<T> &&what)
   {
      // Requires GetDrawable(what) to be known!
      return AddDrawable(GetDrawable(std::move(what)));
   }

   /// Add something to be painted, with options. The pad claims ownership.
   template <class T, class OPTIONS>
   auto &Draw(std::unique_ptr<T> &&what, const OPTIONS &options)
   {
      // Requires GetDrawable(what, options) to be known!
      return AddDrawable(GetDrawable(std::move(what), options));
   }

   /// Add a copy of something to be painted.
   template <class T, class = typename std::enable_if<!ROOT::TypeTraits::IsSmartOrDumbPtr<T>::value>::type>
   auto &Draw(const T &what)
   {
      // Requires GetDrawable(what) to be known!
      return Draw(std::make_unique<T>(what));
   }

   /// Add a copy of something to be painted, with options.
   template <class T, class OPTIONS,
             class = typename std::enable_if<!ROOT::TypeTraits::IsSmartOrDumbPtr<T>::value>::type>
   auto &Draw(const T &what, const OPTIONS &options)
   {
      // Requires GetDrawable(what, options) to be known!
      return Draw(std::make_unique<T>(what), options);
   }

   /// Remove an object from the list of primitives.
   // TODO: void Wipe();

   /// Get the elements contained in the canvas.
   const Primitives_t &GetPrimitives() const { return fPrimitives; }

   /// Convert a `Pixel` position to Canvas-normalized positions.
   virtual std::array<TPadCoord::Normal, 2> PixelsToNormal(const std::array<TPadCoord::Pixel, 2> &pos) const = 0;

   /// Convert user coordinates to normal coordinates.
   std::array<TPadCoord::Normal, 2> UserToNormal(const std::array<TPadCoord::User, 2> &pos) const
   {
      return fFrame->GetUserCoords()->ToNormal(pos);
   }
};
} // namespace Internal

/** \class TPadDrawable
   Draw a TPad, by drawing its contained graphical elements at the pad offset in the parent pad.'
   */
class TPadDrawable: public TDrawable {
private:
   const std::unique_ptr<TPad> fPad; ///< The pad to be painted
   TPadPos fPos;                     ///< Offset with respect to parent TPad.

public:
   TPadDrawable() = default;

   TPadDrawable(std::unique_ptr<TPad> &&pPad, const TPadPos &pos): fPad(std::move(pPad)), fPos(pos) {}

   /// Paint the pad.
   void Paint(Internal::TVirtualCanvasPainter & /*canv*/) final
   {
      // FIXME: and then what? Something with fPad.GetListOfPrimitives()?
   }

   TPad *Get() const { return fPad.get(); }
};

/** \class ROOT::Experimental::TPad
  Graphic container for `TDrawable`-s.
  */

class TPad: public Internal::TPadBase {
private:
   /// Pad containing this pad as a sub-pad.
   const TPadBase *fParent = nullptr;

   /// Size of the pad in the parent's (!) coordinate system.
   TPadExtent fSize;

public:

   friend std::unique_ptr<TPadDrawable> GetDrawable(std::unique_ptr<TPad> &&pad, const TPadPos &pos)
   {
      return std::make_unique<TPadDrawable>(std::move(pad), pos);
   }

   /// Create a child pad.
   TPad(const TPadBase &parent, const TPadExtent &size): fParent(&parent), fSize(size) {}

   /// Destructor to have a vtable.
   virtual ~TPad();

   /// Get the size of the pad in parent (!) coordinates.
   const TPadExtent &GetSize() const { return fSize; }

   /// Convert a `Pixel` position to Canvas-normalized positions.
   std::array<TPadCoord::Normal, 2> PixelsToNormal(const std::array<TPadCoord::Pixel, 2> &pos) const override
   {
      std::array<TPadCoord::Normal, 2> posInParentNormal = fParent->PixelsToNormal(pos);
      std::array<TPadCoord::Normal, 2> myPixelInNormal =
         fParent->PixelsToNormal({{fSize.fHoriz.fPixel, fSize.fVert.fPixel}});
      std::array<TPadCoord::Normal, 2> myUserInNormal =
         fParent->UserToNormal({{fSize.fHoriz.fUser, fSize.fVert.fUser}});
      // If the parent says pos is at 0.6 in normal coords, and our size converted to normal is 0.2, then pos in our
      // coord system is 3.0!
      return {{posInParentNormal[0] / (fSize.fHoriz.fNormal + myPixelInNormal[0] + myUserInNormal[0]),
               posInParentNormal[1] / (fSize.fVert.fNormal + myPixelInNormal[1] + myUserInNormal[1])}};
   }

   /// Convert a TPadPos to [x, y] of normalized coordinates.
   std::array<TPadCoord::Normal, 2> ToNormal(const Internal::TPadHorizVert &pos) const
   {
      std::array<TPadCoord::Normal, 2> pixelsInNormal = PixelsToNormal({{pos.fHoriz.fPixel, pos.fVert.fPixel}});
      std::array<TPadCoord::Normal, 2> userInNormal = UserToNormal({{pos.fHoriz.fUser, pos.fVert.fUser}});
      return {{pos.fHoriz.fNormal + pixelsInNormal[0] + userInNormal[0],
               pos.fVert.fNormal + pixelsInNormal[1] + userInNormal[1]}};
   }
};

} // namespace Experimental
} // namespace ROOT

#endif
<commit_msg>Use TFrame::UserToNormal().<commit_after>/// \file ROOT/TPad.hxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2017-07-06
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_TPad
#define ROOT7_TPad

#include <memory>
#include <vector>

#include "ROOT/TDrawable.hxx"
#include "ROOT/TFrame.hxx"
#include "ROOT/TPadExtent.hxx"
#include "ROOT/TPadPos.hxx"
#include "ROOT/TypeTraits.hxx"

namespace ROOT {
namespace Experimental {

class TPad;

namespace Internal {
class TVirtualCanvasPainter;
}

namespace Internal {

/** \class ROOT::Experimental::Internal::TPadBase
  Base class for graphic containers for `TDrawable`-s.
  */

class TPadBase {
public:
   using Primitives_t = std::vector<std::unique_ptr<TDrawable>>;

private:
   /// Content of the pad.
   Primitives_t fPrimitives;

   /// TFrame with user coordinate system, if used by this pad.
   std::unique_ptr<TFrame> fFrame;

   /// Disable copy construction.
   TPadBase(const TPadBase &) = delete;

   /// Disable assignment.
   TPadBase &operator=(const TPadBase &) = delete;

   template <class DRAWABLE>
   DRAWABLE &AddDrawable(std::unique_ptr<DRAWABLE> &&uPtr)
   {
      DRAWABLE &drw = *uPtr;
      fPrimitives.emplace_back(std::move(uPtr));
      return drw;
   }

protected:
   /// Allow derived classes to default construct a TPadBase.
   TPadBase() = default;

public:
   virtual ~TPadBase();

   /// Divide this pad into a grid of subpad with padding in between.
   /// \param nHoriz Number of horizontal pads.
   /// \param nVert Number of vertical pads.
   /// \param padding Padding between pads.
   /// \returns vector of vector (ret[x][y]) of created pads.
   std::vector<std::vector<TPad *>> Divide(int nHoriz, int nVert, const TPadExtent &padding = {});

   /// Add something to be painted.
   /// The pad observes what's lifetime through a weak pointer.
   template <class T>
   auto &Draw(const std::shared_ptr<T> &what)
   {
      // Requires GetDrawable(what) to be known!
      return AddDrawable(GetDrawable(what));
   }

   /// Add something to be painted, with options.
   /// The pad observes what's lifetime through a weak pointer.
   template <class T, class OPTIONS>
   auto &Draw(const std::shared_ptr<T> &what, const OPTIONS &options)
   {
      // Requires GetDrawable(what, options) to be known!
      return AddDrawable(GetDrawable(what, options));
   }

   /// Add something to be painted. The pad claims ownership.
   template <class T>
   auto &Draw(std::unique_ptr<T> &&what)
   {
      // Requires GetDrawable(what) to be known!
      return AddDrawable(GetDrawable(std::move(what)));
   }

   /// Add something to be painted, with options. The pad claims ownership.
   template <class T, class OPTIONS>
   auto &Draw(std::unique_ptr<T> &&what, const OPTIONS &options)
   {
      // Requires GetDrawable(what, options) to be known!
      return AddDrawable(GetDrawable(std::move(what), options));
   }

   /// Add a copy of something to be painted.
   template <class T, class = typename std::enable_if<!ROOT::TypeTraits::IsSmartOrDumbPtr<T>::value>::type>
   auto &Draw(const T &what)
   {
      // Requires GetDrawable(what) to be known!
      return Draw(std::make_unique<T>(what));
   }

   /// Add a copy of something to be painted, with options.
   template <class T, class OPTIONS,
             class = typename std::enable_if<!ROOT::TypeTraits::IsSmartOrDumbPtr<T>::value>::type>
   auto &Draw(const T &what, const OPTIONS &options)
   {
      // Requires GetDrawable(what, options) to be known!
      return Draw(std::make_unique<T>(what), options);
   }

   /// Remove an object from the list of primitives.
   // TODO: void Wipe();

   /// Get the elements contained in the canvas.
   const Primitives_t &GetPrimitives() const { return fPrimitives; }

   /// Convert a `Pixel` position to Canvas-normalized positions.
   virtual std::array<TPadCoord::Normal, 2> PixelsToNormal(const std::array<TPadCoord::Pixel, 2> &pos) const = 0;

   /// Convert user coordinates to normal coordinates.
   std::array<TPadCoord::Normal, 2> UserToNormal(const std::array<TPadCoord::User, 2> &pos) const
   {
      return fFrame->UserToNormal(pos);
   }
};
} // namespace Internal

/** \class TPadDrawable
   Draw a TPad, by drawing its contained graphical elements at the pad offset in the parent pad.'
   */
class TPadDrawable: public TDrawable {
private:
   const std::unique_ptr<TPad> fPad; ///< The pad to be painted
   TPadPos fPos;                     ///< Offset with respect to parent TPad.

public:
   TPadDrawable() = default;

   TPadDrawable(std::unique_ptr<TPad> &&pPad, const TPadPos &pos): fPad(std::move(pPad)), fPos(pos) {}

   /// Paint the pad.
   void Paint(Internal::TVirtualCanvasPainter & /*canv*/) final
   {
      // FIXME: and then what? Something with fPad.GetListOfPrimitives()?
   }

   TPad *Get() const { return fPad.get(); }
};

/** \class ROOT::Experimental::TPad
  Graphic container for `TDrawable`-s.
  */

class TPad: public Internal::TPadBase {
private:
   /// Pad containing this pad as a sub-pad.
   const TPadBase *fParent = nullptr;

   /// Size of the pad in the parent's (!) coordinate system.
   TPadExtent fSize;

public:

   friend std::unique_ptr<TPadDrawable> GetDrawable(std::unique_ptr<TPad> &&pad, const TPadPos &pos)
   {
      return std::make_unique<TPadDrawable>(std::move(pad), pos);
   }

   /// Create a child pad.
   TPad(const TPadBase &parent, const TPadExtent &size): fParent(&parent), fSize(size) {}

   /// Destructor to have a vtable.
   virtual ~TPad();

   /// Get the size of the pad in parent (!) coordinates.
   const TPadExtent &GetSize() const { return fSize; }

   /// Convert a `Pixel` position to Canvas-normalized positions.
   std::array<TPadCoord::Normal, 2> PixelsToNormal(const std::array<TPadCoord::Pixel, 2> &pos) const override
   {
      std::array<TPadCoord::Normal, 2> posInParentNormal = fParent->PixelsToNormal(pos);
      std::array<TPadCoord::Normal, 2> myPixelInNormal =
         fParent->PixelsToNormal({{fSize.fHoriz.fPixel, fSize.fVert.fPixel}});
      std::array<TPadCoord::Normal, 2> myUserInNormal =
         fParent->UserToNormal({{fSize.fHoriz.fUser, fSize.fVert.fUser}});
      // If the parent says pos is at 0.6 in normal coords, and our size converted to normal is 0.2, then pos in our
      // coord system is 3.0!
      return {{posInParentNormal[0] / (fSize.fHoriz.fNormal + myPixelInNormal[0] + myUserInNormal[0]),
               posInParentNormal[1] / (fSize.fVert.fNormal + myPixelInNormal[1] + myUserInNormal[1])}};
   }

   /// Convert a TPadPos to [x, y] of normalized coordinates.
   std::array<TPadCoord::Normal, 2> ToNormal(const Internal::TPadHorizVert &pos) const
   {
      std::array<TPadCoord::Normal, 2> pixelsInNormal = PixelsToNormal({{pos.fHoriz.fPixel, pos.fVert.fPixel}});
      std::array<TPadCoord::Normal, 2> userInNormal = UserToNormal({{pos.fHoriz.fUser, pos.fVert.fUser}});
      return {{pos.fHoriz.fNormal + pixelsInNormal[0] + userInNormal[0],
               pos.fVert.fNormal + pixelsInNormal[1] + userInNormal[1]}};
   }
};

} // namespace Experimental
} // namespace ROOT

#endif
<|endoftext|>


<commit_before>// @(#)root/eve:$Id$
// Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TEveGedEditor.h"
#include "TEveElement.h"
#include "TEveManager.h"

#include "TGButton.h"
#include "TGLabel.h"
#include "TGToolTip.h"
#include "TGDNDManager.h"
#include "TGMsgBox.h"

#include "TClass.h"

//==============================================================================
// TEveGedEditor
//==============================================================================

//______________________________________________________________________________
//
// Specialization of TGedEditor for proper update propagation to
// TEveManager.

ClassImp(TEveGedEditor);

Int_t   TEveGedEditor::fgMaxExtraEditors = 10;
TList  *TEveGedEditor::fgExtraEditors    = new TList;

//______________________________________________________________________________
TEveGedEditor::TEveGedEditor(TCanvas* canvas, UInt_t width, UInt_t height) :
   TGedEditor(canvas, width, height),
   fElement  (0),
   fObject   (0)
{
   // Constructor.

   // Remove old name-frame -- it is created in TGedEditor constructor
   // so virtuals are not active yet.
   fTabContainer->RemoveAll();
   TGedFrame* nf = CreateNameFrame(fTabContainer, "Style");
   nf->SetGedEditor(this);
   nf->SetModelClass(0);
   fTabContainer->AddFrame(nf, nf->GetLayoutHints());

   // Fix priority for TAttMarkerEditor.
   TClass* amClass = TClass::GetClass("TAttMarker");
   TClass* edClass = TClass::GetClass("TAttMarkerEditor");
   TGWindow *exroot = (TGWindow*) fClient->GetRoot();
   fClient->SetRoot(fTabContainer);
   SetFrameCreator(this);
   TGedFrame *frame = reinterpret_cast<TGedFrame*>(edClass->New());
   frame->SetModelClass(amClass);
   {
      Int_t off = edClass->GetDataMemberOffset("fPriority");
      if (off == 0)
         Warning("TEveGedEditor::TEveGedEditor", "Can't fix priority for TAttMarkerEditor.\n");
      else
         * (Int_t*) (((char*)frame) + off) = 1;
   }
   SetFrameCreator(0);
   fClient->SetRoot(exroot);
   fFrameMap.Add(amClass, frame);
}

//______________________________________________________________________________
TEveGedEditor::~TEveGedEditor()
{
   // Destructor.

   if (gDebug > 0)
      Info("TEveGedEditor::~TEveGedEditor", "%p going down.", this);
}

//______________________________________________________________________________
void TEveGedEditor::CloseWindow()
{
   // Called from window-manger close button.
   // Unregister from global list and delete the window.

   if (gDebug > 0)
      Info("TEveGedEditor::CloseWindow", "%p closing.", this);

   fgExtraEditors->Remove(this);

   DeleteWindow();
}

//______________________________________________________________________________
void TEveGedEditor::DeleteWindow()
{
   // This is exact clone of TGFrame::DeleteWindow().
   // Needs to be overriden together with CloseWindow() otherwise CINT
   // goes kaboom in timer execution.

   if (gDebug > 0)
      Info("TEveGedEditor::DeleteWindow", "%p shooting timer.", this);

   DisplayElement(0);

   if (gDNDManager) {
      if (gDNDManager->GetMainFrame() == this)
         gDNDManager->SetMainFrame(0);
   }
   if (!TestBit(kDeleteWindowCalled))
      TTimer::SingleShot(150, IsA()->GetName(), this, "ReallyDelete()");
   SetBit(kDeleteWindowCalled);
}

//______________________________________________________________________________
TGedFrame* TEveGedEditor::CreateNameFrame(const TGWindow* parent, const char* /*tab_name*/)
{
  // Create name-frame for a tab.

  return new TEveGedNameFrame(parent);
}

//______________________________________________________________________________
TEveElement* TEveGedEditor::GetEveElement() const
{
   // Return eve-element if it is the model object.

   return (fModel == fObject) ? fElement : 0;
}

//______________________________________________________________________________
void TEveGedEditor::DisplayElement(TEveElement* re)
{
   // Show a TEveElement in editor.

   static const TEveException eh("TEveGedEditor::DisplayElement ");

   fElement = re;
   fObject  = fElement ? fElement->GetEditorObject(eh) : 0;
   TGedEditor::SetModel(fPad, fObject, kButton1Down);
}

//______________________________________________________________________________
void TEveGedEditor::DisplayObject(TObject* obj)
{
   // Show a TObject in editor.

   fElement = dynamic_cast<TEveElement*>(obj);
   fObject  = obj;
   TGedEditor::SetModel(fPad, obj, kButton1Down);
}

//==============================================================================

//______________________________________________________________________________
void TEveGedEditor::SetModel(TVirtualPad* pad, TObject* obj, Int_t event)
{
   // Set model object.

   fElement = dynamic_cast<TEveElement*>(obj);
   fObject  = obj;
   TGedEditor::SetModel(pad, obj, event);
}

//______________________________________________________________________________
void TEveGedEditor::Update(TGedFrame* /*gframe*/)
{
   // Virtual method from TGedEditor, called on every change.
   // Propagates changes to TEveElement and TEveManager.

   if (fElement)
   {
      fElement->ElementChanged();
      fElement->PropagateVizParamsToProjecteds();
   }

   gEve->Redraw3D();
}

//------------------------------------------------------------------------------
// Static functions for management of extra editors.
//------------------------------------------------------------------------------

//______________________________________________________________________________
void TEveGedEditor::SpawnNewEditor(TObject* obj)
{
   // Static function to create a new extra editor.

   if (fgExtraEditors->GetSize() >= fgMaxExtraEditors)
   {
      new TGMsgBox(gClient->GetDefaultRoot(), gEve->GetMainWindow(),
                   "Clutter warning",
                   "Maximum number of extra editors reached.",
                   kMBIconStop, kMBOk);
   }

   if (obj)
   {
      TEveGedEditor *ed = new TEveGedEditor();
      ed->DisplayObject(obj);
      ed->SetWindowName(Form("GED %s", obj->GetName()));

      fgExtraEditors->Add(ed);
   }
}

//______________________________________________________________________________
void TEveGedEditor::ElementChanged(TEveElement* el)
{
   // Element was changed. Update editors showing it.

   TObject *eobj = el->GetEditorObject("TEveGedEditor::ElementChanged ");
   TObjLink *lnk = fgExtraEditors->FirstLink();
   while (lnk)
   {
      TEveGedEditor *ed = (TEveGedEditor*) lnk->GetObject();
      if (ed->GetModel() == eobj)
         ed->DisplayElement(el);
      lnk = lnk->Next();
   }
}

//______________________________________________________________________________
void TEveGedEditor::ElementDeleted(TEveElement* el)
{
   // Element is being deleted. Close editors showing it.

   TObject *eobj = el->GetEditorObject("TEveGedEditor::ElementChanged ");
   TObjLink *lnk = fgExtraEditors->FirstLink();
   while (lnk)
   {
      TEveGedEditor *ed = (TEveGedEditor*) lnk->GetObject();
      if (ed->GetModel() == eobj)
      {
         TObjLink *next = lnk->Next();
         ed->DeleteWindow();
         fgExtraEditors->Remove(lnk);
         lnk = next;
      }
      else
      {
         lnk = lnk->Next();
      }
   }
}

//______________________________________________________________________________
void TEveGedEditor::DestroyEditors()
{
   // Destroys all editors. Called from EVE termination.

   while ( ! fgExtraEditors->IsEmpty())
   {
      TEveGedEditor *ed = (TEveGedEditor*) fgExtraEditors->First();
      ed->DeleteWindow();
      fgExtraEditors->RemoveFirst();
   }
}

//==============================================================================
// TEveGedNameFrame
//==============================================================================

//______________________________________________________________________________
//
// Specialization of TGedNameFrame used in EVE.
// It provides the ability to undock given editor for easier use.
// Support for that is also provided from the TEveManager.

ClassImp(TEveGedNameFrame);

//______________________________________________________________________________
TEveGedNameFrame::TEveGedNameFrame(const TGWindow *p, Int_t width, Int_t height,
                                   UInt_t options) :
   TGedFrame(p, width, height, options),
   fNCButton(0)
{
   // Constructor.

   fNCButton = new TGTextButton(this, "");
   fNCButton->SetTextColor(0x0020a0);
   AddFrame(fNCButton, new TGLayoutHints(kLHintsNormal | kLHintsExpandX));
   fNCButton->Connect("Clicked()", "TEveGedNameFrame", this, "SpawnEditorClone()");
}

//______________________________________________________________________________
TEveGedNameFrame::~TEveGedNameFrame()
{
   // Destructor.
}

//______________________________________________________________________________
void TEveGedNameFrame::SetModel(TObject* obj)
{
   // Set model object.

   if (obj)
   {
      fNCButton->SetText(Form("%s [%s]", obj->GetName(), obj->ClassName()));
      fNCButton->SetToolTipText(obj->GetTitle());
      fNCButton->SetEnabled(kTRUE);
   }
   else
   {
      fNCButton->SetText("No object selected.");
      fNCButton->SetToolTipText(0);
      fNCButton->SetEnabled(kFALSE);
   }
}

//______________________________________________________________________________
void TEveGedNameFrame::SpawnEditorClone()
{
   // Create a new floating editor with current object.

   TEveGedEditor::SpawnNewEditor(fGedEditor->GetModel());
}
<commit_msg>Fix coding conventions<commit_after>// @(#)root/eve:$Id$
// Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TEveGedEditor.h"
#include "TEveElement.h"
#include "TEveManager.h"

#include "TGButton.h"
#include "TGLabel.h"
#include "TGToolTip.h"
#include "TGDNDManager.h"
#include "TGMsgBox.h"

#include "TClass.h"

//==============================================================================
// TEveGedEditor
//==============================================================================

//______________________________________________________________________________
//
// Specialization of TGedEditor for proper update propagation to
// TEveManager.

ClassImp(TEveGedEditor);

Int_t   TEveGedEditor::fgMaxExtraEditors = 10;
TList  *TEveGedEditor::fgExtraEditors    = new TList;

//______________________________________________________________________________
TEveGedEditor::TEveGedEditor(TCanvas* canvas, UInt_t width, UInt_t height) :
   TGedEditor(canvas, width, height),
   fElement  (0),
   fObject   (0)
{
   // Constructor.

   // Remove old name-frame -- it is created in TGedEditor constructor
   // so virtuals are not active yet.
   fTabContainer->RemoveAll();
   TGedFrame* nf = CreateNameFrame(fTabContainer, "Style");
   nf->SetGedEditor(this);
   nf->SetModelClass(0);
   fTabContainer->AddFrame(nf, nf->GetLayoutHints());

   // Fix priority for TAttMarkerEditor.
   TClass* amClass = TClass::GetClass("TAttMarker");
   TClass* edClass = TClass::GetClass("TAttMarkerEditor");
   TGWindow *exroot = (TGWindow*) fClient->GetRoot();
   fClient->SetRoot(fTabContainer);
   SetFrameCreator(this);
   TGedFrame *frame = reinterpret_cast<TGedFrame*>(edClass->New());
   frame->SetModelClass(amClass);
   {
      Int_t off = edClass->GetDataMemberOffset("fPriority");
      if (off == 0)
         Warning("TEveGedEditor::TEveGedEditor", "Can't fix priority for TAttMarkerEditor.\n");
      else
         * (Int_t*) (((char*)frame) + off) = 1;
   }
   SetFrameCreator(0);
   fClient->SetRoot(exroot);
   fFrameMap.Add(amClass, frame);
}

//______________________________________________________________________________
TEveGedEditor::~TEveGedEditor()
{
   // Destructor.

   if (gDebug > 0)
      Info("TEveGedEditor::~TEveGedEditor", "%p going down.", this);
}

//______________________________________________________________________________
void TEveGedEditor::CloseWindow()
{
   // Called from window-manger close button.
   // Unregister from global list and delete the window.

   if (gDebug > 0)
      Info("TEveGedEditor::CloseWindow", "%p closing.", this);

   fgExtraEditors->Remove(this);

   DeleteWindow();
}

//______________________________________________________________________________
void TEveGedEditor::DeleteWindow()
{
   // This is exact clone of TGFrame::DeleteWindow().
   // Needs to be overriden together with CloseWindow() otherwise CINT
   // goes kaboom in timer execution.

   if (gDebug > 0)
      Info("TEveGedEditor::DeleteWindow", "%p shooting timer.", this);

   DisplayElement(0);

   if (gDNDManager) {
      if (gDNDManager->GetMainFrame() == this)
         gDNDManager->SetMainFrame(0);
   }
   if (!TestBit(kDeleteWindowCalled))
      TTimer::SingleShot(150, IsA()->GetName(), this, "ReallyDelete()");
   SetBit(kDeleteWindowCalled);
}

//______________________________________________________________________________
TGedFrame* TEveGedEditor::CreateNameFrame(const TGWindow* parent, const char* /*tab_name*/)
{
   // Create name-frame for a tab.

   return new TEveGedNameFrame(parent);
}

//______________________________________________________________________________
TEveElement* TEveGedEditor::GetEveElement() const
{
   // Return eve-element if it is the model object.

   return (fModel == fObject) ? fElement : 0;
}

//______________________________________________________________________________
void TEveGedEditor::DisplayElement(TEveElement* re)
{
   // Show a TEveElement in editor.

   static const TEveException eh("TEveGedEditor::DisplayElement ");

   fElement = re;
   fObject  = fElement ? fElement->GetEditorObject(eh) : 0;
   TGedEditor::SetModel(fPad, fObject, kButton1Down);
}

//______________________________________________________________________________
void TEveGedEditor::DisplayObject(TObject* obj)
{
   // Show a TObject in editor.

   fElement = dynamic_cast<TEveElement*>(obj);
   fObject  = obj;
   TGedEditor::SetModel(fPad, obj, kButton1Down);
}

//==============================================================================

//______________________________________________________________________________
void TEveGedEditor::SetModel(TVirtualPad* pad, TObject* obj, Int_t event)
{
   // Set model object.

   fElement = dynamic_cast<TEveElement*>(obj);
   fObject  = obj;
   TGedEditor::SetModel(pad, obj, event);
}

//______________________________________________________________________________
void TEveGedEditor::Update(TGedFrame* /*gframe*/)
{
   // Virtual method from TGedEditor, called on every change.
   // Propagates changes to TEveElement and TEveManager.

   if (fElement)
   {
      fElement->ElementChanged();
      fElement->PropagateVizParamsToProjecteds();
   }

   gEve->Redraw3D();
}

//------------------------------------------------------------------------------
// Static functions for management of extra editors.
//------------------------------------------------------------------------------

//______________________________________________________________________________
void TEveGedEditor::SpawnNewEditor(TObject* obj)
{
   // Static function to create a new extra editor.

   if (fgExtraEditors->GetSize() >= fgMaxExtraEditors)
   {
      new TGMsgBox(gClient->GetDefaultRoot(), gEve->GetMainWindow(),
                   "Clutter warning",
                   "Maximum number of extra editors reached.",
                   kMBIconStop, kMBOk);
   }

   if (obj)
   {
      TEveGedEditor *ed = new TEveGedEditor();
      ed->DisplayObject(obj);
      ed->SetWindowName(Form("GED %s", obj->GetName()));

      fgExtraEditors->Add(ed);
   }
}

//______________________________________________________________________________
void TEveGedEditor::ElementChanged(TEveElement* el)
{
   // Element was changed. Update editors showing it.

   TObject *eobj = el->GetEditorObject("TEveGedEditor::ElementChanged ");
   TObjLink *lnk = fgExtraEditors->FirstLink();
   while (lnk)
   {
      TEveGedEditor *ed = (TEveGedEditor*) lnk->GetObject();
      if (ed->GetModel() == eobj)
         ed->DisplayElement(el);
      lnk = lnk->Next();
   }
}

//______________________________________________________________________________
void TEveGedEditor::ElementDeleted(TEveElement* el)
{
   // Element is being deleted. Close editors showing it.

   TObject *eobj = el->GetEditorObject("TEveGedEditor::ElementChanged ");
   TObjLink *lnk = fgExtraEditors->FirstLink();
   while (lnk)
   {
      TEveGedEditor *ed = (TEveGedEditor*) lnk->GetObject();
      if (ed->GetModel() == eobj)
      {
         TObjLink *next = lnk->Next();
         ed->DeleteWindow();
         fgExtraEditors->Remove(lnk);
         lnk = next;
      }
      else
      {
         lnk = lnk->Next();
      }
   }
}

//______________________________________________________________________________
void TEveGedEditor::DestroyEditors()
{
   // Destroys all editors. Called from EVE termination.

   while ( ! fgExtraEditors->IsEmpty())
   {
      TEveGedEditor *ed = (TEveGedEditor*) fgExtraEditors->First();
      ed->DeleteWindow();
      fgExtraEditors->RemoveFirst();
   }
}

//==============================================================================
// TEveGedNameFrame
//==============================================================================

//______________________________________________________________________________
//
// Specialization of TGedNameFrame used in EVE.
// It provides the ability to undock given editor for easier use.
// Support for that is also provided from the TEveManager.

ClassImp(TEveGedNameFrame);

//______________________________________________________________________________
TEveGedNameFrame::TEveGedNameFrame(const TGWindow *p, Int_t width, Int_t height,
                                   UInt_t options) :
   TGedFrame(p, width, height, options),
   fNCButton(0)
{
   // Constructor.

   fNCButton = new TGTextButton(this, "");
   fNCButton->SetTextColor(0x0020a0);
   AddFrame(fNCButton, new TGLayoutHints(kLHintsNormal | kLHintsExpandX));
   fNCButton->Connect("Clicked()", "TEveGedNameFrame", this, "SpawnEditorClone()");
}

//______________________________________________________________________________
TEveGedNameFrame::~TEveGedNameFrame()
{
   // Destructor.
}

//______________________________________________________________________________
void TEveGedNameFrame::SetModel(TObject* obj)
{
   // Set model object.

   if (obj)
   {
      fNCButton->SetText(Form("%s [%s]", obj->GetName(), obj->ClassName()));
      fNCButton->SetToolTipText(obj->GetTitle());
      fNCButton->SetEnabled(kTRUE);
   }
   else
   {
      fNCButton->SetText("No object selected.");
      fNCButton->SetToolTipText(0);
      fNCButton->SetEnabled(kFALSE);
   }
}

//______________________________________________________________________________
void TEveGedNameFrame::SpawnEditorClone()
{
   // Create a new floating editor with current object.

   TEveGedEditor::SpawnNewEditor(fGedEditor->GetModel());
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, Intel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "ui/base/l10n/l10n_util.h"
#include "base/callback.h"
#include "base/i18n/rtl.h"
#include "base/singleton.h"
#include "base/values.h"
#include "content/browser/webui/web_ui_util.h"
#include "chrome/browser/ui/webui/blank_ui.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/jstemplate_builder.h"
#include "content/browser/browser_thread.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "grit/generated_resources.h"

class BlankUIHTMLSource : public ChromeURLDataManager::DataSource {
  public:
    BlankUIHTMLSource()
	:DataSource(chrome::kChromeUINewTabHost, MessageLoop::current()) {}

    virtual void StartDataRequest(const std::string& path,
						bool is_off_the_record,
						int request_id) {

	std::string title = QString::fromUtf8(l10n_util::GetStringUTF8(IDS_NEW_TAB_TITLE).c_str()).toStdString();
	std::string full_html;
	full_html.append("<meta charset=\"utf-8\"/><title>");
	full_html.append(title);
	full_html.append("</title>");

	RefCountedBytes* html = new RefCountedBytes;
	html->data.resize(full_html.size());
	std::copy(full_html.begin(), full_html.end(), html->data.begin());
	SendResponse(request_id, html);
    }

    virtual std::string GetMimeType(const std::string&) const {
       DLOG(INFO)<<__FUNCTION__;
       return "text/html";
    }

  private:
    ~BlankUIHTMLSource() {}

    DISALLOW_COPY_AND_ASSIGN(BlankUIHTMLSource);
};

BlankUI::BlankUI(TabContents* tab_contents) : WebUI(tab_contents) {
  BlankUIHTMLSource* html_source = new BlankUIHTMLSource();
  tab_contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
}
<commit_msg>use new i18n method for blank page<commit_after>/*
 * Copyright (c) 2010, Intel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "ui/base/l10n/l10n_util.h"
#include "base/callback.h"
#include "base/i18n/rtl.h"
#include "base/singleton.h"
#include "base/values.h"
#include "content/browser/webui/web_ui_util.h"
#include "chrome/browser/ui/webui/blank_ui.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/jstemplate_builder.h"
#include "content/browser/browser_thread.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "grit/generated_resources.h"

class BlankUIHTMLSource : public ChromeURLDataManager::DataSource {
  public:
    BlankUIHTMLSource()
	:DataSource(chrome::kChromeUINewTabHost, MessageLoop::current()) {}

    virtual void StartDataRequest(const std::string& path,
						bool is_off_the_record,
						int request_id) {
 	DictionaryValue localized_strings;
  	localized_strings.SetString("title",
      		l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));

  	ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);

  	static const base::StringPiece blank_tab_html("<title i18n-content=\"title\"></title>");

  	std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
      		blank_tab_html, &localized_strings);

	RefCountedBytes* html = new RefCountedBytes;
	html->data.resize(full_html.size());
	std::copy(full_html.begin(), full_html.end(), html->data.begin());

	SendResponse(request_id, html);
    }

    virtual std::string GetMimeType(const std::string&) const {
       DLOG(INFO)<<__FUNCTION__;
       return "text/html";
    }

  private:
    ~BlankUIHTMLSource() {}

    DISALLOW_COPY_AND_ASSIGN(BlankUIHTMLSource);
};

BlankUI::BlankUI(TabContents* tab_contents) : WebUI(tab_contents) {
  BlankUIHTMLSource* html_source = new BlankUIHTMLSource();
  tab_contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/experimental/io/AsyncBase.h>

#include <sys/eventfd.h>
#include <cerrno>
#include <ostream>
#include <stdexcept>
#include <string>

#include <boost/intrusive/parent_from_member.hpp>
#include <glog/logging.h>

#include <folly/Exception.h>
#include <folly/Format.h>
#include <folly/Likely.h>
#include <folly/String.h>
#include <folly/portability/Unistd.h>

namespace folly {

AsyncBaseOp::AsyncBaseOp(NotificationCallback cb)
    : cb_(std::move(cb)), state_(State::UNINITIALIZED), result_(-EINVAL) {}

void AsyncBaseOp::reset(NotificationCallback cb) {
  CHECK_NE(state_, State::PENDING);
  cb_ = std::move(cb);
  state_ = State::UNINITIALIZED;
  result_ = -EINVAL;
}

AsyncBaseOp::~AsyncBaseOp() {
  CHECK_NE(state_, State::PENDING);
}

void AsyncBaseOp::start() {
  DCHECK_EQ(state_, State::INITIALIZED);
  state_ = State::PENDING;
}

void AsyncBaseOp::unstart() {
  DCHECK_EQ(state_, State::PENDING);
  state_ = State::INITIALIZED;
}

void AsyncBaseOp::complete(ssize_t result) {
  DCHECK_EQ(state_, State::PENDING);
  state_ = State::COMPLETED;
  result_ = result;
  if (cb_) {
    cb_(this);
  }
}

void AsyncBaseOp::cancel() {
  DCHECK_EQ(state_, State::PENDING);
  state_ = State::CANCELED;
}

ssize_t AsyncBaseOp::result() const {
  CHECK_EQ(state_, State::COMPLETED);
  return result_;
}

void AsyncBaseOp::init() {
  CHECK_EQ(state_, State::UNINITIALIZED);
  state_ = State::INITIALIZED;
}

std::string AsyncBaseOp::fd2name(int fd) {
  std::string path = folly::to<std::string>("/proc/self/fd/", fd);
  char link[PATH_MAX];
  const ssize_t length =
      std::max<ssize_t>(readlink(path.c_str(), link, PATH_MAX), 0);
  return path.assign(link, length);
}

AsyncBase::AsyncBase(size_t capacity, PollMode pollMode) : capacity_(capacity) {
  CHECK_GT(capacity_, 0);
  completed_.reserve(capacity_);
  if (pollMode == POLLABLE) {
    pollFd_ = eventfd(0, EFD_NONBLOCK);
    checkUnixError(pollFd_, "AsyncBase: eventfd creation failed");
  }
}

AsyncBase::~AsyncBase() {
  CHECK_EQ(pending_, 0);
  if (pollFd_ != -1) {
    CHECK_ERR(close(pollFd_));
  }
}

void AsyncBase::decrementPending(size_t n) {
  auto p =
      pending_.fetch_add(static_cast<size_t>(-n), std::memory_order_acq_rel);
  DCHECK_GE(p, 1);
}

void AsyncBase::submit(Op* op) {
  CHECK_EQ(op->state(), Op::State::INITIALIZED);
  initializeContext(); // on demand

  // We can increment past capacity, but we'll clean up after ourselves.
  auto p = pending_.fetch_add(1, std::memory_order_acq_rel);
  if (p >= capacity_) {
    decrementPending();
    throw std::range_error("AsyncBase: too many pending requests");
  }

  op->start();
  int rc = submitOne(op);

  if (rc <= 0) {
    op->unstart();
    decrementPending();
    if (rc < 0) {
      throwSystemErrorExplicit(-rc, "AsyncBase: io_submit failed");
    }
  }
  submitted_ += rc;
  DCHECK_EQ(rc, 1);
}

int AsyncBase::submit(Range<Op**> ops) {
  for (auto& op : ops) {
    CHECK_EQ(op->state(), Op::State::INITIALIZED);
    op->start();
  }
  initializeContext(); // on demand

  // We can increment past capacity, but we'll clean up after ourselves.
  auto p = pending_.fetch_add(ops.size(), std::memory_order_acq_rel);
  if (p >= capacity_) {
    decrementPending(ops.size());
    throw std::range_error("AsyncBase: too many pending requests");
  }

  int rc = submitRange(ops);

  if (rc < 0) {
    decrementPending(ops.size());
    throwSystemErrorExplicit(-rc, "AsyncBase: io_submit failed");
  }
  // Any ops that did not get submitted go back to INITIALIZED state
  // and are removed from pending count.
  for (size_t i = rc; i < ops.size(); i++) {
    ops[i]->unstart();
    decrementPending(1);
  }
  submitted_ += rc;
  DCHECK_LE(rc, ops.size());

  return rc;
}

Range<AsyncBase::Op**> AsyncBase::wait(size_t minRequests) {
  CHECK(isInit());
  CHECK_EQ(pollFd_, -1) << "wait() only allowed on non-pollable object";
  auto p = pending_.load(std::memory_order_acquire);
  CHECK_LE(minRequests, p);
  return doWait(WaitType::COMPLETE, minRequests, p, completed_);
}

Range<AsyncBase::Op**> AsyncBase::cancel() {
  CHECK(isInit());
  auto p = pending_.load(std::memory_order_acquire);
  return doWait(WaitType::CANCEL, p, p, canceled_);
}

Range<AsyncBase::Op**> AsyncBase::pollCompleted() {
  CHECK(isInit());
  CHECK_NE(pollFd_, -1) << "pollCompleted() only allowed on pollable object";
  uint64_t numEvents;
  // This sets the eventFd counter to 0, see
  // http://www.kernel.org/doc/man-pages/online/pages/man2/eventfd.2.html
  ssize_t rc;
  do {
    rc = ::read(pollFd_, &numEvents, 8);
  } while (rc == -1 && errno == EINTR);
  if (UNLIKELY(rc == -1 && errno == EAGAIN)) {
    return Range<Op**>(); // nothing completed
  }
  checkUnixError(rc, "AsyncBase: read from event fd failed");
  DCHECK_EQ(rc, 8);

  DCHECK_GT(numEvents, 0);

  // Don't reap more than pending_, as we've just reset the counter to 0.
  return doWait(WaitType::COMPLETE, 0, pending_.load(), completed_);
}

AsyncBaseQueue::AsyncBaseQueue(AsyncBase* asyncBase) : asyncBase_(asyncBase) {}

AsyncBaseQueue::~AsyncBaseQueue() {
  CHECK_EQ(asyncBase_->pending(), 0);
}

void AsyncBaseQueue::submit(AsyncBaseOp* op) {
  submit([op]() { return op; });
}

void AsyncBaseQueue::submit(OpFactory op) {
  queue_.push_back(op);
  maybeDequeue();
}

void AsyncBaseQueue::onCompleted(AsyncBaseOp* /* op */) {
  maybeDequeue();
}

void AsyncBaseQueue::maybeDequeue() {
  while (!queue_.empty() && asyncBase_->pending() < asyncBase_->capacity()) {
    auto& opFactory = queue_.front();
    auto op = opFactory();
    queue_.pop_front();

    // Interpose our completion callback
    auto nextCb = op->getNotificationCallback();
    op->setNotificationCallback(
        [this, nextCb{std::move(nextCb)}](AsyncBaseOp* op2) mutable {
          this->onCompleted(op2);
          if (nextCb) {
            nextCb(op2);
          }
        });

    asyncBase_->submit(op);
  }
}

// debugging helpers:

namespace {

#define X(c) \
  case c:    \
    return #c

const char* asyncIoOpStateToString(AsyncBaseOp::State state) {
  switch (state) {
    X(AsyncBaseOp::State::UNINITIALIZED);
    X(AsyncBaseOp::State::INITIALIZED);
    X(AsyncBaseOp::State::PENDING);
    X(AsyncBaseOp::State::COMPLETED);
    X(AsyncBaseOp::State::CANCELED);
  }
  return "<INVALID AsyncBaseOp::State>";
}
#undef X
} // namespace

std::ostream& operator<<(std::ostream& os, const AsyncBaseOp& op) {
  op.toStream(os);
  return os;
}

std::ostream& operator<<(std::ostream& os, AsyncBaseOp::State state) {
  return os << asyncIoOpStateToString(state);
}

} // namespace folly
<commit_msg>let AsyncBase build even without eventfd available<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/experimental/io/AsyncBase.h>

#include <cerrno>
#include <ostream>
#include <stdexcept>
#include <string>

#include <boost/intrusive/parent_from_member.hpp>
#include <glog/logging.h>

#include <folly/Exception.h>
#include <folly/Format.h>
#include <folly/Likely.h>
#include <folly/String.h>
#include <folly/portability/Unistd.h>

#if __has_include(<sys/eventfd.h>)
#include <sys/eventfd.h>
#endif

namespace folly {

AsyncBaseOp::AsyncBaseOp(NotificationCallback cb)
    : cb_(std::move(cb)), state_(State::UNINITIALIZED), result_(-EINVAL) {}

void AsyncBaseOp::reset(NotificationCallback cb) {
  CHECK_NE(state_, State::PENDING);
  cb_ = std::move(cb);
  state_ = State::UNINITIALIZED;
  result_ = -EINVAL;
}

AsyncBaseOp::~AsyncBaseOp() {
  CHECK_NE(state_, State::PENDING);
}

void AsyncBaseOp::start() {
  DCHECK_EQ(state_, State::INITIALIZED);
  state_ = State::PENDING;
}

void AsyncBaseOp::unstart() {
  DCHECK_EQ(state_, State::PENDING);
  state_ = State::INITIALIZED;
}

void AsyncBaseOp::complete(ssize_t result) {
  DCHECK_EQ(state_, State::PENDING);
  state_ = State::COMPLETED;
  result_ = result;
  if (cb_) {
    cb_(this);
  }
}

void AsyncBaseOp::cancel() {
  DCHECK_EQ(state_, State::PENDING);
  state_ = State::CANCELED;
}

ssize_t AsyncBaseOp::result() const {
  CHECK_EQ(state_, State::COMPLETED);
  return result_;
}

void AsyncBaseOp::init() {
  CHECK_EQ(state_, State::UNINITIALIZED);
  state_ = State::INITIALIZED;
}

std::string AsyncBaseOp::fd2name(int fd) {
  std::string path = folly::to<std::string>("/proc/self/fd/", fd);
  char link[PATH_MAX];
  const ssize_t length =
      std::max<ssize_t>(readlink(path.c_str(), link, PATH_MAX), 0);
  return path.assign(link, length);
}

AsyncBase::AsyncBase(size_t capacity, PollMode pollMode) : capacity_(capacity) {
  CHECK_GT(capacity_, 0);
  completed_.reserve(capacity_);
  if (pollMode == POLLABLE) {
#if __has_include(<sys/eventfd.h>)
    pollFd_ = eventfd(0, EFD_NONBLOCK);
    checkUnixError(pollFd_, "AsyncBase: eventfd creation failed");
#else
    // fallthrough to not-pollable, observed as: pollFd() == -1
#endif
  }
}

AsyncBase::~AsyncBase() {
  CHECK_EQ(pending_, 0);
  if (pollFd_ != -1) {
    CHECK_ERR(close(pollFd_));
  }
}

void AsyncBase::decrementPending(size_t n) {
  auto p =
      pending_.fetch_add(static_cast<size_t>(-n), std::memory_order_acq_rel);
  DCHECK_GE(p, 1);
}

void AsyncBase::submit(Op* op) {
  CHECK_EQ(op->state(), Op::State::INITIALIZED);
  initializeContext(); // on demand

  // We can increment past capacity, but we'll clean up after ourselves.
  auto p = pending_.fetch_add(1, std::memory_order_acq_rel);
  if (p >= capacity_) {
    decrementPending();
    throw std::range_error("AsyncBase: too many pending requests");
  }

  op->start();
  int rc = submitOne(op);

  if (rc <= 0) {
    op->unstart();
    decrementPending();
    if (rc < 0) {
      throwSystemErrorExplicit(-rc, "AsyncBase: io_submit failed");
    }
  }
  submitted_ += rc;
  DCHECK_EQ(rc, 1);
}

int AsyncBase::submit(Range<Op**> ops) {
  for (auto& op : ops) {
    CHECK_EQ(op->state(), Op::State::INITIALIZED);
    op->start();
  }
  initializeContext(); // on demand

  // We can increment past capacity, but we'll clean up after ourselves.
  auto p = pending_.fetch_add(ops.size(), std::memory_order_acq_rel);
  if (p >= capacity_) {
    decrementPending(ops.size());
    throw std::range_error("AsyncBase: too many pending requests");
  }

  int rc = submitRange(ops);

  if (rc < 0) {
    decrementPending(ops.size());
    throwSystemErrorExplicit(-rc, "AsyncBase: io_submit failed");
  }
  // Any ops that did not get submitted go back to INITIALIZED state
  // and are removed from pending count.
  for (size_t i = rc; i < ops.size(); i++) {
    ops[i]->unstart();
    decrementPending(1);
  }
  submitted_ += rc;
  DCHECK_LE(rc, ops.size());

  return rc;
}

Range<AsyncBase::Op**> AsyncBase::wait(size_t minRequests) {
  CHECK(isInit());
  CHECK_EQ(pollFd_, -1) << "wait() only allowed on non-pollable object";
  auto p = pending_.load(std::memory_order_acquire);
  CHECK_LE(minRequests, p);
  return doWait(WaitType::COMPLETE, minRequests, p, completed_);
}

Range<AsyncBase::Op**> AsyncBase::cancel() {
  CHECK(isInit());
  auto p = pending_.load(std::memory_order_acquire);
  return doWait(WaitType::CANCEL, p, p, canceled_);
}

Range<AsyncBase::Op**> AsyncBase::pollCompleted() {
  CHECK(isInit());
  CHECK_NE(pollFd_, -1) << "pollCompleted() only allowed on pollable object";
  uint64_t numEvents;
  // This sets the eventFd counter to 0, see
  // http://www.kernel.org/doc/man-pages/online/pages/man2/eventfd.2.html
  ssize_t rc;
  do {
    rc = ::read(pollFd_, &numEvents, 8);
  } while (rc == -1 && errno == EINTR);
  if (UNLIKELY(rc == -1 && errno == EAGAIN)) {
    return Range<Op**>(); // nothing completed
  }
  checkUnixError(rc, "AsyncBase: read from event fd failed");
  DCHECK_EQ(rc, 8);

  DCHECK_GT(numEvents, 0);

  // Don't reap more than pending_, as we've just reset the counter to 0.
  return doWait(WaitType::COMPLETE, 0, pending_.load(), completed_);
}

AsyncBaseQueue::AsyncBaseQueue(AsyncBase* asyncBase) : asyncBase_(asyncBase) {}

AsyncBaseQueue::~AsyncBaseQueue() {
  CHECK_EQ(asyncBase_->pending(), 0);
}

void AsyncBaseQueue::submit(AsyncBaseOp* op) {
  submit([op]() { return op; });
}

void AsyncBaseQueue::submit(OpFactory op) {
  queue_.push_back(op);
  maybeDequeue();
}

void AsyncBaseQueue::onCompleted(AsyncBaseOp* /* op */) {
  maybeDequeue();
}

void AsyncBaseQueue::maybeDequeue() {
  while (!queue_.empty() && asyncBase_->pending() < asyncBase_->capacity()) {
    auto& opFactory = queue_.front();
    auto op = opFactory();
    queue_.pop_front();

    // Interpose our completion callback
    auto nextCb = op->getNotificationCallback();
    op->setNotificationCallback(
        [this, nextCb{std::move(nextCb)}](AsyncBaseOp* op2) mutable {
          this->onCompleted(op2);
          if (nextCb) {
            nextCb(op2);
          }
        });

    asyncBase_->submit(op);
  }
}

// debugging helpers:

namespace {

#define X(c) \
  case c:    \
    return #c

const char* asyncIoOpStateToString(AsyncBaseOp::State state) {
  switch (state) {
    X(AsyncBaseOp::State::UNINITIALIZED);
    X(AsyncBaseOp::State::INITIALIZED);
    X(AsyncBaseOp::State::PENDING);
    X(AsyncBaseOp::State::COMPLETED);
    X(AsyncBaseOp::State::CANCELED);
  }
  return "<INVALID AsyncBaseOp::State>";
}
#undef X
} // namespace

std::ostream& operator<<(std::ostream& os, const AsyncBaseOp& op) {
  op.toStream(os);
  return os;
}

std::ostream& operator<<(std::ostream& os, AsyncBaseOp::State state) {
  return os << asyncIoOpStateToString(state);
}

} // namespace folly
<|endoftext|>


<commit_before>/****************************************************************************

This file is part of the QtMediaHub project on http://www.qtmediahub.com

Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Girish Ramakrishnan girish@forwardbias.in
Contact:  Nokia Corporation donald.carr@nokia.com
Contact:  Nokia Corporation johannes.zellner@nokia.com

You may use this file under the terms of the BSD license as follows:

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

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

****************************************************************************/

#include "declarativeview.h"
#include <QGraphicsObject>
#include <QDeclarativeEngine>
#include <QDebug>
#include <QPaintEvent>
#include <QGLWidget>

DeclarativeView::DeclarativeView(QWidget *parent)
    : QDeclarativeView(parent),
      m_frameCount(0),
      m_fps(0)
{
    startTimer(1000);
    connect(this, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(handleStatusChanged(QDeclarativeView::Status)));
}

void DeclarativeView::setSource(const QUrl &url)
{
    m_url = url;
    QMetaObject::invokeMethod(this, "handleSourceChanged", Qt::QueuedConnection);
}

void DeclarativeView::paintEvent(QPaintEvent *event)
{
    bool isGLViewport = qobject_cast<QGLWidget*>(viewport());
    if (window()->property("overlayMode").toBool() && !isGLViewport) {
        QPainter painter(viewport());
        painter.fillRect(event->rect(), Qt::transparent);
    }
    m_frameTimer.restart();
    QDeclarativeView::paintEvent(event);
    m_timeSigma += m_frameTimer.elapsed();
    ++m_frameCount;
}

void DeclarativeView::timerEvent(QTimerEvent *event)
{
    if (m_timeSigma) {
        m_fps = 1000*m_frameCount/m_timeSigma;
        m_timeSigma = m_frameCount = 0;
        emit fpsChanged();
    }
    QDeclarativeView::timerEvent(event);
}

void DeclarativeView::handleSourceChanged()
{
    QDeclarativeView::setSource(m_url);
}

void DeclarativeView::handleStatusChanged(QDeclarativeView::Status status)
{
    if (status == QDeclarativeView::Ready) {
        activateWindow();
    }
}

QObject *DeclarativeView::focusItem() const
{
    return qgraphicsitem_cast<QGraphicsObject *>(scene()->focusItem());
}

int DeclarativeView::fps() const
{
    return m_fps;
}

void DeclarativeView::addImportPath(const QString &path)
{
    engine()->addImportPath(path);
}

<commit_msg>Guard GL usage in view<commit_after>/****************************************************************************

This file is part of the QtMediaHub project on http://www.qtmediahub.com

Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
All rights reserved.

Contact:  Girish Ramakrishnan girish@forwardbias.in
Contact:  Nokia Corporation donald.carr@nokia.com
Contact:  Nokia Corporation johannes.zellner@nokia.com

You may use this file under the terms of the BSD license as follows:

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

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

****************************************************************************/

#include "declarativeview.h"
#include <QGraphicsObject>
#include <QDeclarativeEngine>
#include <QDebug>
#include <QPaintEvent>

#ifdef GL
#include <QGLWidget>
#endif

DeclarativeView::DeclarativeView(QWidget *parent)
    : QDeclarativeView(parent),
      m_frameCount(0),
      m_fps(0)
{
    startTimer(1000);
    connect(this, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(handleStatusChanged(QDeclarativeView::Status)));
}

void DeclarativeView::setSource(const QUrl &url)
{
    m_url = url;
    QMetaObject::invokeMethod(this, "handleSourceChanged", Qt::QueuedConnection);
}

void DeclarativeView::paintEvent(QPaintEvent *event)
{
    static bool isGLViewport
        #ifdef GL
            = qobject_cast<QGLWidget*>(viewport());
        #else
            = false;
        #endif
    if (window()->property("overlayMode").toBool() && !isGLViewport) {
        QPainter painter(viewport());
        painter.fillRect(event->rect(), Qt::transparent);
    }
    m_frameTimer.restart();
    QDeclarativeView::paintEvent(event);
    m_timeSigma += m_frameTimer.elapsed();
    ++m_frameCount;
}

void DeclarativeView::timerEvent(QTimerEvent *event)
{
    if (m_timeSigma) {
        m_fps = 1000*m_frameCount/m_timeSigma;
        m_timeSigma = m_frameCount = 0;
        emit fpsChanged();
    }
    QDeclarativeView::timerEvent(event);
}

void DeclarativeView::handleSourceChanged()
{
    QDeclarativeView::setSource(m_url);
}

void DeclarativeView::handleStatusChanged(QDeclarativeView::Status status)
{
    if (status == QDeclarativeView::Ready) {
        activateWindow();
    }
}

QObject *DeclarativeView::focusItem() const
{
    return qgraphicsitem_cast<QGraphicsObject *>(scene()->focusItem());
}

int DeclarativeView::fps() const
{
    return m_fps;
}

void DeclarativeView::addImportPath(const QString &path)
{
    engine()->addImportPath(path);
}

<|endoftext|>