<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008, 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/binary.hpp"
#include "flusspferd/encodings.hpp"
#include "flusspferd/create.hpp"
#include <iconv.h>
#include <errno.h>
#include <sstream>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace flusspferd;

void flusspferd::load_encodings_module(object container) {
  object exports = container.get_property_object("exports");

  // Load the binary module
  container.call("require", "binary");

  create_native_function(
    exports,
    "convertToString", &encodings::convert_to_string);

  create_native_function(
    exports,
    "convertFromString", &encodings::convert_from_string);

  create_native_function(
    exports,
    "convert", &encodings::convert);

  load_class<encodings::transcoder>(exports);
}

// HELPER METHODS

static char16_t const b1 = *(char16_t*)"\xff\xfe";
static char16_t const b2 = 0xfffe;

static char const * const native_charset = b1 == b2 ? "utf-16be" : "utf-16le";

// JAVASCRIPT METHODS

flusspferd::string
encodings::convert_to_string(std::string const &enc_, binary &source_binary) {
  transcoder &trans =
    create_native_object<transcoder>(object(), enc_, native_charset);
  root_object root_obj(trans);

  trans.push_accumulate(source_binary);

  binary &out = trans.close(boost::none);

  return flusspferd::string(
    reinterpret_cast<char16_t const *>(&out.get_data()[0]),
    out.get_length() / sizeof(char16_t));
}

object encodings::convert_from_string(std::string const &enc, string const &str)
{
  transcoder &trans =
    create_native_object<transcoder>(object(), native_charset, enc);
  root_object root_obj(trans);

  binary &source_binary = create_native_object<byte_string>(
    object(),
    reinterpret_cast<binary::element_type const *>(str.data()),
    str.size() * sizeof(char16_t));
  root_object root_obj2(source_binary);

  trans.push_accumulate(source_binary);

  return trans.close(boost::none);
}

object encodings::convert(
  std::string const &from_, std::string const &to_, binary &source_binary)
{
  transcoder &trans =
    create_native_object<transcoder>(object(), from_, to_);
  root_object root_obj(trans);

  trans.push_accumulate(source_binary);

  return trans.close(boost::none);
}

// TRANSCODER

class encodings::transcoder::impl {
public:
  impl()
  : conv(iconv_t(-1))
  {}

  ~impl() {
    if (conv != iconv_t(-1))
      iconv_close(conv);
  }

  binary::vector_type accumulator;
  binary::vector_type multibyte_part;

  iconv_t conv;
};

void encodings::transcoder::trace(tracer &trc) {
}

encodings::transcoder::transcoder(object const &obj, call_context &x)
: base_type(obj)
{
  init(x.arg[0].to_std_string(), x.arg[1].to_std_string());
}

encodings::transcoder::transcoder(
  object const &obj, std::string const &from, std::string const &to)
: base_type(obj)
{
  init(from, to);
}

encodings::transcoder::~transcoder() {
}

void encodings::transcoder::init(std::string const &from, std::string const &to)
{
  boost::scoped_ptr<impl> p(new impl);

  define_property(
    "sourceCharset",
    flusspferd::value(from),
    property_attributes(read_only_property | permanent_property));

  define_property(
    "destinationCharset",
    flusspferd::value(to),
    property_attributes(read_only_property | permanent_property));

  p->conv = iconv_open(to.c_str(), from.c_str());

  if (p->conv == iconv_t(-1))
    throw exception("Could not create Transcoder with iconv");

  this->p.swap(p);
}

binary &encodings::transcoder::push(
  binary &input, boost::optional<byte_array&> const &output_)
{
  binary &output = get_output_binary(output_);

  root_object root_obj(output);

  append_accumulator(output);
  do_push(input, output.get_data());

  return output;
}

void encodings::transcoder::push_accumulate(binary &input) {
  do_push(input, p->accumulator);
}

binary &encodings::transcoder::close(
  boost::optional<byte_array&> const &output_)
{
  if (!p->multibyte_part.empty())
    throw exception("Invalid multibyte sequence at the end of input");

  binary &output = get_output_binary(output_);

  root_object root_obj(output);

  append_accumulator(output);

  if (p->conv != iconv_t(-1)) {
    binary::vector_type &out_v = output.get_data();
    std::size_t start = out_v.size();
    // 32 bytes should suffice for the initial state shift
    std::size_t outlen = 32;
    out_v.resize(out_v.size() + outlen);
    char *outbuf = reinterpret_cast<char*>(&out_v[start]);
    if (iconv(p->conv, 0, 0, &outbuf, &outlen) == std::size_t(-1))
      throw exception("Adding closing character sequence failed");
    out_v.resize(out_v.size() - outlen);

    if (iconv_close(p->conv) == -1)
      throw exception("Closing character set conversion descriptor failed");

    p->conv = iconv_t(-1);
  }

  return output;
}

binary &encodings::transcoder::get_output_binary(
  boost::optional<byte_array&> const &output_)
{
  return
    output_
    ? static_cast<binary&>(output_.get())
    : static_cast<binary&>(
        create_native_object<byte_string>(
          object(),
          (byte_string::element_type*)0,
          0));
}

void encodings::transcoder::do_push(binary &input, binary::vector_type &out_v) {
  binary::vector_type &in_v =
    p->multibyte_part.empty() ? input.get_data() : p->multibyte_part;

  if (!p->multibyte_part.empty())
    in_v.insert(in_v.end(), input.get_data().begin(), input.get_data().end());

  // A rough guess how much space might be needed for the new characters.
  std::size_t out_estimate = in_v.size() + in_v.size()/16 + 32;

  std::size_t out_start = out_v.size();

  for (;;) {
    out_v.resize(out_v.size() + out_estimate);

    char *inbuf = reinterpret_cast<char*>(&in_v[0]);
    char *outbuf = reinterpret_cast<char*>(&out_v[out_start]);

    std::size_t inbytesleft = in_v.size();
    std::size_t outbytesleft = out_estimate;

    std::size_t n_chars = iconv(
      p->conv,
      &inbuf, &inbytesleft,
      &outbuf, &outbytesleft);

    if (n_chars == std::size_t(-1)) {
      switch (errno) {
      case EILSEQ:
        throw exception("Invalid multi-byte sequence in input");

      case E2BIG:
        out_v.resize(out_v.size() - out_estimate);
        out_estimate *= 2;
        break;

      case EINVAL:
        p->multibyte_part.assign(outbuf, outbuf + outbytesleft);
        out_v.resize(out_v.size() - outbytesleft);
        return;

      default:
        throw exception("Unknown error in character conversion");
      }
    } else {
      out_v.resize(out_v.size() - outbytesleft);
      return;
    }
  }
}

void encodings::transcoder::append_accumulator(binary &output) {
  binary::vector_type &out_v = output.get_data();

  if (!p->accumulator.empty()) {
    if (!out_v.empty()) {
      out_v.insert(out_v.end(), p->accumulator.begin(), p->accumulator.end());
      binary::vector_type().swap(p->accumulator);
    } else {
      out_v.swap(p->accumulator);
    }
  }
}
<commit_msg>encodings: use utf-8 as the native charset because the utf-16 code had undefined behavior and alignment issues<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008, 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/binary.hpp"
#include "flusspferd/encodings.hpp"
#include "flusspferd/create.hpp"
#include <iconv.h>
#include <errno.h>
#include <sstream>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace flusspferd;

void flusspferd::load_encodings_module(object container) {
  object exports = container.get_property_object("exports");

  // Load the binary module
  container.call("require", "binary");

  create_native_function(
    exports,
    "convertToString", &encodings::convert_to_string);

  create_native_function(
    exports,
    "convertFromString", &encodings::convert_from_string);

  create_native_function(
    exports,
    "convert", &encodings::convert);

  load_class<encodings::transcoder>(exports);
}

// HELPER METHODS

// JAVASCRIPT METHODS

flusspferd::string
encodings::convert_to_string(std::string const &enc_, binary &source_binary) {
  transcoder &trans =
    create_native_object<transcoder>(object(), enc_, "utf-8");
  root_object root_obj(trans);

  trans.push_accumulate(source_binary);

  binary &out = trans.close(boost::none);

  return flusspferd::string(
    reinterpret_cast<char const *>(&out.get_data()[0]),
    out.get_length());
}

object encodings::convert_from_string(std::string const &enc, string const &str)
{
  transcoder &trans =
    create_native_object<transcoder>(object(), "utf-8", enc);
  root_object root_obj(trans);

  binary &source_binary = create_native_object<byte_string>(
    object(),
    reinterpret_cast<binary::element_type const *>(str.c_str()),
    std::strlen(str.c_str()));
  root_object root_obj2(source_binary);

  trans.push_accumulate(source_binary);

  return trans.close(boost::none);
}

object encodings::convert(
  std::string const &from_, std::string const &to_, binary &source_binary)
{
  transcoder &trans =
    create_native_object<transcoder>(object(), from_, to_);
  root_object root_obj(trans);

  trans.push_accumulate(source_binary);

  return trans.close(boost::none);
}

// TRANSCODER

class encodings::transcoder::impl {
public:
  impl()
  : conv(iconv_t(-1))
  {}

  ~impl() {
    if (conv != iconv_t(-1))
      iconv_close(conv);
  }

  binary::vector_type accumulator;
  binary::vector_type multibyte_part;

  iconv_t conv;
};

void encodings::transcoder::trace(tracer &trc) {
}

encodings::transcoder::transcoder(object const &obj, call_context &x)
: base_type(obj)
{
  init(x.arg[0].to_std_string(), x.arg[1].to_std_string());
}

encodings::transcoder::transcoder(
  object const &obj, std::string const &from, std::string const &to)
: base_type(obj)
{
  init(from, to);
}

encodings::transcoder::~transcoder() {
}

void encodings::transcoder::init(std::string const &from, std::string const &to)
{
  boost::scoped_ptr<impl> p(new impl);

  define_property(
    "sourceCharset",
    flusspferd::value(from),
    property_attributes(read_only_property | permanent_property));

  define_property(
    "destinationCharset",
    flusspferd::value(to),
    property_attributes(read_only_property | permanent_property));

  p->conv = iconv_open(to.c_str(), from.c_str());

  if (p->conv == iconv_t(-1))
    throw exception("Could not create Transcoder with iconv");

  this->p.swap(p);
}

binary &encodings::transcoder::push(
  binary &input, boost::optional<byte_array&> const &output_)
{
  binary &output = get_output_binary(output_);

  root_object root_obj(output);

  append_accumulator(output);
  do_push(input, output.get_data());

  return output;
}

void encodings::transcoder::push_accumulate(binary &input) {
  do_push(input, p->accumulator);
}

binary &encodings::transcoder::close(
  boost::optional<byte_array&> const &output_)
{
  if (!p->multibyte_part.empty())
    throw exception("Invalid multibyte sequence at the end of input");

  binary &output = get_output_binary(output_);

  root_object root_obj(output);

  append_accumulator(output);

  if (p->conv != iconv_t(-1)) {
    binary::vector_type &out_v = output.get_data();
    std::size_t start = out_v.size();
    // 32 bytes should suffice for the initial state shift
    std::size_t outlen = 32;
    out_v.resize(out_v.size() + outlen);
    char *outbuf = reinterpret_cast<char*>(&out_v[start]);
    if (iconv(p->conv, 0, 0, &outbuf, &outlen) == std::size_t(-1))
      throw exception("Adding closing character sequence failed");
    out_v.resize(out_v.size() - outlen);

    if (iconv_close(p->conv) == -1)
      throw exception("Closing character set conversion descriptor failed");

    p->conv = iconv_t(-1);
  }

  return output;
}

binary &encodings::transcoder::get_output_binary(
  boost::optional<byte_array&> const &output_)
{
  return
    output_
    ? static_cast<binary&>(output_.get())
    : static_cast<binary&>(
        create_native_object<byte_string>(
          object(),
          (byte_string::element_type*)0,
          0));
}

void encodings::transcoder::do_push(binary &input, binary::vector_type &out_v) {
  binary::vector_type &in_v =
    p->multibyte_part.empty() ? input.get_data() : p->multibyte_part;

  if (!p->multibyte_part.empty())
    in_v.insert(in_v.end(), input.get_data().begin(), input.get_data().end());

  // A rough guess how much space might be needed for the new characters.
  std::size_t out_estimate = in_v.size() + in_v.size()/16 + 32;

  std::size_t out_start = out_v.size();

  for (;;) {
    out_v.resize(out_v.size() + out_estimate);

    char *inbuf = reinterpret_cast<char*>(&in_v[0]);
    char *outbuf = reinterpret_cast<char*>(&out_v[out_start]);

    std::size_t inbytesleft = in_v.size();
    std::size_t outbytesleft = out_estimate;

    std::size_t n_chars = iconv(
      p->conv,
      &inbuf, &inbytesleft,
      &outbuf, &outbytesleft);

    if (n_chars == std::size_t(-1)) {
      switch (errno) {
      case EILSEQ:
        throw exception("Invalid multi-byte sequence in input");

      case E2BIG:
        out_v.resize(out_v.size() - out_estimate);
        out_estimate *= 2;
        break;

      case EINVAL:
        p->multibyte_part.assign(outbuf, outbuf + outbytesleft);
        out_v.resize(out_v.size() - outbytesleft);
        return;

      default:
        throw exception("Unknown error in character conversion");
      }
    } else {
      out_v.resize(out_v.size() - outbytesleft);
      return;
    }
  }
}

void encodings::transcoder::append_accumulator(binary &output) {
  binary::vector_type &out_v = output.get_data();

  if (!p->accumulator.empty()) {
    if (!out_v.empty()) {
      out_v.insert(out_v.end(), p->accumulator.begin(), p->accumulator.end());
      binary::vector_type().swap(p->accumulator);
    } else {
      out_v.swap(p->accumulator);
    }
  }
}
<|endoftext|>


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

#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/background/background_contents_service.h"
#include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/base/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

class AppBackgroundPageApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisablePopupBlocking);
    command_line->AppendSwitch(switches::kAllowHTTPBackgroundPage);
  }

  bool CreateApp(const std::string& app_manifest,
                 FilePath* app_dir) {
    if (!app_dir_.CreateUniqueTempDir()) {
      LOG(ERROR) << "Unable to create a temporary directory.";
      return false;
    }
    FilePath manifest_path = app_dir_.path().AppendASCII("manifest.json");
    int bytes_written = file_util::WriteFile(manifest_path,
                                             app_manifest.data(),
                                             app_manifest.size());
    if (bytes_written != static_cast<int>(app_manifest.size())) {
      LOG(ERROR) << "Unable to write complete manifest to file. Return code="
                 << bytes_written;
      return false;
    }
    *app_dir = app_dir_.path();
    return true;
  }

 private:
  ScopedTempDir app_dir_;
};

// Disable on Mac only.  http://crbug.com/95139
#if defined(OS_MACOSX)
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, MAYBE_Basic) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"permissions\": [\"background\"]"
      "}",
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/basic")) << message_;
}

// Crashy, http://crbug.com/69215.
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_LacksPermission) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  }"
      "}",
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/lacks_permission"))
      << message_;
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, ManifestBackgroundPage) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"permissions\": [\"background\"],"
      "  \"background_page\": \"http://a.com:%d/test.html\""
      "}",
      test_server()->host_port_pair().port(),
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));

  const Extension* extension = GetSingleLoadedExtension();
  ASSERT_TRUE(
      BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
          GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoBackgroundPages) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"permissions\": [\"background\"]"
      "}",
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/two_pages")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoPagesWithManifest) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"background_page\": \"http://a.com:%d/bg.html\","
      "  \"permissions\": [\"background\"]"
      "}",
      test_server()->host_port_pair().port(),
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/two_with_manifest")) <<
      message_;
}
<commit_msg>Update these tests to use manifest_version 2.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/background/background_contents_service.h"
#include "chrome/browser/background/background_contents_service_factory.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/base/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

class AppBackgroundPageApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisablePopupBlocking);
    command_line->AppendSwitch(switches::kAllowHTTPBackgroundPage);
  }

  bool CreateApp(const std::string& app_manifest,
                 FilePath* app_dir) {
    if (!app_dir_.CreateUniqueTempDir()) {
      LOG(ERROR) << "Unable to create a temporary directory.";
      return false;
    }
    FilePath manifest_path = app_dir_.path().AppendASCII("manifest.json");
    int bytes_written = file_util::WriteFile(manifest_path,
                                             app_manifest.data(),
                                             app_manifest.size());
    if (bytes_written != static_cast<int>(app_manifest.size())) {
      LOG(ERROR) << "Unable to write complete manifest to file. Return code="
                 << bytes_written;
      return false;
    }
    *app_dir = app_dir_.path();
    return true;
  }

 private:
  ScopedTempDir app_dir_;
};

// Disable on Mac only.  http://crbug.com/95139
#if defined(OS_MACOSX)
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, MAYBE_Basic) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"manifest_version\": 2,"
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"permissions\": [\"background\"]"
      "}",
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/basic")) << message_;
}

// Crashy, http://crbug.com/69215.
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_LacksPermission) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"manifest_version\": 2,"
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  }"
      "}",
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/lacks_permission"))
      << message_;
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, ManifestBackgroundPage) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"manifest_version\": 2,"
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"permissions\": [\"background\"],"
      "  \"background_page\": \"http://a.com:%d/test.html\""
      "}",
      test_server()->host_port_pair().port(),
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));

  const Extension* extension = GetSingleLoadedExtension();
  ASSERT_TRUE(
      BackgroundContentsServiceFactory::GetForProfile(browser()->profile())->
          GetAppBackgroundContents(ASCIIToUTF16(extension->id())));
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoBackgroundPages) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"manifest_version\": 2,"
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"permissions\": [\"background\"]"
      "}",
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/two_pages")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, OpenTwoPagesWithManifest) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(StartTestServer());

  std::string app_manifest = base::StringPrintf(
      "{"
      "  \"name\": \"App\","
      "  \"version\": \"0.1\","
      "  \"manifest_version\": 2,"
      "  \"app\": {"
      "    \"urls\": ["
      "      \"http://a.com/\""
      "    ],"
      "    \"launch\": {"
      "      \"web_url\": \"http://a.com:%d/\""
      "    }"
      "  },"
      "  \"background_page\": \"http://a.com:%d/bg.html\","
      "  \"permissions\": [\"background\"]"
      "}",
      test_server()->host_port_pair().port(),
      test_server()->host_port_pair().port());

  FilePath app_dir;
  ASSERT_TRUE(CreateApp(app_manifest, &app_dir));
  ASSERT_TRUE(LoadExtension(app_dir));
  ASSERT_TRUE(RunExtensionTest("app_background_page/two_with_manifest")) <<
      message_;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// CoinVault
//
// createtxdialogview.cpp
//
// Copyright (c) 2013 Eric Lombrozo
//
// All Rights Reserved.

#include "createtxdialog.h"
#include "numberformats.h"
#include "currencyvalidator.h"

#include "settings.h"
#include "coinparams.h"

#include <stdutils/uchar_vector.h>
#include <CoinQ/CoinQ_script.h>

#include <QDialogButtonBox>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QComboBox>
#include <QLineEdit>
#include <QLabel>

#include <QMessageBox>

#include <stdexcept>

TxOutLayout::TxOutLayout(uint64_t currencyDivisor, const QString& currencySymbol, uint64_t currencyMax, unsigned int currencyDecimals, QWidget* parent)
    : QHBoxLayout(parent)
{
    // Base58 version bytes
    base58_versions[0] = getCoinParams().pay_to_pubkey_hash_version();
    base58_versions[1] = getCoinParams().pay_to_script_hash_version();

    // Coin parameters
    this->currencyDivisor = currencyDivisor;
    this->currencySymbol = currencySymbol;
    this->currencyMax = currencyMax;
    this->currencyDecimals = currencyDecimals;

    QLabel* addressLabel = new QLabel(tr("Address:"));
    addressEdit = new QLineEdit();
    addressEdit->setFixedWidth(300);

    QLabel* amountLabel = new QLabel(tr("Amount") + " (" + currencySymbol + "):");
    amountEdit = new QLineEdit();
    amountEdit->setFixedWidth(100);
    amountEdit->setValidator(new CurrencyValidator(currencyMax, currencyDecimals, this));

    QLabel* recipientLabel = new QLabel(tr("For:"));
    recipientEdit = new QLineEdit();
    recipientEdit->setFixedWidth(100);

    removeButton = new QPushButton(tr("Remove"));

    setSizeConstraint(QLayout::SetFixedSize);
    addWidget(addressLabel);
    addWidget(addressEdit);
    addWidget(amountLabel);
    addWidget(amountEdit);
    addWidget(recipientLabel);
    addWidget(recipientEdit);
    addWidget(removeButton);
}

inline void TxOutLayout::setAddress(const QString& address)
{
    addressEdit->setText(address);
}

inline QString TxOutLayout::getAddress() const
{
    return addressEdit->text();
}

bytes_t TxOutLayout::getScript() const
{
    bytes_t script = CoinQ::Script::getTxOutScriptForAddress(getAddress().toStdString(), base58_versions);
    return script;
}

void TxOutLayout::setValue(uint64_t value)
{
    amountEdit->setText(QString::number(value/(1.0 * currencyDivisor), 'g', 8));
}

uint64_t TxOutLayout::getValue() const
{
    return decimalStringToInteger(amountEdit->text().toStdString(), currencyMax, currencyDivisor, currencyDecimals);
}

// TODO: call this field the label rather than the recipient
void TxOutLayout::setRecipient(const QString& recipient)
{
    recipientEdit->setText(recipient);
}

inline QString TxOutLayout::getRecipient() const
{
    return recipientEdit->text();
}

void TxOutLayout::removeWidgets()
{
    while(!isEmpty()) {
        delete itemAt(0)->widget();
    }
}

CreateTxDialog::CreateTxDialog(const QString& accountName, const PaymentRequest& paymentRequest, QWidget* parent)
    : QDialog(parent), status(SAVE_ONLY)
{
    // Coin parameters
    currencyDivisor = getCoinParams().currency_divisor();
    currencySymbol = getCoinParams().currency_symbol();
    currencyMax = getCoinParams().currency_max();
    currencyDecimals = getCoinParams().currency_decimals();

    // Buttons
    signAndSendButton = new QPushButton(tr("Sign and Send"));
    signAndSaveButton = new QPushButton(tr("Sign and Save"));
    saveButton = new QPushButton(tr("Save Unsigned"));
    cancelButton = new QPushButton(tr("Cancel"));
    cancelButton->setDefault(true);
/*
    QDialogButtonBox* buttonBox = new QDialogButtonBox(
                                        QDialogButtonBox::Ok |
                                        QDialogButtonBox::Cancel);

*/
    QDialogButtonBox* buttonBox = new QDialogButtonBox;
    buttonBox->addButton(signAndSendButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(signAndSaveButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(saveButton, QDialogButtonBox::AcceptRole);
    buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole);

    connect(signAndSendButton, &QPushButton::clicked, [this]() { status = SIGN_AND_SEND; accept(); });
    connect(signAndSaveButton, &QPushButton::clicked, [this]() { status = SIGN_AND_SAVE; accept(); });
    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

    // Prompt
    QLabel* promptLabel = new QLabel(tr("Add Outputs:"));

    // Account
    QLabel* accountLabel = new QLabel(tr("Account:"));
    accountComboBox = new QComboBox();
    accountComboBox->insertItem(0, accountName);

    QHBoxLayout* accountLayout = new QHBoxLayout();
    accountLayout->addWidget(accountLabel);
    accountLayout->addWidget(accountComboBox);

    // Fee
    QLabel* feeLabel = new QLabel(tr("Fee") + " (" + currencySymbol + "):");
    feeEdit = new QLineEdit();
    feeEdit->setValidator(new CurrencyValidator(currencyMax, currencyDecimals, this));
    feeEdit->setText("0.0005"); // TODO: suggest more intelligently

    QHBoxLayout* feeLayout = new QHBoxLayout();
    feeLayout->addWidget(feeLabel);
    feeLayout->addWidget(feeEdit);

    // TxOuts
    txOutVBoxLayout = new QVBoxLayout();
    txOutVBoxLayout->setSizeConstraint(QLayout::SetMinimumSize);
    addTxOut(paymentRequest);

    // Add Output Button
    QPushButton* addTxOutButton = new QPushButton(tr("Add Output"));
    connect(addTxOutButton, SIGNAL(clicked()), this, SLOT(addTxOut()));

    mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(promptLabel);
    mainLayout->addLayout(accountLayout);
    mainLayout->addLayout(feeLayout);
    mainLayout->addLayout(txOutVBoxLayout);
    mainLayout->addWidget(addTxOutButton);
    mainLayout->addWidget(buttonBox);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(mainLayout);
}

QString CreateTxDialog::getAccountName() const
{
    return accountComboBox->currentText();
}

uint64_t CreateTxDialog::getFeeValue() const
{
    return decimalStringToInteger(feeEdit->text().toStdString(), currencyMax, currencyDivisor, currencyDecimals);
}

std::vector<std::shared_ptr<CoinDB::TxOut>> CreateTxDialog::getTxOuts()
{
    std::vector<std::shared_ptr<CoinDB::TxOut>> txouts;
    std::set<TxOutLayout*> txOutLayoutsCopy = txOutLayouts;
    for (auto& txOutLayout: txOutLayoutsCopy) {
        if (txOutLayout->getAddress().isEmpty()) {
            removeTxOut(txOutLayout);
            continue;
        }
        std::shared_ptr<CoinDB::TxOut> txout(new CoinDB::TxOut(txOutLayout->getValue(), txOutLayout->getScript()));
        txout->sending_label(txOutLayout->getRecipient().toStdString());
        txouts.push_back(txout);
    }

    if (txouts.empty()) {
        addTxOut();
        throw std::runtime_error("No outputs entered.");
    }
    return txouts;
}

std::vector<TaggedOutput> CreateTxDialog::getOutputs()
{
    std::vector<TaggedOutput> outputs;
    std::set<TxOutLayout*> txOutLayoutsCopy = txOutLayouts;
    for (auto& txOutLayout: txOutLayoutsCopy) {
        if (txOutLayout->getAddress().isEmpty()) {
            removeTxOut(txOutLayout);
            continue;
        }
        TaggedOutput output(txOutLayout->getScript(), txOutLayout->getValue(), txOutLayout->getRecipient().toStdString());
        outputs.push_back(output);
    }

    if (outputs.empty()) {
        addTxOut();
        throw std::runtime_error("No outputs entered.");
    }
    return outputs;
}

void CreateTxDialog::addTxOut(const PaymentRequest& paymentRequest)
{
    TxOutLayout* txOutLayout = new TxOutLayout(currencyDivisor, currencySymbol, currencyMax, currencyDecimals);
    txOutLayouts.insert(txOutLayout);
    setRemoveEnabled(txOutLayouts.size() > 1);
    QPushButton* removeButton = txOutLayout->getRemoveButton();
    connect(removeButton, &QPushButton::clicked, [=]() { this->removeTxOut(txOutLayout); });
    txOutVBoxLayout->addLayout(txOutLayout);

    if (paymentRequest.hasAddress()) {
        txOutLayout->setAddress(paymentRequest.address());
    }

    if (paymentRequest.hasValue()) {
        txOutLayout->setValue(paymentRequest.value());
    }

    if (paymentRequest.hasLabel()) {
        txOutLayout->setRecipient(paymentRequest.label());
    }
}

void CreateTxDialog::removeTxOut(TxOutLayout* txOutLayout)
{
    txOutLayouts.erase(txOutLayout);
    setRemoveEnabled(txOutLayouts.size() > 1);
    txOutLayout->removeWidgets();
    txOutVBoxLayout->removeItem(txOutLayout);
    delete txOutLayout;
}

void CreateTxDialog::setRemoveEnabled(bool enabled)
{
    for (auto& layout: txOutLayouts)
    {
        layout->getRemoveButton()->setEnabled(enabled);
    }
}

<commit_msg>Right-align amount input in CreateTxDialog.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// CoinVault
//
// createtxdialogview.cpp
//
// Copyright (c) 2013 Eric Lombrozo
//
// All Rights Reserved.

#include "createtxdialog.h"
#include "numberformats.h"
#include "currencyvalidator.h"

#include "settings.h"
#include "coinparams.h"

#include <stdutils/uchar_vector.h>
#include <CoinQ/CoinQ_script.h>

#include <QDialogButtonBox>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QComboBox>
#include <QLineEdit>
#include <QLabel>

#include <QMessageBox>

#include <stdexcept>

TxOutLayout::TxOutLayout(uint64_t currencyDivisor, const QString& currencySymbol, uint64_t currencyMax, unsigned int currencyDecimals, QWidget* parent)
    : QHBoxLayout(parent)
{
    // Base58 version bytes
    base58_versions[0] = getCoinParams().pay_to_pubkey_hash_version();
    base58_versions[1] = getCoinParams().pay_to_script_hash_version();

    // Coin parameters
    this->currencyDivisor = currencyDivisor;
    this->currencySymbol = currencySymbol;
    this->currencyMax = currencyMax;
    this->currencyDecimals = currencyDecimals;

    QLabel* addressLabel = new QLabel(tr("Address:"));
    addressEdit = new QLineEdit();
    addressEdit->setFixedWidth(300);

    QLabel* amountLabel = new QLabel(tr("Amount") + " (" + currencySymbol + "):");
    amountEdit = new QLineEdit();
    amountEdit->setFixedWidth(100);
    amountEdit->setAlignment(Qt::AlignRight);
    amountEdit->setValidator(new CurrencyValidator(currencyMax, currencyDecimals, this));

    QLabel* recipientLabel = new QLabel(tr("For:"));
    recipientEdit = new QLineEdit();
    recipientEdit->setFixedWidth(100);

    removeButton = new QPushButton(tr("Remove"));

    setSizeConstraint(QLayout::SetFixedSize);
    addWidget(addressLabel);
    addWidget(addressEdit);
    addWidget(amountLabel);
    addWidget(amountEdit);
    addWidget(recipientLabel);
    addWidget(recipientEdit);
    addWidget(removeButton);
}

inline void TxOutLayout::setAddress(const QString& address)
{
    addressEdit->setText(address);
}

inline QString TxOutLayout::getAddress() const
{
    return addressEdit->text();
}

bytes_t TxOutLayout::getScript() const
{
    bytes_t script = CoinQ::Script::getTxOutScriptForAddress(getAddress().toStdString(), base58_versions);
    return script;
}

void TxOutLayout::setValue(uint64_t value)
{
    amountEdit->setText(QString::number(value/(1.0 * currencyDivisor), 'g', 8));
}

uint64_t TxOutLayout::getValue() const
{
    return decimalStringToInteger(amountEdit->text().toStdString(), currencyMax, currencyDivisor, currencyDecimals);
}

// TODO: call this field the label rather than the recipient
void TxOutLayout::setRecipient(const QString& recipient)
{
    recipientEdit->setText(recipient);
}

inline QString TxOutLayout::getRecipient() const
{
    return recipientEdit->text();
}

void TxOutLayout::removeWidgets()
{
    while(!isEmpty()) {
        delete itemAt(0)->widget();
    }
}

CreateTxDialog::CreateTxDialog(const QString& accountName, const PaymentRequest& paymentRequest, QWidget* parent)
    : QDialog(parent), status(SAVE_ONLY)
{
    // Coin parameters
    currencyDivisor = getCoinParams().currency_divisor();
    currencySymbol = getCoinParams().currency_symbol();
    currencyMax = getCoinParams().currency_max();
    currencyDecimals = getCoinParams().currency_decimals();

    // Buttons
    signAndSendButton = new QPushButton(tr("Sign and Send"));
    signAndSaveButton = new QPushButton(tr("Sign and Save"));
    saveButton = new QPushButton(tr("Save Unsigned"));
    cancelButton = new QPushButton(tr("Cancel"));
    cancelButton->setDefault(true);
/*
    QDialogButtonBox* buttonBox = new QDialogButtonBox(
                                        QDialogButtonBox::Ok |
                                        QDialogButtonBox::Cancel);

*/
    QDialogButtonBox* buttonBox = new QDialogButtonBox;
    buttonBox->addButton(signAndSendButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(signAndSaveButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(saveButton, QDialogButtonBox::AcceptRole);
    buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole);

    connect(signAndSendButton, &QPushButton::clicked, [this]() { status = SIGN_AND_SEND; accept(); });
    connect(signAndSaveButton, &QPushButton::clicked, [this]() { status = SIGN_AND_SAVE; accept(); });
    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));

    // Prompt
    QLabel* promptLabel = new QLabel(tr("Add Outputs:"));

    // Account
    QLabel* accountLabel = new QLabel(tr("Account:"));
    accountComboBox = new QComboBox();
    accountComboBox->insertItem(0, accountName);

    QHBoxLayout* accountLayout = new QHBoxLayout();
    accountLayout->addWidget(accountLabel);
    accountLayout->addWidget(accountComboBox);

    // Fee
    QLabel* feeLabel = new QLabel(tr("Fee") + " (" + currencySymbol + "):");
    feeEdit = new QLineEdit();
    feeEdit->setValidator(new CurrencyValidator(currencyMax, currencyDecimals, this));
    feeEdit->setText("0.0005"); // TODO: suggest more intelligently

    QHBoxLayout* feeLayout = new QHBoxLayout();
    feeLayout->addWidget(feeLabel);
    feeLayout->addWidget(feeEdit);

    // TxOuts
    txOutVBoxLayout = new QVBoxLayout();
    txOutVBoxLayout->setSizeConstraint(QLayout::SetMinimumSize);
    addTxOut(paymentRequest);

    // Add Output Button
    QPushButton* addTxOutButton = new QPushButton(tr("Add Output"));
    connect(addTxOutButton, SIGNAL(clicked()), this, SLOT(addTxOut()));

    mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(promptLabel);
    mainLayout->addLayout(accountLayout);
    mainLayout->addLayout(feeLayout);
    mainLayout->addLayout(txOutVBoxLayout);
    mainLayout->addWidget(addTxOutButton);
    mainLayout->addWidget(buttonBox);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(mainLayout);
}

QString CreateTxDialog::getAccountName() const
{
    return accountComboBox->currentText();
}

uint64_t CreateTxDialog::getFeeValue() const
{
    return decimalStringToInteger(feeEdit->text().toStdString(), currencyMax, currencyDivisor, currencyDecimals);
}

std::vector<std::shared_ptr<CoinDB::TxOut>> CreateTxDialog::getTxOuts()
{
    std::vector<std::shared_ptr<CoinDB::TxOut>> txouts;
    std::set<TxOutLayout*> txOutLayoutsCopy = txOutLayouts;
    for (auto& txOutLayout: txOutLayoutsCopy) {
        if (txOutLayout->getAddress().isEmpty()) {
            removeTxOut(txOutLayout);
            continue;
        }
        std::shared_ptr<CoinDB::TxOut> txout(new CoinDB::TxOut(txOutLayout->getValue(), txOutLayout->getScript()));
        txout->sending_label(txOutLayout->getRecipient().toStdString());
        txouts.push_back(txout);
    }

    if (txouts.empty()) {
        addTxOut();
        throw std::runtime_error("No outputs entered.");
    }
    return txouts;
}

std::vector<TaggedOutput> CreateTxDialog::getOutputs()
{
    std::vector<TaggedOutput> outputs;
    std::set<TxOutLayout*> txOutLayoutsCopy = txOutLayouts;
    for (auto& txOutLayout: txOutLayoutsCopy) {
        if (txOutLayout->getAddress().isEmpty()) {
            removeTxOut(txOutLayout);
            continue;
        }
        TaggedOutput output(txOutLayout->getScript(), txOutLayout->getValue(), txOutLayout->getRecipient().toStdString());
        outputs.push_back(output);
    }

    if (outputs.empty()) {
        addTxOut();
        throw std::runtime_error("No outputs entered.");
    }
    return outputs;
}

void CreateTxDialog::addTxOut(const PaymentRequest& paymentRequest)
{
    TxOutLayout* txOutLayout = new TxOutLayout(currencyDivisor, currencySymbol, currencyMax, currencyDecimals);
    txOutLayouts.insert(txOutLayout);
    setRemoveEnabled(txOutLayouts.size() > 1);
    QPushButton* removeButton = txOutLayout->getRemoveButton();
    connect(removeButton, &QPushButton::clicked, [=]() { this->removeTxOut(txOutLayout); });
    txOutVBoxLayout->addLayout(txOutLayout);

    if (paymentRequest.hasAddress()) {
        txOutLayout->setAddress(paymentRequest.address());
    }

    if (paymentRequest.hasValue()) {
        txOutLayout->setValue(paymentRequest.value());
    }

    if (paymentRequest.hasLabel()) {
        txOutLayout->setRecipient(paymentRequest.label());
    }
}

void CreateTxDialog::removeTxOut(TxOutLayout* txOutLayout)
{
    txOutLayouts.erase(txOutLayout);
    setRemoveEnabled(txOutLayouts.size() > 1);
    txOutLayout->removeWidgets();
    txOutVBoxLayout->removeItem(txOutLayout);
    delete txOutLayout;
}

void CreateTxDialog::setRemoveEnabled(bool enabled)
{
    for (auto& layout: txOutLayouts)
    {
        layout->getRemoveButton()->setEnabled(enabled);
    }
}

<|endoftext|>


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

#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script didn't run.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'Unmodified')",
      &result);
  EXPECT_TRUE(result);
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Load a dummy extension. This just tests that we don't regress a
  // crash fix when multiple incognito- and non-incognito-enabled extensions
  // are mixed.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("all_frames")));

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Dummy extension #2.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("isolated_world1")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script ran.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'modified')",
      &result);
  EXPECT_TRUE(result);
}

// Tests that the APIs in an incognito-enabled extension work properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-enabled split-mode extension work
// properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoSplitMode) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // We need 2 ResultCatchers because we'll be running the same test in both
  // regular and incognito mode.
  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToProfile(
      browser()->profile()->GetOffTheRecordProfile());

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("split")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
// Hangy, http://crbug.com/53869.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoDisabled) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtension(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis_disabled")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("popup")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* incognito_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);

  // Simulate the incognito's browser action being clicked.
  BrowserActionTestUtil(incognito_browser).Press(0);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<commit_msg>Re-disable IncognitoSplitMode. It still fails/hangs periodically (though more rare at least).<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script didn't run.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'Unmodified')",
      &result);
  EXPECT_TRUE(result);
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Load a dummy extension. This just tests that we don't regress a
  // crash fix when multiple incognito- and non-incognito-enabled extensions
  // are mixed.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("all_frames")));

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Dummy extension #2.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("isolated_world1")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script ran.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'modified')",
      &result);
  EXPECT_TRUE(result);
}

// Tests that the APIs in an incognito-enabled extension work properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-enabled split-mode extension work
// properly.
// Hangy, http://crbug.com/53991.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoSplitMode) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // We need 2 ResultCatchers because we'll be running the same test in both
  // regular and incognito mode.
  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToProfile(
      browser()->profile()->GetOffTheRecordProfile());

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("split")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
// Hangy, http://crbug.com/53869.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoDisabled) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtension(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis_disabled")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("popup")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* incognito_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);

  // Simulate the incognito's browser action being clicked.
  BrowserActionTestUtil(incognito_browser).Press(0);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<|endoftext|>


<commit_before>#include <ctime>
#include <iostream>
#include <cstdlib>
#include <iterator>

#include <dariadb.h>
#include <utils/fs.h>
#include <ctime>
#include <limits>
#include <cmath>
#include <chrono>
#include <thread>
#include <random>
#include <cstdlib>
#include <atomic>
#include <cassert>

class BenchCallback :public dariadb::storage::ReaderClb {
public:
    BenchCallback()=default;
	void call(const dariadb::Meas&m) {
		if (m.flag != dariadb::Flags::NO_DATA) {
			count++;
		}
		else {
			count_ig++;
		}
	}
	size_t count;
	size_t count_ig;
};

void writer_1(dariadb::storage::BaseStorage_ptr ms)
{
	auto m = dariadb::Meas::empty();
	dariadb::Time t = dariadb::timeutil::current_time();
	for (dariadb::Id i = 0; i < 32768; i += 1) {
		m.id = i;
		m.flag = dariadb::Flag(0);
		m.time = t;
		m.value = dariadb::Value(i);
		ms->append(m);
		t++;
	}
}

std::atomic_long writen{ 0 };

void writer_2(dariadb::Id id_from, size_t id_per_thread, dariadb::storage::BaseStorage_ptr ms)
{
	auto m = dariadb::Meas::empty();
	std::random_device r;
	std::default_random_engine e1(r());
	std::uniform_int_distribution<int> uniform_dist(10, 64);

    size_t max_id=(id_from + id_per_thread);

    for (dariadb::Id i = id_from; i < max_id; i += 1) {
		dariadb::Value v = 1.0;
        m.id = i;
        m.flag = dariadb::Flag(0);
        auto max_rnd = uniform_dist(e1);
        m.time = dariadb::timeutil::current_time();
		for (dariadb::Time p = 0; p < dariadb::Time(max_rnd); p++) {
            m.time+=10;
			m.value = v;
			ms->append(m);
			writen++;
			auto rnd = rand() / float(RAND_MAX);

			v += rnd;
		}

	}
}

int main(int argc, char *argv[]) {
	(void)argc;
	(void)argv;
	srand(static_cast<unsigned int>(time(NULL)));

	const std::string storage_path = "testStorage";
	const size_t chunk_per_storage = 1024 * 1024;
	const size_t chunk_size = 256;
	const size_t cap_max_size = 100;
	const dariadb::Time write_window_deep = 5000;
	const dariadb::Time old_mem_chunks = 0;
	const size_t max_mem_chunks = 0;

    {// 1.
        if (dariadb::utils::fs::path_exists(storage_path)) {
            dariadb::utils::fs::rm(storage_path);
        }

        auto raw_ptr = new dariadb::storage::UnionStorage(
            dariadb::storage::PageManager::Params(storage_path, dariadb::storage::MODE::SINGLE, chunk_per_storage, chunk_size),
            dariadb::storage::Capacitor::Params(cap_max_size, write_window_deep),
            dariadb::storage::UnionStorage::Limits(old_mem_chunks, max_mem_chunks));
        dariadb::storage::BaseStorage_ptr ms{ raw_ptr };
        auto start = clock();

        writer_1(ms);

        auto elapsed = ((float)clock() - start) / CLOCKS_PER_SEC;
        std::cout << "1. insert : " << elapsed << std::endl;
    }

	if (dariadb::utils::fs::path_exists(storage_path)) {
		dariadb::utils::fs::rm(storage_path);
	}

	auto raw_ptr_ds = new dariadb::storage::UnionStorage(
		dariadb::storage::PageManager::Params(storage_path, dariadb::storage::MODE::SINGLE, chunk_per_storage, chunk_size),
		dariadb::storage::Capacitor::Params(cap_max_size, write_window_deep),
		dariadb::storage::UnionStorage::Limits(old_mem_chunks, max_mem_chunks));
	dariadb::storage::BaseStorage_ptr ms{ raw_ptr_ds };

	{// 2.
        const size_t threads_count = 16;
		const size_t id_per_thread = size_t(32768 / threads_count);

		auto start = clock();
		std::vector<std::thread> writers(threads_count);
		size_t pos = 0;
        for (size_t i = 0; i < threads_count; i++) {
            std::thread t{ writer_2, id_per_thread*i+1, id_per_thread, ms};
			writers[pos++] = std::move(t);
		}

		pos = 0;
		for (size_t i = 0; i < threads_count; i++) {
			std::thread t = std::move(writers[pos++]);
			t.join();
		}

		auto elapsed = ((float)clock() - start) / CLOCKS_PER_SEC;
		std::cout << "2. insert : " << elapsed << std::endl;
		raw_ptr_ds->flush();
	}
    auto queue_sizes = raw_ptr_ds->queue_size();
    std::cout
        << "\rin memory chunks: " << raw_ptr_ds->chunks_in_memory()
        << " in disk chunks: " << dariadb::storage::PageManager::instance()->chunks_in_cur_page()
        << " in queue: (p:" << queue_sizes.page << " m:" << queue_sizes.mem << " cap:" << queue_sizes.cap << ")"
        << " pooled: " << dariadb::storage::ChunkPool::instance()->polled()
        << std::endl;
    {
        auto ids=ms->getIds();
        std::cout << "ids.size:"<<ids.size() << std::endl;
        std::cout << "read all..." << std::endl;
        std::shared_ptr<BenchCallback> clbk{ new BenchCallback() };
        auto start = clock();
        ms->readInterval(0,ms->maxTime())->readAll(clbk.get());

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC);
        std::cout << "readed: " << clbk->count << std::endl;
        std::cout << "time: " << elapsed << std::endl;
    }
    {//3

        std::random_device r;
        std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Id> uniform_dist(1, 32767);
        dariadb::IdArray ids;
        ids.resize(1);

        const size_t queries_count = 32768;

        dariadb::IdArray rnd_ids(queries_count);
        std::vector<dariadb::Time> rnd_time(queries_count);
        for (size_t i = 0; i < queries_count; i++) {
            rnd_ids[i] = uniform_dist(e1);
            dariadb::Time minT,maxT;
            assert(raw_ptr_ds->minMaxTime(rnd_ids[i],&minT,&maxT));
            std::uniform_int_distribution<dariadb::Time> uniform_dist_tmp(minT,maxT);
            rnd_time[i] = uniform_dist_tmp(e1);
        }
        auto raw_ptr = new BenchCallback();
        dariadb::storage::ReaderClb_ptr clbk{ raw_ptr };

        auto start = clock();

        for (size_t i = 0; i < queries_count; i++) {
            ids[0]= rnd_ids[i];
            auto t = rnd_time[i];
            auto rdr=ms->readInTimePoint(ids,0,t);
            rdr->readAll(clbk.get());
        }

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC)/ queries_count;
        std::cout << "3. time point: " << elapsed<< " readed: "<< raw_ptr->count << std::endl;
    }
    {//4
        std::random_device r;
        std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Id> uniform_dist(raw_ptr_ds->minTime(), dariadb::timeutil::current_time());

        const size_t queries_count = 1;

        dariadb::IdArray ids;
        std::vector<dariadb::Time> rnd_time(queries_count);
        for (size_t i = 0; i < queries_count; i++){
            rnd_time[i]=uniform_dist(e1);
        }
        auto raw_ptr = new BenchCallback();
        dariadb::storage::ReaderClb_ptr clbk{raw_ptr};

        auto start = clock();

        for (size_t i = 0; i < queries_count; i++) {
            auto t = rnd_time[i];
            auto rdr = ms->readInTimePoint(ids, 0, t);
            rdr->readAll(clbk.get());
        }

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC) / queries_count;
        std::cout << "4. time point: " << elapsed << " readed: " << raw_ptr->count << std::endl;
    }

    {//5
        std::random_device r;
        std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Time> uniform_dist(raw_ptr_ds->minTime(), dariadb::timeutil::current_time());

        auto raw_ptr = new BenchCallback();
        dariadb::storage::ReaderClb_ptr clbk{ raw_ptr };
        const size_t queries_count = 1;

        std::vector<dariadb::Time> rnd_time_from(queries_count),rnd_time_to(queries_count);
        for (size_t i = 0; i < queries_count; i++){
            rnd_time_from[i]=uniform_dist(e1);
            rnd_time_to[i]=uniform_dist(e1);
        }

        auto start = clock();

        for (size_t i = 0; i < queries_count; i++) {
            auto f = std::min(rnd_time_from[i],rnd_time_to[i]);
            auto t = std::max(rnd_time_from[i],rnd_time_to[i]);
            auto rdr = ms->readInterval(f, t);
            rdr->readAll(clbk.get());
        }

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC) / queries_count;
        std::cout << "5. interval: " << elapsed << " readed: " << raw_ptr->count << std::endl;
    }

	{//6
		std::random_device r;
		std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Time> uniform_dist(raw_ptr_ds->minTime(), dariadb::timeutil::current_time());
		std::uniform_int_distribution<dariadb::Id> uniform_dist_id(1, 32767);

		const size_t ids_count = size_t(32768 * 0.1);
		dariadb::IdArray ids;
		ids.resize(ids_count);

		auto raw_ptr = new BenchCallback();
		dariadb::storage::ReaderClb_ptr clbk{ raw_ptr };
        const size_t queries_count = 1;

        std::vector<dariadb::Time> rnd_time_from(queries_count),rnd_time_to(queries_count);
        for (size_t i = 0; i < queries_count; i++){
            rnd_time_from[i]=uniform_dist(e1);
            rnd_time_to[i]=uniform_dist(e1);
        }

		auto start = clock();

		for (size_t i = 0; i < queries_count; i++) {
			for (size_t j = 0; j < ids_count; j++) {
				ids[j] = uniform_dist_id(e1);
			}
            auto f = std::min(rnd_time_from[i],rnd_time_to[i]);
            auto t = std::max(rnd_time_from[i],rnd_time_to[i]);
            auto rdr = ms->readInterval(ids,0, f, t );
			rdr->readAll(clbk.get());
		}

		auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC) / queries_count;
		std::cout << "6. interval: " << elapsed << " readed: " << raw_ptr->count << std::endl;
	}

	ms = nullptr;

	if (dariadb::utils::fs::path_exists(storage_path)) {
		dariadb::utils::fs::rm(storage_path);
	}
}
<commit_msg>msvc build.<commit_after>#include <ctime>
#include <iostream>
#include <cstdlib>
#include <iterator>

#include <dariadb.h>
#include <utils/fs.h>
#include <ctime>
#include <limits>
#include <cmath>
#include <chrono>
#include <thread>
#include <random>
#include <cstdlib>
#include <atomic>
#include <cassert>
#include <algorithm>

class BenchCallback :public dariadb::storage::ReaderClb {
public:
    BenchCallback()=default;
	void call(const dariadb::Meas&m) {
		if (m.flag != dariadb::Flags::NO_DATA) {
			count++;
		}
		else {
			count_ig++;
		}
	}
	size_t count;
	size_t count_ig;
};

void writer_1(dariadb::storage::BaseStorage_ptr ms)
{
	auto m = dariadb::Meas::empty();
	dariadb::Time t = dariadb::timeutil::current_time();
	for (dariadb::Id i = 0; i < 32768; i += 1) {
		m.id = i;
		m.flag = dariadb::Flag(0);
		m.time = t;
		m.value = dariadb::Value(i);
		ms->append(m);
		t++;
	}
}

std::atomic_long writen{ 0 };

void writer_2(dariadb::Id id_from, size_t id_per_thread, dariadb::storage::BaseStorage_ptr ms)
{
	auto m = dariadb::Meas::empty();
	std::random_device r;
	std::default_random_engine e1(r());
	std::uniform_int_distribution<int> uniform_dist(10, 64);

    size_t max_id=(id_from + id_per_thread);

    for (dariadb::Id i = id_from; i < max_id; i += 1) {
		dariadb::Value v = 1.0;
        m.id = i;
        m.flag = dariadb::Flag(0);
        auto max_rnd = uniform_dist(e1);
        m.time = dariadb::timeutil::current_time();
		for (dariadb::Time p = 0; p < dariadb::Time(max_rnd); p++) {
            m.time+=10;
			m.value = v;
			ms->append(m);
			writen++;
			auto rnd = rand() / float(RAND_MAX);

			v += rnd;
		}

	}
}

int main(int argc, char *argv[]) {
	(void)argc;
	(void)argv;
	srand(static_cast<unsigned int>(time(NULL)));

	const std::string storage_path = "testStorage";
	const size_t chunk_per_storage = 1024 * 1024;
	const size_t chunk_size = 256;
	const size_t cap_max_size = 100;
	const dariadb::Time write_window_deep = 5000;
	const dariadb::Time old_mem_chunks = 0;
	const size_t max_mem_chunks = 0;

    {// 1.
        if (dariadb::utils::fs::path_exists(storage_path)) {
            dariadb::utils::fs::rm(storage_path);
        }

        auto raw_ptr = new dariadb::storage::UnionStorage(
            dariadb::storage::PageManager::Params(storage_path, dariadb::storage::MODE::SINGLE, chunk_per_storage, chunk_size),
            dariadb::storage::Capacitor::Params(cap_max_size, write_window_deep),
            dariadb::storage::UnionStorage::Limits(old_mem_chunks, max_mem_chunks));
        dariadb::storage::BaseStorage_ptr ms{ raw_ptr };
        auto start = clock();

        writer_1(ms);

        auto elapsed = ((float)clock() - start) / CLOCKS_PER_SEC;
        std::cout << "1. insert : " << elapsed << std::endl;
    }

	if (dariadb::utils::fs::path_exists(storage_path)) {
		dariadb::utils::fs::rm(storage_path);
	}

	auto raw_ptr_ds = new dariadb::storage::UnionStorage(
		dariadb::storage::PageManager::Params(storage_path, dariadb::storage::MODE::SINGLE, chunk_per_storage, chunk_size),
		dariadb::storage::Capacitor::Params(cap_max_size, write_window_deep),
		dariadb::storage::UnionStorage::Limits(old_mem_chunks, max_mem_chunks));
	dariadb::storage::BaseStorage_ptr ms{ raw_ptr_ds };

	{// 2.
        const size_t threads_count = 16;
		const size_t id_per_thread = size_t(32768 / threads_count);

		auto start = clock();
		std::vector<std::thread> writers(threads_count);
		size_t pos = 0;
        for (size_t i = 0; i < threads_count; i++) {
            std::thread t{ writer_2, id_per_thread*i+1, id_per_thread, ms};
			writers[pos++] = std::move(t);
		}

		pos = 0;
		for (size_t i = 0; i < threads_count; i++) {
			std::thread t = std::move(writers[pos++]);
			t.join();
		}

		auto elapsed = ((float)clock() - start) / CLOCKS_PER_SEC;
		std::cout << "2. insert : " << elapsed << std::endl;
		raw_ptr_ds->flush();
	}
    auto queue_sizes = raw_ptr_ds->queue_size();
    std::cout
        << "\rin memory chunks: " << raw_ptr_ds->chunks_in_memory()
        << " in disk chunks: " << dariadb::storage::PageManager::instance()->chunks_in_cur_page()
        << " in queue: (p:" << queue_sizes.page << " m:" << queue_sizes.mem << " cap:" << queue_sizes.cap << ")"
        << " pooled: " << dariadb::storage::ChunkPool::instance()->polled()
        << std::endl;
    {
        auto ids=ms->getIds();
        std::cout << "ids.size:"<<ids.size() << std::endl;
        std::cout << "read all..." << std::endl;
        std::shared_ptr<BenchCallback> clbk{ new BenchCallback() };
        auto start = clock();
        ms->readInterval(0,ms->maxTime())->readAll(clbk.get());

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC);
        std::cout << "readed: " << clbk->count << std::endl;
        std::cout << "time: " << elapsed << std::endl;
    }
    {//3

        std::random_device r;
        std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Id> uniform_dist(1, 32767);
        dariadb::IdArray ids;
        ids.resize(1);

        const size_t queries_count = 32768;

        dariadb::IdArray rnd_ids(queries_count);
        std::vector<dariadb::Time> rnd_time(queries_count);
        for (size_t i = 0; i < queries_count; i++) {
            rnd_ids[i] = uniform_dist(e1);
            dariadb::Time minT,maxT;
            assert(raw_ptr_ds->minMaxTime(rnd_ids[i],&minT,&maxT));
            std::uniform_int_distribution<dariadb::Time> uniform_dist_tmp(minT,maxT);
            rnd_time[i] = uniform_dist_tmp(e1);
        }
        auto raw_ptr = new BenchCallback();
        dariadb::storage::ReaderClb_ptr clbk{ raw_ptr };

        auto start = clock();

        for (size_t i = 0; i < queries_count; i++) {
            ids[0]= rnd_ids[i];
            auto t = rnd_time[i];
            auto rdr=ms->readInTimePoint(ids,0,t);
            rdr->readAll(clbk.get());
        }

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC)/ queries_count;
        std::cout << "3. time point: " << elapsed<< " readed: "<< raw_ptr->count << std::endl;
    }
    {//4
        std::random_device r;
        std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Id> uniform_dist(raw_ptr_ds->minTime(), dariadb::timeutil::current_time());

        const size_t queries_count = 1;

        dariadb::IdArray ids;
        std::vector<dariadb::Time> rnd_time(queries_count);
        for (size_t i = 0; i < queries_count; i++){
            rnd_time[i]=uniform_dist(e1);
        }
        auto raw_ptr = new BenchCallback();
        dariadb::storage::ReaderClb_ptr clbk{raw_ptr};

        auto start = clock();

        for (size_t i = 0; i < queries_count; i++) {
            auto t = rnd_time[i];
            auto rdr = ms->readInTimePoint(ids, 0, t);
            rdr->readAll(clbk.get());
        }

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC) / queries_count;
        std::cout << "4. time point: " << elapsed << " readed: " << raw_ptr->count << std::endl;
    }

    {//5
        std::random_device r;
        std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Time> uniform_dist(raw_ptr_ds->minTime(), dariadb::timeutil::current_time());

        auto raw_ptr = new BenchCallback();
        dariadb::storage::ReaderClb_ptr clbk{ raw_ptr };
        const size_t queries_count = 1;

        std::vector<dariadb::Time> rnd_time_from(queries_count),rnd_time_to(queries_count);
        for (size_t i = 0; i < queries_count; i++){
            rnd_time_from[i]=uniform_dist(e1);
            rnd_time_to[i]=uniform_dist(e1);
        }

        auto start = clock();

        for (size_t i = 0; i < queries_count; i++) {
            auto f = std::min(rnd_time_from[i],rnd_time_to[i]);
            auto t = std::max(rnd_time_from[i],rnd_time_to[i]);
            auto rdr = ms->readInterval(f, t);
            rdr->readAll(clbk.get());
        }

        auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC) / queries_count;
        std::cout << "5. interval: " << elapsed << " readed: " << raw_ptr->count << std::endl;
    }

	{//6
		std::random_device r;
		std::default_random_engine e1(r());
        std::uniform_int_distribution<dariadb::Time> uniform_dist(raw_ptr_ds->minTime(), dariadb::timeutil::current_time());
		std::uniform_int_distribution<dariadb::Id> uniform_dist_id(1, 32767);

		const size_t ids_count = size_t(32768 * 0.1);
		dariadb::IdArray ids;
		ids.resize(ids_count);

		auto raw_ptr = new BenchCallback();
		dariadb::storage::ReaderClb_ptr clbk{ raw_ptr };
        const size_t queries_count = 1;

        std::vector<dariadb::Time> rnd_time_from(queries_count),rnd_time_to(queries_count);
        for (size_t i = 0; i < queries_count; i++){
            rnd_time_from[i]=uniform_dist(e1);
            rnd_time_to[i]=uniform_dist(e1);
        }

		auto start = clock();

		for (size_t i = 0; i < queries_count; i++) {
			for (size_t j = 0; j < ids_count; j++) {
				ids[j] = uniform_dist_id(e1);
			}
            auto f = std::min(rnd_time_from[i],rnd_time_to[i]);
            auto t = std::max(rnd_time_from[i],rnd_time_to[i]);
            auto rdr = ms->readInterval(ids,0, f, t );
			rdr->readAll(clbk.get());
		}

		auto elapsed = (((float)clock() - start) / CLOCKS_PER_SEC) / queries_count;
		std::cout << "6. interval: " << elapsed << " readed: " << raw_ptr->count << std::endl;
	}

	ms = nullptr;

	if (dariadb::utils::fs::path_exists(storage_path)) {
		dariadb::utils::fs::rm(storage_path);
	}
}
<|endoftext|>


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

#include "base/path_service.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

#if defined(OS_MACOSX)
// WebSocket test started timing out - suspect webkit roll from 67965->68051.
// http://crbug.com/56596
#define MAYBE_WebSocket DISABLED_WebSocket
#else
#define MAYBE_WebSocket WebSocket
#endif
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_WebSocket) {
  FilePath websocket_root_dir;
  PathService::Get(chrome::DIR_TEST_DATA, &websocket_root_dir);
  websocket_root_dir = websocket_root_dir.AppendASCII("layout_tests")
      .AppendASCII("LayoutTests");
  ui_test_utils::TestWebSocketServer server(websocket_root_dir);
  ASSERT_TRUE(RunExtensionTest("websocket")) << message_;
}
<commit_msg>Disable ExtensionApiTest.WebSocket<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/path_service.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

#if defined(OS_MACOSX)
// WebSocket test started timing out - suspect webkit roll from 67965->68051.
// http://crbug.com/56596
#define MAYBE_WebSocket DISABLED_WebSocket
#else
#define MAYBE_WebSocket WebSocket
#endif
// This test is disabled because of http://crbug.com/57662.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WebSocket) {
  FilePath websocket_root_dir;
  PathService::Get(chrome::DIR_TEST_DATA, &websocket_root_dir);
  websocket_root_dir = websocket_root_dir.AppendASCII("layout_tests")
      .AppendASCII("LayoutTests");
  ui_test_utils::TestWebSocketServer server(websocket_root_dir);
  ASSERT_TRUE(RunExtensionTest("websocket")) << message_;
}
<|endoftext|>


<commit_before>#include "seat.hpp"
#include "wayfire/opengl.hpp"
#include "../core-impl.hpp"
#include "touch.hpp"
#include "input-manager.hpp"
#include "wayfire/render-manager.hpp"
#include "wayfire/output-layout.hpp"
#include <wayfire/util/log.hpp>
#include "wayfire/signal-definitions.hpp"

extern "C"
{
#include <wlr/backend/libinput.h>
}

wf_drag_icon::wf_drag_icon(wlr_drag_icon *ic) :
    wf::wlr_child_surface_base_t(this), icon(ic)
{
    on_map.set_callback([&] (void*) { this->map(icon->surface); });
    on_unmap.set_callback([&] (void*) { this->unmap(); });
    on_destroy.set_callback([&] (void*)
    {
        /* we don't dec_keep_count() because the surface memory is
         * managed by the unique_ptr */
        wf::dnd_signal data;
        data.icon = wf::get_core_impl().input->drag_icon.get();
        wf::get_core().emit_signal("drag-stopped", &data);
        wf::get_core_impl().input->drag_icon = nullptr;
    });

    on_map.connect(&icon->events.map);
    on_unmap.connect(&icon->events.unmap);
    on_destroy.connect(&icon->events.destroy);
}

wf::point_t wf_drag_icon::get_offset()
{
    auto pos = icon->drag->grab_type == WLR_DRAG_GRAB_KEYBOARD_TOUCH ?
        wf::get_core().get_touch_position(icon->drag->touch_id) :
        wf::get_core().get_cursor_position();

    if (is_mapped())
    {
        pos.x += icon->surface->sx;
        pos.y += icon->surface->sy;
    }

    return {(int)pos.x, (int)pos.y};
}

void wf_drag_icon::damage()
{
    // damage previous position
    damage_surface_box_global(last_box);

    // damage new position
    last_box = {0, 0, get_size().width, get_size().height};
    last_box = last_box + get_offset();
    damage_surface_box_global(last_box);
}

void wf_drag_icon::damage_surface_box(const wlr_box& box)
{
    if (!is_mapped())
    {
        return;
    }

    damage_surface_box_global(box + this->get_offset());
}

void wf_drag_icon::damage_surface_box_global(const wlr_box& rect)
{
    for (auto& output : wf::get_core().output_layout->get_outputs())
    {
        auto output_geometry = output->get_layout_geometry();
        if (output_geometry & rect)
        {
            auto local = rect;
            local.x -= output_geometry.x;
            local.y -= output_geometry.y;
            output->render->damage(local);
        }
    }
}

void input_manager::validate_drag_request(wlr_seat_request_start_drag_event *ev)
{
    auto seat = wf::get_core().get_current_seat();

    if (wlr_seat_validate_pointer_grab_serial(seat, ev->origin, ev->serial))
    {
        wlr_seat_start_pointer_drag(seat, ev->drag, ev->serial);

        return;
    }

    struct wlr_touch_point *point;
    if (wlr_seat_validate_touch_grab_serial(seat, ev->origin, ev->serial, &point))
    {
        wlr_seat_start_touch_drag(seat, ev->drag, ev->serial, point);

        return;
    }

    LOGD("Ignoring start_drag request: ",
        "could not validate pointer or touch serial ", ev->serial);
    wlr_data_source_destroy(ev->drag->source);
}

void input_manager::update_drag_icon()
{
    if (drag_icon && drag_icon->is_mapped())
    {
        drag_icon->damage();
    }
}

void input_manager::create_seat()
{
    seat     = wlr_seat_create(wf::get_core().display, "default");
    cursor   = std::make_unique<wf_cursor>();
    lpointer = std::make_unique<wf::LogicalPointer>(
        nonstd::make_observer(this));

    touch = std::make_unique<wf::touch_interface_t>(cursor->cursor, seat,
        [this] (wf::pointf_t global, wf::pointf_t& local)
    {
        return this->input_surface_at(global, local);
    });

    request_set_cursor.set_callback([&] (void *data)
    {
        auto ev = static_cast<wlr_seat_pointer_request_set_cursor_event*>(data);
        wf::get_core_impl().input->cursor->set_cursor(ev, true);
    });
    request_set_cursor.connect(&seat->events.request_set_cursor);

    request_start_drag.set_callback([&] (void *data)
    {
        auto ev = static_cast<wlr_seat_request_start_drag_event*>(data);
        validate_drag_request(ev);
    });
    request_start_drag.connect(&seat->events.request_start_drag);

    start_drag.set_callback([&] (void *data)
    {
        auto d = static_cast<wlr_drag*>(data);
        wf::get_core_impl().input->drag_icon =
            std::make_unique<wf_drag_icon>(d->icon);

        wf::dnd_signal evdata;
        evdata.icon = wf::get_core_impl().input->drag_icon.get();
        wf::get_core().emit_signal("drag-started", &evdata);
    });
    start_drag.connect(&seat->events.start_drag);

    request_set_selection.set_callback([&] (void *data)
    {
        auto ev = static_cast<wlr_seat_request_set_selection_event*>(data);
        wlr_seat_set_selection(wf::get_core().get_current_seat(),
            ev->source, ev->serial);
    });
    request_set_selection.connect(&seat->events.request_set_selection);

    request_set_primary_selection.set_callback([&] (void *data)
    {
        auto ev =
            static_cast<wlr_seat_request_set_primary_selection_event*>(data);
        wlr_seat_set_primary_selection(wf::get_core().get_current_seat(),
            ev->source, ev->serial);
    });
    request_set_primary_selection.connect(
        &seat->events.request_set_primary_selection);
}

namespace wf
{
wlr_input_device*input_device_t::get_wlr_handle()
{
    return handle;
}

bool input_device_t::set_enabled(bool enabled)
{
    if (enabled == is_enabled())
    {
        return true;
    }

    if (!wlr_input_device_is_libinput(handle))
    {
        return false;
    }

    auto dev = wlr_libinput_get_device_handle(handle);
    assert(dev);

    libinput_device_config_send_events_set_mode(dev,
        enabled ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED :
        LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);

    return true;
}

bool input_device_t::is_enabled()
{
    /* Currently no support for enabling/disabling non-libinput devices */
    if (!wlr_input_device_is_libinput(handle))
    {
        return true;
    }

    auto dev = wlr_libinput_get_device_handle(handle);
    assert(dev);

    auto mode = libinput_device_config_send_events_get_mode(dev);

    return mode == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}

input_device_t::input_device_t(wlr_input_device *handle)
{
    this->handle = handle;
}
}

wf_input_device_internal::wf_input_device_internal(wlr_input_device *dev) :
    wf::input_device_t(dev)
{
    on_destroy.set_callback([&] (void*)
    {
        wf::get_core_impl().input->handle_input_destroyed(this->get_wlr_handle());
    });
    on_destroy.connect(&dev->events.destroy);
}

wf::pointf_t get_surface_relative_coords(wf::surface_interface_t *surface,
    const wf::pointf_t& point)
{
    auto og    = surface->get_output()->get_layout_geometry();
    auto local = point;
    local.x -= og.x;
    local.y -= og.y;

    auto view =
        dynamic_cast<wf::view_interface_t*>(surface->get_main_surface());

    return view->global_to_local_point(local, surface);
}
<commit_msg>seat: do not assume drag will always have an icon<commit_after>#include "seat.hpp"
#include "wayfire/opengl.hpp"
#include "../core-impl.hpp"
#include "touch.hpp"
#include "input-manager.hpp"
#include "wayfire/render-manager.hpp"
#include "wayfire/output-layout.hpp"
#include <wayfire/util/log.hpp>
#include "wayfire/signal-definitions.hpp"

extern "C"
{
#include <wlr/backend/libinput.h>
}

wf_drag_icon::wf_drag_icon(wlr_drag_icon *ic) :
    wf::wlr_child_surface_base_t(this), icon(ic)
{
    on_map.set_callback([&] (void*) { this->map(icon->surface); });
    on_unmap.set_callback([&] (void*) { this->unmap(); });
    on_destroy.set_callback([&] (void*)
    {
        /* we don't dec_keep_count() because the surface memory is
         * managed by the unique_ptr */
        wf::dnd_signal data;
        data.icon = wf::get_core_impl().input->drag_icon.get();
        wf::get_core().emit_signal("drag-stopped", &data);
        wf::get_core_impl().input->drag_icon = nullptr;
    });

    on_map.connect(&icon->events.map);
    on_unmap.connect(&icon->events.unmap);
    on_destroy.connect(&icon->events.destroy);
}

wf::point_t wf_drag_icon::get_offset()
{
    auto pos = icon->drag->grab_type == WLR_DRAG_GRAB_KEYBOARD_TOUCH ?
        wf::get_core().get_touch_position(icon->drag->touch_id) :
        wf::get_core().get_cursor_position();

    if (is_mapped())
    {
        pos.x += icon->surface->sx;
        pos.y += icon->surface->sy;
    }

    return {(int)pos.x, (int)pos.y};
}

void wf_drag_icon::damage()
{
    // damage previous position
    damage_surface_box_global(last_box);

    // damage new position
    last_box = {0, 0, get_size().width, get_size().height};
    last_box = last_box + get_offset();
    damage_surface_box_global(last_box);
}

void wf_drag_icon::damage_surface_box(const wlr_box& box)
{
    if (!is_mapped())
    {
        return;
    }

    damage_surface_box_global(box + this->get_offset());
}

void wf_drag_icon::damage_surface_box_global(const wlr_box& rect)
{
    for (auto& output : wf::get_core().output_layout->get_outputs())
    {
        auto output_geometry = output->get_layout_geometry();
        if (output_geometry & rect)
        {
            auto local = rect;
            local.x -= output_geometry.x;
            local.y -= output_geometry.y;
            output->render->damage(local);
        }
    }
}

void input_manager::validate_drag_request(wlr_seat_request_start_drag_event *ev)
{
    auto seat = wf::get_core().get_current_seat();

    if (wlr_seat_validate_pointer_grab_serial(seat, ev->origin, ev->serial))
    {
        wlr_seat_start_pointer_drag(seat, ev->drag, ev->serial);

        return;
    }

    struct wlr_touch_point *point;
    if (wlr_seat_validate_touch_grab_serial(seat, ev->origin, ev->serial, &point))
    {
        wlr_seat_start_touch_drag(seat, ev->drag, ev->serial, point);

        return;
    }

    LOGD("Ignoring start_drag request: ",
        "could not validate pointer or touch serial ", ev->serial);
    wlr_data_source_destroy(ev->drag->source);
}

void input_manager::update_drag_icon()
{
    if (drag_icon && drag_icon->is_mapped())
    {
        drag_icon->damage();
    }
}

void input_manager::create_seat()
{
    seat     = wlr_seat_create(wf::get_core().display, "default");
    cursor   = std::make_unique<wf_cursor>();
    lpointer = std::make_unique<wf::LogicalPointer>(
        nonstd::make_observer(this));

    touch = std::make_unique<wf::touch_interface_t>(cursor->cursor, seat,
        [this] (wf::pointf_t global, wf::pointf_t& local)
    {
        return this->input_surface_at(global, local);
    });

    request_set_cursor.set_callback([&] (void *data)
    {
        auto ev = static_cast<wlr_seat_pointer_request_set_cursor_event*>(data);
        wf::get_core_impl().input->cursor->set_cursor(ev, true);
    });
    request_set_cursor.connect(&seat->events.request_set_cursor);

    request_start_drag.set_callback([&] (void *data)
    {
        auto ev = static_cast<wlr_seat_request_start_drag_event*>(data);
        validate_drag_request(ev);
    });
    request_start_drag.connect(&seat->events.request_start_drag);

    start_drag.set_callback([&] (void *data)
    {
        auto d = static_cast<wlr_drag*>(data);
        if (d->icon)
        {
            wf::get_core_impl().input->drag_icon =
                std::make_unique<wf_drag_icon>(d->icon);
        }

        wf::dnd_signal evdata;
        evdata.icon = wf::get_core_impl().input->drag_icon.get();
        wf::get_core().emit_signal("drag-started", &evdata);
    });
    start_drag.connect(&seat->events.start_drag);

    request_set_selection.set_callback([&] (void *data)
    {
        auto ev = static_cast<wlr_seat_request_set_selection_event*>(data);
        wlr_seat_set_selection(wf::get_core().get_current_seat(),
            ev->source, ev->serial);
    });
    request_set_selection.connect(&seat->events.request_set_selection);

    request_set_primary_selection.set_callback([&] (void *data)
    {
        auto ev =
            static_cast<wlr_seat_request_set_primary_selection_event*>(data);
        wlr_seat_set_primary_selection(wf::get_core().get_current_seat(),
            ev->source, ev->serial);
    });
    request_set_primary_selection.connect(
        &seat->events.request_set_primary_selection);
}

namespace wf
{
wlr_input_device*input_device_t::get_wlr_handle()
{
    return handle;
}

bool input_device_t::set_enabled(bool enabled)
{
    if (enabled == is_enabled())
    {
        return true;
    }

    if (!wlr_input_device_is_libinput(handle))
    {
        return false;
    }

    auto dev = wlr_libinput_get_device_handle(handle);
    assert(dev);

    libinput_device_config_send_events_set_mode(dev,
        enabled ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED :
        LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);

    return true;
}

bool input_device_t::is_enabled()
{
    /* Currently no support for enabling/disabling non-libinput devices */
    if (!wlr_input_device_is_libinput(handle))
    {
        return true;
    }

    auto dev = wlr_libinput_get_device_handle(handle);
    assert(dev);

    auto mode = libinput_device_config_send_events_get_mode(dev);

    return mode == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
}

input_device_t::input_device_t(wlr_input_device *handle)
{
    this->handle = handle;
}
}

wf_input_device_internal::wf_input_device_internal(wlr_input_device *dev) :
    wf::input_device_t(dev)
{
    on_destroy.set_callback([&] (void*)
    {
        wf::get_core_impl().input->handle_input_destroyed(this->get_wlr_handle());
    });
    on_destroy.connect(&dev->events.destroy);
}

wf::pointf_t get_surface_relative_coords(wf::surface_interface_t *surface,
    const wf::pointf_t& point)
{
    auto og    = surface->get_output()->get_layout_geometry();
    auto local = point;
    local.x -= og.x;
    local.y -= og.y;

    auto view =
        dynamic_cast<wf::view_interface_t*>(surface->get_main_surface());

    return view->global_to_local_point(local, surface);
}
<|endoftext|>