<commit_before>// Copyright 2014 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/at_exit.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "crypto/random.h"
#include "mojo/dart/embedder/dart_controller.h"
#include "mojo/dart/embedder/test/dart_to_cpp.mojom.h"
#include "mojo/edk/test/test_utils.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/macros.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace dart {

// Global value updated by some checks to prevent compilers from optimizing
// reads out of existence.
uint32 g_waste_accumulator = 0;

namespace {

// Negative numbers with different values in each byte, the last of
// which can survive promotion to double and back.
const int8  kExpectedInt8Value = -65;
const int16 kExpectedInt16Value = -16961;
const int32 kExpectedInt32Value = -1145258561;
const int64 kExpectedInt64Value = -77263311946305LL;

// Positive numbers with different values in each byte, the last of
// which can survive promotion to double and back.
const uint8  kExpectedUInt8Value = 65;
const uint16 kExpectedUInt16Value = 16961;
const uint32 kExpectedUInt32Value = 1145258561;
const uint64 kExpectedUInt64Value = 77263311946305LL;

// Double/float values, including special case constants.
const double kExpectedDoubleVal = 3.14159265358979323846;
const double kExpectedDoubleInf = std::numeric_limits<double>::infinity();
const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN();
const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal);
const float kExpectedFloatInf = std::numeric_limits<float>::infinity();
const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN();

// NaN has the property that it is not equal to itself.
#define EXPECT_NAN(x) EXPECT_NE(x, x)

void CheckDataPipe(MojoHandle data_pipe_handle) {
  unsigned char buffer[100];
  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
  MojoResult result = MojoReadData(
      data_pipe_handle, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE);
  EXPECT_EQ(MOJO_RESULT_OK, result);
  EXPECT_EQ(64u, buffer_size);
  for (int i = 0; i < 64; ++i) {
    EXPECT_EQ(i, buffer[i]);
  }
}

void CheckMessagePipe(MojoHandle message_pipe_handle) {
  unsigned char buffer[100];
  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
  MojoResult result = MojoReadMessage(
      message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
  EXPECT_EQ(MOJO_RESULT_OK, result);
  EXPECT_EQ(64u, buffer_size);
  for (int i = 0; i < 64; ++i) {
    EXPECT_EQ(255 - i, buffer[i]);
  }
}

dart_to_cpp::EchoArgsPtr BuildSampleEchoArgs() {
  dart_to_cpp::EchoArgsPtr args(dart_to_cpp::EchoArgs::New());
  args->si64 = kExpectedInt64Value;
  args->si32 = kExpectedInt32Value;
  args->si16 = kExpectedInt16Value;
  args->si8 = kExpectedInt8Value;
  args->ui64 = kExpectedUInt64Value;
  args->ui32 = kExpectedUInt32Value;
  args->ui16 = kExpectedUInt16Value;
  args->ui8 = kExpectedUInt8Value;
  args->float_val = kExpectedFloatVal;
  args->float_inf = kExpectedFloatInf;
  args->float_nan = kExpectedFloatNan;
  args->double_val = kExpectedDoubleVal;
  args->double_inf = kExpectedDoubleInf;
  args->double_nan = kExpectedDoubleNan;
  args->name = "coming";
  Array<String> string_array(3);
  string_array[0] = "one";
  string_array[1] = "two";
  string_array[2] = "three";
  args->string_array = string_array.Pass();
  return args.Pass();
}

void CheckSampleEchoArgs(const dart_to_cpp::EchoArgs& arg) {
  EXPECT_EQ(kExpectedInt64Value, arg.si64);
  EXPECT_EQ(kExpectedInt32Value, arg.si32);
  EXPECT_EQ(kExpectedInt16Value, arg.si16);
  EXPECT_EQ(kExpectedInt8Value, arg.si8);
  EXPECT_EQ(kExpectedUInt64Value, arg.ui64);
  EXPECT_EQ(kExpectedUInt32Value, arg.ui32);
  EXPECT_EQ(kExpectedUInt16Value, arg.ui16);
  EXPECT_EQ(kExpectedUInt8Value, arg.ui8);
  EXPECT_EQ(kExpectedFloatVal, arg.float_val);
  EXPECT_EQ(kExpectedFloatInf, arg.float_inf);
  EXPECT_NAN(arg.float_nan);
  EXPECT_EQ(kExpectedDoubleVal, arg.double_val);
  EXPECT_EQ(kExpectedDoubleInf, arg.double_inf);
  EXPECT_NAN(arg.double_nan);
  EXPECT_EQ(std::string("coming"), arg.name.get());
  EXPECT_EQ(std::string("one"), arg.string_array[0].get());
  EXPECT_EQ(std::string("two"), arg.string_array[1].get());
  EXPECT_EQ(std::string("three"), arg.string_array[2].get());
  CheckDataPipe(arg.data_handle.get().value());
  CheckMessagePipe(arg.message_handle.get().value());
}

void CheckSampleEchoArgsList(const dart_to_cpp::EchoArgsListPtr& list) {
  if (list.is_null())
    return;
  CheckSampleEchoArgs(*list->item);
  CheckSampleEchoArgsList(list->next);
}

// Base Provider implementation class. It's expected that tests subclass and
// override the appropriate Provider functions. When test is done quit the
// run_loop().
class CppSideConnection : public mojo::InterfaceImpl<dart_to_cpp::CppSide> {
 public:
  CppSideConnection() :
      run_loop_(NULL),
      dart_side_(NULL),
      mishandled_messages_(0) {
  }
  ~CppSideConnection() override {}

  void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
  base::RunLoop* run_loop() { return run_loop_; }

  void set_dart_side(dart_to_cpp::DartSide* dart_side) {
    dart_side_ = dart_side;
  }
  dart_to_cpp::DartSide* dart_side() { return dart_side_; }

  // dart_to_cpp::CppSide:
  void StartTest() override { NOTREACHED(); }

  void TestFinished() override { NOTREACHED(); }

  void PingResponse() override { mishandled_messages_ += 1; }

  void EchoResponse(dart_to_cpp::EchoArgsListPtr list) override {
    mishandled_messages_ += 1;
  }

 protected:
  base::RunLoop* run_loop_;
  dart_to_cpp::DartSide* dart_side_;
  int mishandled_messages_;

 private:
  DISALLOW_COPY_AND_ASSIGN(CppSideConnection);
};

// Trivial test to verify a message sent from Dart is received.
class PingCppSideConnection : public CppSideConnection {
 public:
  PingCppSideConnection() : got_message_(false) {}
  ~PingCppSideConnection() override {}

  // dart_to_cpp::CppSide:
  void StartTest() override {
    dart_side_->Ping();
  }

  void PingResponse() override {
    got_message_ = true;
    run_loop()->Quit();
  }

  bool DidSucceed() {
    return got_message_ && !mishandled_messages_;
  }

 private:
  bool got_message_;
  DISALLOW_COPY_AND_ASSIGN(PingCppSideConnection);
};

// Test that parameters are passed with correct values.
class EchoCppSideConnection : public CppSideConnection {
 public:
  EchoCppSideConnection() :
      message_count_(0),
      termination_seen_(false) {
  }
  ~EchoCppSideConnection() override {}

  // dart_to_cpp::CppSide:
  void StartTest() override {
    dart_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs());
  }

  void EchoResponse(dart_to_cpp::EchoArgsListPtr list) override {
    const dart_to_cpp::EchoArgsPtr& special_arg = list->item;
    message_count_ += 1;
    EXPECT_EQ(-1, special_arg->si64);
    EXPECT_EQ(-1, special_arg->si32);
    EXPECT_EQ(-1, special_arg->si16);
    EXPECT_EQ(-1, special_arg->si8);
    EXPECT_EQ(std::string("going"), special_arg->name.To<std::string>());
    CheckSampleEchoArgsList(list->next);
  }

  void TestFinished() override {
    termination_seen_ = true;
    run_loop()->Quit();
  }

  bool DidSucceed() {
    return termination_seen_ &&
        !mishandled_messages_ &&
        message_count_ == kExpectedMessageCount;
  }

 private:
  static const int kExpectedMessageCount = 10;
  int message_count_;
  bool termination_seen_;
  DISALLOW_COPY_AND_ASSIGN(EchoCppSideConnection);
};

}  // namespace

class DartToCppTest : public testing::Test {
 public:
  DartToCppTest() {}

  bool RunTest(const std::string& test, CppSideConnection* cpp_side) {
    // Putting Dart on its own thread so we can use Dart_RunLoop (called from
    // DartController::RunDartScript) and base::RunLoop::Run together. Passing
    // the thread to RunWithDartOnThread instead of inlining that function here
    // so that we are sure the MessagePipe destructor runs and closes the
    // handles on the C++ side before the Thread destructor runs and joins on
    // the Dart thread. Closing the handles on the C++ side must happen first
    // because it is the client, and therefore the Dart side will run and not
    // join while handles are still open, until the C++ side closes them.
    base::Thread dart_thread("dart");
    cpp_side->set_run_loop(&run_loop_);
    return RunWithDartOnThread(&dart_thread, test, cpp_side);
  }

 private:
  base::MessageLoop loop;
  base::RunLoop run_loop_;

  static void UnhandledExceptionCallback(bool* exception, Dart_Handle error) {
    *exception = true;
  }

  static bool GenerateEntropy(uint8_t* buffer, intptr_t length) {
    crypto::RandBytes(reinterpret_cast<void*>(buffer), length);
    return true;
  }

  static void InitializeDartConfig(DartControllerConfig* config,
                                   const std::string& test,
                                   MojoHandle handle,
                                   const char** arguments,
                                   int arguments_count,
                                   bool* unhandled_exception,
                                   char** error) {
    base::FilePath path;
    PathService::Get(base::DIR_SOURCE_ROOT, &path);
    path = path.AppendASCII("mojo")
               .AppendASCII("dart")
               .AppendASCII("embedder")
               .AppendASCII("test")
               .AppendASCII(test);

    // Read in the source.
    std::string source;
    EXPECT_TRUE(ReadFileToString(path, &source)) << "Failed to read test file";

    // Setup the package root.
    base::FilePath package_root;
    PathService::Get(base::DIR_EXE, &package_root);
    package_root = package_root.AppendASCII("gen");

    config->strict_compilation = true;
    config->script = source;
    config->script_uri = path.AsUTF8Unsafe();
    config->package_root = package_root.AsUTF8Unsafe();
    config->application_data = nullptr;
    config->callbacks.exception =
        base::Bind(&UnhandledExceptionCallback, unhandled_exception);
    config->entropy = GenerateEntropy;
    config->handle = handle;
    config->arguments = arguments;
    config->arguments_count = arguments_count;
    config->compile_all = false;
    config->error = error;
  }

  static void RunDartSide(const DartControllerConfig& config) {
    DartController::RunSingleDartScript(config);
  }

  bool RunWithDartOnThread(base::Thread* dart_thread,
                           const std::string& test,
                           CppSideConnection* cpp_side) {
    MessagePipe pipe;
    dart_to_cpp::DartSidePtr dart_side =
        MakeProxy<dart_to_cpp::DartSide>(pipe.handle0.Pass());

    dart_to_cpp::CppSidePtr cpp_side_ptr;
    BindToProxy(cpp_side, &cpp_side_ptr);
    dart_side->SetClient(cpp_side_ptr.Pass());

    dart_side.internal_state()->router_for_testing()->EnableTestingMode();

    cpp_side->set_dart_side(dart_side.get());

    DartControllerConfig config;
    char* error;
    bool unhandled_exception = false;
    InitializeDartConfig(
        &config,
        test,
        pipe.handle1.release().value(),
        nullptr,
        0,
        &unhandled_exception,
        &error);

    dart_thread->Start();
    dart_thread->message_loop()->PostTask(FROM_HERE,
        base::Bind(&RunDartSide, base::ConstRef(config)));

    run_loop_.Run();
    return unhandled_exception;
  }

  DISALLOW_COPY_AND_ASSIGN(DartToCppTest);
};

TEST_F(DartToCppTest, Ping) {
  PingCppSideConnection cpp_side_connection;
  bool unhandled_exception =
      RunTest("dart_to_cpp_tests.dart", &cpp_side_connection);
  EXPECT_TRUE(cpp_side_connection.DidSucceed());
  EXPECT_FALSE(unhandled_exception);
}

TEST_F(DartToCppTest, Echo) {
  EchoCppSideConnection cpp_side_connection;
  bool unhandled_exception =
      RunTest("dart_to_cpp_tests.dart", &cpp_side_connection);
  EXPECT_TRUE(cpp_side_connection.DidSucceed());
  EXPECT_FALSE(unhandled_exception);
}

}  // namespace dart
}  // namespace mojo
<commit_msg>Avoid InterfaceImpl and raw MessagePipe in dart embedder tests<commit_after>// Copyright 2014 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/at_exit.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "crypto/random.h"
#include "mojo/dart/embedder/dart_controller.h"
#include "mojo/dart/embedder/test/dart_to_cpp.mojom.h"
#include "mojo/edk/test/test_utils.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/macros.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace dart {

// Global value updated by some checks to prevent compilers from optimizing
// reads out of existence.
uint32 g_waste_accumulator = 0;

namespace {

// Negative numbers with different values in each byte, the last of
// which can survive promotion to double and back.
const int8  kExpectedInt8Value = -65;
const int16 kExpectedInt16Value = -16961;
const int32 kExpectedInt32Value = -1145258561;
const int64 kExpectedInt64Value = -77263311946305LL;

// Positive numbers with different values in each byte, the last of
// which can survive promotion to double and back.
const uint8  kExpectedUInt8Value = 65;
const uint16 kExpectedUInt16Value = 16961;
const uint32 kExpectedUInt32Value = 1145258561;
const uint64 kExpectedUInt64Value = 77263311946305LL;

// Double/float values, including special case constants.
const double kExpectedDoubleVal = 3.14159265358979323846;
const double kExpectedDoubleInf = std::numeric_limits<double>::infinity();
const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN();
const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal);
const float kExpectedFloatInf = std::numeric_limits<float>::infinity();
const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN();

// NaN has the property that it is not equal to itself.
#define EXPECT_NAN(x) EXPECT_NE(x, x)

void CheckDataPipe(MojoHandle data_pipe_handle) {
  unsigned char buffer[100];
  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
  MojoResult result = MojoReadData(
      data_pipe_handle, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE);
  EXPECT_EQ(MOJO_RESULT_OK, result);
  EXPECT_EQ(64u, buffer_size);
  for (int i = 0; i < 64; ++i) {
    EXPECT_EQ(i, buffer[i]);
  }
}

void CheckMessagePipe(MojoHandle message_pipe_handle) {
  unsigned char buffer[100];
  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
  MojoResult result = MojoReadMessage(
      message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
  EXPECT_EQ(MOJO_RESULT_OK, result);
  EXPECT_EQ(64u, buffer_size);
  for (int i = 0; i < 64; ++i) {
    EXPECT_EQ(255 - i, buffer[i]);
  }
}

dart_to_cpp::EchoArgsPtr BuildSampleEchoArgs() {
  dart_to_cpp::EchoArgsPtr args(dart_to_cpp::EchoArgs::New());
  args->si64 = kExpectedInt64Value;
  args->si32 = kExpectedInt32Value;
  args->si16 = kExpectedInt16Value;
  args->si8 = kExpectedInt8Value;
  args->ui64 = kExpectedUInt64Value;
  args->ui32 = kExpectedUInt32Value;
  args->ui16 = kExpectedUInt16Value;
  args->ui8 = kExpectedUInt8Value;
  args->float_val = kExpectedFloatVal;
  args->float_inf = kExpectedFloatInf;
  args->float_nan = kExpectedFloatNan;
  args->double_val = kExpectedDoubleVal;
  args->double_inf = kExpectedDoubleInf;
  args->double_nan = kExpectedDoubleNan;
  args->name = "coming";
  Array<String> string_array(3);
  string_array[0] = "one";
  string_array[1] = "two";
  string_array[2] = "three";
  args->string_array = string_array.Pass();
  return args.Pass();
}

void CheckSampleEchoArgs(const dart_to_cpp::EchoArgs& arg) {
  EXPECT_EQ(kExpectedInt64Value, arg.si64);
  EXPECT_EQ(kExpectedInt32Value, arg.si32);
  EXPECT_EQ(kExpectedInt16Value, arg.si16);
  EXPECT_EQ(kExpectedInt8Value, arg.si8);
  EXPECT_EQ(kExpectedUInt64Value, arg.ui64);
  EXPECT_EQ(kExpectedUInt32Value, arg.ui32);
  EXPECT_EQ(kExpectedUInt16Value, arg.ui16);
  EXPECT_EQ(kExpectedUInt8Value, arg.ui8);
  EXPECT_EQ(kExpectedFloatVal, arg.float_val);
  EXPECT_EQ(kExpectedFloatInf, arg.float_inf);
  EXPECT_NAN(arg.float_nan);
  EXPECT_EQ(kExpectedDoubleVal, arg.double_val);
  EXPECT_EQ(kExpectedDoubleInf, arg.double_inf);
  EXPECT_NAN(arg.double_nan);
  EXPECT_EQ(std::string("coming"), arg.name.get());
  EXPECT_EQ(std::string("one"), arg.string_array[0].get());
  EXPECT_EQ(std::string("two"), arg.string_array[1].get());
  EXPECT_EQ(std::string("three"), arg.string_array[2].get());
  CheckDataPipe(arg.data_handle.get().value());
  CheckMessagePipe(arg.message_handle.get().value());
}

void CheckSampleEchoArgsList(const dart_to_cpp::EchoArgsListPtr& list) {
  if (list.is_null())
    return;
  CheckSampleEchoArgs(*list->item);
  CheckSampleEchoArgsList(list->next);
}

// Base Provider implementation class. It's expected that tests subclass and
// override the appropriate Provider functions. When test is done quit the
// run_loop().
class CppSideConnection : public dart_to_cpp::CppSide {
 public:
  CppSideConnection() :
      run_loop_(NULL),
      dart_side_(NULL),
      mishandled_messages_(0),
      binding_(this) {
  }
  ~CppSideConnection() override {}

  void Bind(InterfaceRequest<dart_to_cpp::CppSide> request) {
    binding_.Bind(request.Pass());
  }

  void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
  base::RunLoop* run_loop() { return run_loop_; }

  void set_dart_side(dart_to_cpp::DartSide* dart_side) {
    dart_side_ = dart_side;
  }
  dart_to_cpp::DartSide* dart_side() { return dart_side_; }

  // dart_to_cpp::CppSide:
  void StartTest() override { NOTREACHED(); }

  void TestFinished() override { NOTREACHED(); }

  void PingResponse() override { mishandled_messages_ += 1; }

  void EchoResponse(dart_to_cpp::EchoArgsListPtr list) override {
    mishandled_messages_ += 1;
  }

 protected:
  base::RunLoop* run_loop_;
  dart_to_cpp::DartSide* dart_side_;
  int mishandled_messages_;

 private:
  StrongBinding<dart_to_cpp::CppSide> binding_;
  DISALLOW_COPY_AND_ASSIGN(CppSideConnection);
};

// Trivial test to verify a message sent from Dart is received.
class PingCppSideConnection : public CppSideConnection {
 public:
  PingCppSideConnection() : got_message_(false) {}
  ~PingCppSideConnection() override {}

  // dart_to_cpp::CppSide:
  void StartTest() override {
    dart_side_->Ping();
  }

  void PingResponse() override {
    got_message_ = true;
    run_loop()->Quit();
  }

  bool DidSucceed() {
    return got_message_ && !mishandled_messages_;
  }

 private:
  bool got_message_;
  DISALLOW_COPY_AND_ASSIGN(PingCppSideConnection);
};

// Test that parameters are passed with correct values.
class EchoCppSideConnection : public CppSideConnection {
 public:
  EchoCppSideConnection() :
      message_count_(0),
      termination_seen_(false) {
  }
  ~EchoCppSideConnection() override {}

  // dart_to_cpp::CppSide:
  void StartTest() override {
    dart_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs());
  }

  void EchoResponse(dart_to_cpp::EchoArgsListPtr list) override {
    const dart_to_cpp::EchoArgsPtr& special_arg = list->item;
    message_count_ += 1;
    EXPECT_EQ(-1, special_arg->si64);
    EXPECT_EQ(-1, special_arg->si32);
    EXPECT_EQ(-1, special_arg->si16);
    EXPECT_EQ(-1, special_arg->si8);
    EXPECT_EQ(std::string("going"), special_arg->name.To<std::string>());
    CheckSampleEchoArgsList(list->next);
  }

  void TestFinished() override {
    termination_seen_ = true;
    run_loop()->Quit();
  }

  bool DidSucceed() {
    return termination_seen_ &&
        !mishandled_messages_ &&
        message_count_ == kExpectedMessageCount;
  }

 private:
  static const int kExpectedMessageCount = 10;
  int message_count_;
  bool termination_seen_;
  DISALLOW_COPY_AND_ASSIGN(EchoCppSideConnection);
};

}  // namespace

class DartToCppTest : public testing::Test {
 public:
  DartToCppTest() {}

  bool RunTest(const std::string& test, CppSideConnection* cpp_side) {
    // Putting Dart on its own thread so we can use Dart_RunLoop (called from
    // DartController::RunDartScript) and base::RunLoop::Run together. Passing
    // the thread to RunWithDartOnThread instead of inlining that function here
    // so that we are sure the MessagePipe destructor runs and closes the
    // handles on the C++ side before the Thread destructor runs and joins on
    // the Dart thread. Closing the handles on the C++ side must happen first
    // because it is the client, and therefore the Dart side will run and not
    // join while handles are still open, until the C++ side closes them.
    base::Thread dart_thread("dart");
    cpp_side->set_run_loop(&run_loop_);
    return RunWithDartOnThread(&dart_thread, test, cpp_side);
  }

 private:
  base::MessageLoop loop;
  base::RunLoop run_loop_;

  static void UnhandledExceptionCallback(bool* exception, Dart_Handle error) {
    *exception = true;
  }

  static bool GenerateEntropy(uint8_t* buffer, intptr_t length) {
    crypto::RandBytes(reinterpret_cast<void*>(buffer), length);
    return true;
  }

  static void InitializeDartConfig(DartControllerConfig* config,
                                   const std::string& test,
                                   MojoHandle handle,
                                   const char** arguments,
                                   int arguments_count,
                                   bool* unhandled_exception,
                                   char** error) {
    base::FilePath path;
    PathService::Get(base::DIR_SOURCE_ROOT, &path);
    path = path.AppendASCII("mojo")
               .AppendASCII("dart")
               .AppendASCII("embedder")
               .AppendASCII("test")
               .AppendASCII(test);

    // Read in the source.
    std::string source;
    EXPECT_TRUE(ReadFileToString(path, &source)) << "Failed to read test file";

    // Setup the package root.
    base::FilePath package_root;
    PathService::Get(base::DIR_EXE, &package_root);
    package_root = package_root.AppendASCII("gen");

    config->strict_compilation = true;
    config->script = source;
    config->script_uri = path.AsUTF8Unsafe();
    config->package_root = package_root.AsUTF8Unsafe();
    config->application_data = nullptr;
    config->callbacks.exception =
        base::Bind(&UnhandledExceptionCallback, unhandled_exception);
    config->entropy = GenerateEntropy;
    config->handle = handle;
    config->arguments = arguments;
    config->arguments_count = arguments_count;
    config->compile_all = false;
    config->error = error;
  }

  static void RunDartSide(const DartControllerConfig& config) {
    DartController::RunSingleDartScript(config);
  }

  bool RunWithDartOnThread(base::Thread* dart_thread,
                           const std::string& test,
                           CppSideConnection* cpp_side) {
    dart_to_cpp::DartSidePtr dart_side_ptr;
    auto dart_side_request = GetProxy(&dart_side_ptr);

    dart_to_cpp::CppSidePtr cpp_side_ptr;
    cpp_side->Bind(GetProxy(&cpp_side_ptr));
    dart_side_ptr->SetClient(cpp_side_ptr.Pass());

    dart_side_ptr.internal_state()->router_for_testing()->EnableTestingMode();

    cpp_side->set_dart_side(dart_side_ptr.get());

    DartControllerConfig config;
    char* error;
    bool unhandled_exception = false;
    InitializeDartConfig(
        &config,
        test,
        dart_side_request.PassMessagePipe().release().value(),
        nullptr,
        0,
        &unhandled_exception,
        &error);

    dart_thread->Start();
    dart_thread->message_loop()->PostTask(FROM_HERE,
        base::Bind(&RunDartSide, base::ConstRef(config)));

    run_loop_.Run();
    return unhandled_exception;
  }

  DISALLOW_COPY_AND_ASSIGN(DartToCppTest);
};

TEST_F(DartToCppTest, Ping) {
  PingCppSideConnection cpp_side_connection;
  bool unhandled_exception =
      RunTest("dart_to_cpp_tests.dart", &cpp_side_connection);
  EXPECT_TRUE(cpp_side_connection.DidSucceed());
  EXPECT_FALSE(unhandled_exception);
}

TEST_F(DartToCppTest, Echo) {
  EchoCppSideConnection cpp_side_connection;
  bool unhandled_exception =
      RunTest("dart_to_cpp_tests.dart", &cpp_side_connection);
  EXPECT_TRUE(cpp_side_connection.DidSucceed());
  EXPECT_FALSE(unhandled_exception);
}

}  // namespace dart
}  // namespace mojo
<|endoftext|>


<commit_before>// The MIT License(MIT)
//
// Copyright 2016-2017 Huldra
//
// 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.

// demo.cpp : Defines the entry point for the application.
#include "demo/demo.h"

#include <time.h>
#include <deque>
#include "engine/easy.h"

using namespace arctic;
using namespace arctic::easy;

Sprite g_intro_pyramids;
Sprite g_intro_airplane;
Sprite g_wall;
Sprite g_hero;
Sprite g_floor;
Sound g_step;

Si32 g_maze[32][20];
Vec2Si32 g_hero_pos(1, 1);

void StepMazeGeneration(Vec2Si32 from, Vec2Si32 size) {
    g_maze[from.x][from.y] = 1;
    Vec2Si32 direction[4] = {Vec2Si32(-1, 0)
        , Vec2Si32(1, 0)
        , Vec2Si32(0, -1)
        , Vec2Si32(0, 1)};
    for (Si32 variants = 4; variants > 0; --variants) {
        Si32 idx = rand() % variants;
        Vec2Si32 dir = direction[idx];
        Vec2Si32 path = from + dir;
        Vec2Si32 to = path + dir;
        if (to.x > 0 && to.x < size.x - 1 && to.y > 0 && to.y < size.y - 1) {
            if (g_maze[to.x][to.y] == 0) {
                g_maze[path.x][path.y] = 1;
                StepMazeGeneration(to, size);
            }
        }
        direction[idx] = direction[variants - 1];
    }
}

bool IsDeadEnd(Si32 x, Si32 y) {
    Vec2Si32 dir[4] = {Vec2Si32(-1, 0)
        , Vec2Si32(1, 0)
        , Vec2Si32(0, -1)
        , Vec2Si32(0, 1)};
    if (g_maze[x][y] == 1) {
        Si32 exits = 0;
        for (Si32 idx = 0; idx < 4; ++idx) {
            if (g_maze[x + dir[idx].x][y + dir[idx].y] == 1) {
                exits++;
            }
        }
        if (exits == 1) {
            return true;
        }
    }
    return false;
}

std::deque<Vec2Si32> FindDeadEnds(Vec2Si32 size) {
    std::deque<Vec2Si32> res;
    Vec2Si32 max(size.x - 1, size.y - 1);
    for (Si32 x = 1; x < max.x; ++x) {
        for (Si32 y = 1; y < max.y; ++y) {
            if (IsDeadEnd(x, y)) {
                res.emplace_back(x, y);
            }
        }
    }
    return res;
}

void EliminateDeadEnd(Vec2Si32 pos) {
    Vec2Si32 dir[4] = {Vec2Si32(-1, 0)
        , Vec2Si32(1, 0)
        , Vec2Si32(0, -1)
        , Vec2Si32(0, 1)};
    while (true) {
        if (g_maze[pos.x][pos.y] != 1) {
            return;
        }
        Si32 exits = 0;
        Vec2Si32 exit;
        for (Si32 idx = 0; idx < 4; ++idx) {
            if (g_maze[pos.x + dir[idx].x][pos.y + dir[idx].y] == 1) {
                exits++;
                exit = Vec2Si32(pos.x + dir[idx].x, pos.y + dir[idx].y);
            }
        }
        if (exits != 1) {
            return;
        }
        g_maze[pos.x][pos.y] = 0;
        pos = exit;
    }
}

void PlayIntro() {
    ResizeScreen(320, 200);
    Vec2Si32 pyramids_pos(0, 10);

    Vec2Si32 airplane_pos_begin(ScreenSize().x,
        ScreenSize().y - g_intro_airplane.height() / 2);
    Vec2Si32 airplane_pos_end(-g_intro_airplane.width(), 0);
    Si32 duration1 = 380;
    Si32 duration2 = 500;
    Si32 duration3 = 560;
    Si32 frame = 0;
    while (true) {
        if (IsKey(kKeyEscape) || IsKey(kKeySpace) || IsKey(kKeyEnter)) {
            return;
        }
        frame++;
        if (frame > duration3) {
            break;
        }
        if (frame > duration1 && frame < duration2) {
            pyramids_pos = Vec2Si32(rand() % 3 - 1, 10 + rand() % 3 - 1);
        }
        g_intro_pyramids.Draw(pyramids_pos);
        if (frame < duration1) {
            Vec2Si32 airplane_pos = airplane_pos_begin +
                (airplane_pos_end - airplane_pos_begin) * frame / duration1;
            g_intro_airplane.Draw(airplane_pos);
        }
        ShowFrame();
    }
}

void Init() {
    g_intro_pyramids.Load("data/pyramids1.tga");
    g_intro_airplane.Load("data/airplane1.tga");
    g_wall.Load("data/wall1.tga");
    g_hero.Load("data/hero1.tga");
    g_floor.Load("data/floor1.tga");
    g_step.Load("data/step.wav");

    PlayIntro();

    ResizeScreen(800, 500);
    Vec2Si32 maze_size(32, 20);
    for (Si32 x = 0; x < maze_size.x; ++x) {
        for (Si32 y = 0; y < maze_size.y; ++y) {
            g_maze[x][y] = 0;
        }
    }

    g_hero_pos = Vec2Si32(1, 1);
    srand(static_cast<unsigned int>(time(nullptr)));
    StepMazeGeneration(g_hero_pos, maze_size);
    std::deque<Vec2Si32> dead_ends = FindDeadEnds(maze_size);
    Si32 to_eliminate = dead_ends.size() / 2;
    for (Si32 idx = 0; idx < to_eliminate; ++idx) {
        Si32 rnd = rand() % dead_ends.size();
        EliminateDeadEnd(dead_ends[rnd]);
        dead_ends[rnd] = dead_ends.back();
        dead_ends.pop_back();
    }
}

void Update() {
    Vec2Si32 step(0, 0);
    if (IsKey(kKeyUp) || IsKey("w")) {
        step.y = 1;
    }
    if (IsKey(kKeyDown) || IsKey("s")) {
        step.y = -1;
    }
    if (IsKey(kKeyLeft) || IsKey("a")) {
        step.x = -1;
        step.y = 0;
    }
    if (IsKey(kKeyRight) || IsKey("d")) {
        step.x = 1;
        step.y = 0;
    }

    if (g_maze[g_hero_pos.x + step.x][g_hero_pos.y + step.y] == 1) {
        g_step.Play();
        g_hero_pos += step;
    }
}

void Render() {
    for (Si32 x = 0; x < 32; ++x) {
        for (Si32 y = 19; y >= 0; --y) {
            if (g_maze[x][y] == 0) {
                g_wall.Draw(x * 25, y * 25);
            } else {
                g_floor.Draw(x * 25, y * 25);
            }
            if (x == g_hero_pos.x && y == g_hero_pos.y) {
                g_hero.Draw(x * 25 + 5, y * 25 + 10);
            }
        }
    }
}

void EasyMain() {
    Init();
    while (!IsKey(kKeyEscape)) {
        Update();
        Render();
        ShowFrame();
    }
}
<commit_msg>Implement snow in intro<commit_after>// The MIT License(MIT)
//
// Copyright 2016-2017 Huldra
//
// 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.

// demo.cpp : Defines the entry point for the application.
#include "demo/demo.h"

#include <time.h>
#include <deque>
#include "engine/easy.h"

using namespace arctic;
using namespace arctic::easy;

Sprite g_intro_pyramids;
Sprite g_intro_airplane;
Sprite g_wall;
Sprite g_hero;
Sprite g_floor;
Sound g_step;

Si32 g_maze[32][20];
Vec2Si32 g_hero_pos(1, 1);

void StepMazeGeneration(Vec2Si32 from, Vec2Si32 size) {
    g_maze[from.x][from.y] = 1;
    Vec2Si32 direction[4] = {Vec2Si32(-1, 0)
        , Vec2Si32(1, 0)
        , Vec2Si32(0, -1)
        , Vec2Si32(0, 1)};
    for (Si32 variants = 4; variants > 0; --variants) {
        Si32 idx = rand() % variants;
        Vec2Si32 dir = direction[idx];
        Vec2Si32 path = from + dir;
        Vec2Si32 to = path + dir;
        if (to.x > 0 && to.x < size.x - 1 && to.y > 0 && to.y < size.y - 1) {
            if (g_maze[to.x][to.y] == 0) {
                g_maze[path.x][path.y] = 1;
                StepMazeGeneration(to, size);
            }
        }
        direction[idx] = direction[variants - 1];
    }
}

bool IsDeadEnd(Si32 x, Si32 y) {
    Vec2Si32 dir[4] = {Vec2Si32(-1, 0)
        , Vec2Si32(1, 0)
        , Vec2Si32(0, -1)
        , Vec2Si32(0, 1)};
    if (g_maze[x][y] == 1) {
        Si32 exits = 0;
        for (Si32 idx = 0; idx < 4; ++idx) {
            if (g_maze[x + dir[idx].x][y + dir[idx].y] == 1) {
                exits++;
            }
        }
        if (exits == 1) {
            return true;
        }
    }
    return false;
}

std::deque<Vec2Si32> FindDeadEnds(Vec2Si32 size) {
    std::deque<Vec2Si32> res;
    Vec2Si32 max(size.x - 1, size.y - 1);
    for (Si32 x = 1; x < max.x; ++x) {
        for (Si32 y = 1; y < max.y; ++y) {
            if (IsDeadEnd(x, y)) {
                res.emplace_back(x, y);
            }
        }
    }
    return res;
}

void EliminateDeadEnd(Vec2Si32 pos) {
    Vec2Si32 dir[4] = {Vec2Si32(-1, 0)
        , Vec2Si32(1, 0)
        , Vec2Si32(0, -1)
        , Vec2Si32(0, 1)};
    while (true) {
        if (g_maze[pos.x][pos.y] != 1) {
            return;
        }
        Si32 exits = 0;
        Vec2Si32 exit;
        for (Si32 idx = 0; idx < 4; ++idx) {
            if (g_maze[pos.x + dir[idx].x][pos.y + dir[idx].y] == 1) {
                exits++;
                exit = Vec2Si32(pos.x + dir[idx].x, pos.y + dir[idx].y);
            }
        }
        if (exits != 1) {
            return;
        }
        g_maze[pos.x][pos.y] = 0;
        pos = exit;
    }
}

void PlayIntro() {
    ResizeScreen(320, 200);
    Ui8 snow[2][320 * 200];
    for (Si32 i = 0; i < 320 * 200; ++i) {
        if (rand() % 16 == 0) {
            snow[0][i] = rand() % 256;
        } else {
            snow[0][i] = 0;
        }
    }
    Ui8 *cur_snow = snow[0];
    Ui8 *next_snow = snow[1];

    Vec2Si32 pyramids_pos(0, 10);

    Vec2Si32 airplane_pos_begin(ScreenSize().x,
        ScreenSize().y - g_intro_airplane.height() / 2);
    Vec2Si32 airplane_pos_end(-g_intro_airplane.width(), 0);
    Si32 duration1 = 380;
    Si32 duration2 = 500;
    Si32 duration3 = 560;
    Si32 frame = 0;
    while (true) {
        if (IsKey(kKeyEscape) || IsKey(kKeySpace) || IsKey(kKeyEnter)) {
            return;
        }
        frame++;
        if (frame > duration3) {
            break;
        }
        if (frame > duration1 && frame < duration2) {
            pyramids_pos = Vec2Si32(rand() % 3 - 1, 10 + rand() % 3 - 1);
        }
        g_intro_pyramids.Draw(pyramids_pos);
        if (frame < duration1) {
            Vec2Si32 airplane_pos = airplane_pos_begin +
                (airplane_pos_end - airplane_pos_begin) * frame / duration1;
            g_intro_airplane.Draw(airplane_pos);
        }

        Rgba *back_buffer = GetEngine()->GetBackbuffer().RgbaData();
        memset(next_snow, 0, 320 * 200);
        for (Si32 y = 0; y < 200; ++y) {
            for (Si32 x = 0; x < 320; ++x) {
                Si32 z = cur_snow[x + y * 320];
                if (z) {
                    Si32 next_x = x + 8 - z/42;
                    Si32 next_y = y - 1;
                    if (next_x >= 320) {
                        next_x -= 320;
                    }
                    if (next_y < 0) {
                        next_y = 199;
                    }
                    if (next_snow[next_x + next_y * 320] == 0
                        || next_snow[next_x + next_y * 320] > z) {
                        next_snow[next_x + next_y * 320] = z;
                    }
                    if (rand() % 16 == 0) {
                        Si32 z2 = rand() % 256;
                        if (z2 > z) {
                            next_snow[x + y * 320] = z2;
                        }
                    }
                    back_buffer[x + y * 320] = Rgba(255 - z/8, 255 - z/8, 255 - z/8);
                }
            }
        }
        std::swap(cur_snow, next_snow);
        ShowFrame();
    }
}

void Init() {
    g_intro_pyramids.Load("data/pyramids1.tga");
    g_intro_airplane.Load("data/airplane1.tga");
    g_wall.Load("data/wall1.tga");
    g_hero.Load("data/hero1.tga");
    g_floor.Load("data/floor1.tga");
    g_step.Load("data/step.wav");

    PlayIntro();

    ResizeScreen(800, 500);
    Vec2Si32 maze_size(32, 20);
    for (Si32 x = 0; x < maze_size.x; ++x) {
        for (Si32 y = 0; y < maze_size.y; ++y) {
            g_maze[x][y] = 0;
        }
    }

    g_hero_pos = Vec2Si32(1, 1);
    srand(static_cast<unsigned int>(time(nullptr)));
    StepMazeGeneration(g_hero_pos, maze_size);
    std::deque<Vec2Si32> dead_ends = FindDeadEnds(maze_size);
    Si32 to_eliminate = dead_ends.size() / 2;
    for (Si32 idx = 0; idx < to_eliminate; ++idx) {
        Si32 rnd = rand() % dead_ends.size();
        EliminateDeadEnd(dead_ends[rnd]);
        dead_ends[rnd] = dead_ends.back();
        dead_ends.pop_back();
    }
}

void Update() {
    Vec2Si32 step(0, 0);
    if (IsKey(kKeyUp) || IsKey("w")) {
        step.y = 1;
    }
    if (IsKey(kKeyDown) || IsKey("s")) {
        step.y = -1;
    }
    if (IsKey(kKeyLeft) || IsKey("a")) {
        step.x = -1;
        step.y = 0;
    }
    if (IsKey(kKeyRight) || IsKey("d")) {
        step.x = 1;
        step.y = 0;
    }

    if (g_maze[g_hero_pos.x + step.x][g_hero_pos.y + step.y] == 1) {
        g_step.Play();
        g_hero_pos += step;
    }
}

void Render() {
    for (Si32 x = 0; x < 32; ++x) {
        for (Si32 y = 19; y >= 0; --y) {
            if (g_maze[x][y] == 0) {
                g_wall.Draw(x * 25, y * 25);
            } else {
                g_floor.Draw(x * 25, y * 25);
            }
            if (x == g_hero_pos.x && y == g_hero_pos.y) {
                g_hero.Draw(x * 25 + 5, y * 25 + 10);
            }
        }
    }
}

void EasyMain() {
    Init();
    while (!IsKey(kKeyEscape)) {
        Update();
        Render();
        ShowFrame();
    }
}
<|endoftext|>


<commit_before>#include "BulletsConverter.h"
#include "StylesWriter.h"

using namespace PPT_FORMAT;

BulletsConverter::BulletsConverter(CRelsGenerator* pRels) : m_pRels(pRels) {}

void BulletsConverter::FillPPr(PPTX::Logic::TextParagraphPr &oPPr, CParagraph &paragraph)
{
    oPPr.lvl = paragraph.m_lTextLevel;

    auto* pPF = &(paragraph.m_oPFRun);
    if (pPF)
        ConvertPFRun(oPPr, pPF);
}

void BulletsConverter::ConvertPFRun(PPTX::Logic::TextParagraphPr &oPPr, CTextPFRun *pPF)
{
    const int oneTabSize = 457200;
    int leftMargin = 0;
    if (pPF->leftMargin.is_init())
    {
        leftMargin = pPF->leftMargin.get();
        oPPr.marL = leftMargin;
    }
    if (pPF->indent.is_init())
    {
        if (pPF->hasBullet.get_value_or(false) && pPF->indent.get() != -leftMargin)
        {
            oPPr.indent = pPF->indent.get() - leftMargin;
        }
        else
        {
            oPPr.indent = pPF->indent.get();
        }
    } else if (pPF->hasBullet.get_value_or(false))
    {
        const int tabLvl = oPPr.lvl.get_value_or(0);
        if (tabLvl != -1)
            oPPr.indent = oneTabSize*tabLvl - leftMargin;
        else
            oPPr.indent = -leftMargin;
    }
    if (pPF->textAlignment.is_init())
    {
        oPPr.algn = new PPTX::Limit::TextAlign;
        oPPr.algn->set(CStylesWriter::GetTextAlign(pPF->textAlignment.get()));
    }
    if (pPF->defaultTabSize.is_init())
    {
        oPPr.defTabSz = pPF->defaultTabSize.get();
    }
    if (pPF->textDirection.is_init())
    {
        if (pPF->textDirection.get() == 1)	oPPr.rtl = true;
        else								oPPr.rtl = false;
    }
    if (pPF->fontAlign.is_init())
    {
        oPPr.fontAlgn = new PPTX::Limit::FontAlign;
        oPPr.fontAlgn->set(CStylesWriter::GetFontAlign(pPF->fontAlign.get()));
    }
    if (pPF->wrapFlags.is_init() && pPF->wrapFlags.get() & 0b111)
    {
        const auto& flags = pPF->wrapFlags.get();
        if (flags & 0b100)
            oPPr.hangingPunct = true;

    }

    ConvertTabStops(oPPr.tabLst, pPF->tabStops);

    if (pPF->lineSpacing.is_init())
    {
        LONG val = pPF->lineSpacing.get();
        auto pLnSpc = new PPTX::Logic::TextSpacing;
        pLnSpc->m_name = L"a:lnSpc";

        if (val > 0)
            pLnSpc->spcPct = val * 12.5;
        else if (val < 0 && val > -13200)
            pLnSpc->spcPct = val * -1000;

        oPPr.lnSpc = pLnSpc;
    }

    if (pPF->spaceAfter.is_init())
    {
        LONG val = pPF->spaceAfter.get();
        auto pSpcAft = new PPTX::Logic::TextSpacing;
        pSpcAft->m_name = L"a:spcAft";
        if (val > 0)
            pSpcAft->spcPts = round(12.5 * pPF->spaceAfter.get());
        else if (val < 0 && val > -13200)
            pSpcAft->spcPts = val * -1000;

        oPPr.spcAft = pSpcAft;
    }
    if (pPF->spaceBefore.is_init())
    {
        LONG val = pPF->spaceBefore.get();
        auto pSpcBef = new PPTX::Logic::TextSpacing;
        pSpcBef->m_name = L"a:spcBef";
        if (val > 0)
            pSpcBef->spcPts = round(12.5 * pPF->spaceBefore.get());
        else if (val < 0 && val > -13200)
            pSpcBef->spcPct = val * -1000;

        oPPr.spcBef = pSpcBef;
    }

    ConvertAllBullets(oPPr, pPF);
}

void BulletsConverter::ConvertTabStops(std::vector<PPTX::Logic::Tab> &arrTabs, std::vector<std::pair<int, int> > &arrTabStops)
{
    for (size_t t = 0 ; t < arrTabStops.size(); t++)
    {
        PPTX::Logic::Tab tab;
        tab.pos = arrTabStops[t].first;
        auto pAlgn = new PPTX::Limit::TextTabAlignType;

        switch (arrTabStops[t].second)
        {
        case 1: pAlgn->set(L"ctr"); break;
        case 2: pAlgn->set(L"r"); break;
        case 3: pAlgn->set(L"dec"); break;
        default: pAlgn->set(L"l");
        }
        tab.algn = pAlgn;

        arrTabs.push_back(tab);
    }
}

void BulletsConverter::FillBuChar(PPTX::Logic::Bullet &oBullet, WCHAR symbol, CTextPFRun *pPF)
{
    auto pBuChar = new PPTX::Logic::BuChar;
    pBuChar->Char.clear();
    if (pPF != nullptr && pPF->bulletFontProperties.IsInit())
    {
        const auto& fontProp = *(pPF->bulletFontProperties);
        if (fontProp.Charset == 10)
        {
            symbol &= 0x00ff;
            symbol |= 0xf000;
        }
    }
    pBuChar->Char.push_back(symbol);
    oBullet.m_Bullet.reset(pBuChar);
}

void BulletsConverter::ConvertAllBullets(PPTX::Logic::TextParagraphPr &oPPr, CTextPFRun *pPF)
{
    if (pPF->hasBullet.is_init())
    {
        if (pPF->hasBullet.get())
        {
            if (pPF->bulletColor.is_init())
            {
                FillBuClr(oPPr.buColor, pPF->bulletColor.get());
            }
            if (pPF->bulletSize.is_init())
            {
                PPTX::WrapperWritingElement* pBuSize(nullptr);
                if (pPF->bulletSize.get() > 24 && pPF->bulletSize.get() < 401)
                {
                    pBuSize = new PPTX::Logic::BuSzPct;
                    static_cast<PPTX::Logic::BuSzPct*>(pBuSize)->val = pPF->bulletSize.get() * 1000 ;
                }
                if (pPF->bulletSize.get() < 0 && pPF->bulletSize.get() > -4001)
                {
                    pBuSize = new PPTX::Logic::BuSzPts;
                    static_cast<PPTX::Logic::BuSzPts*>(pBuSize)->val = - (pPF->bulletSize.get());
                }
                if (pBuSize != nullptr)
                    oPPr.buSize.m_Size = pBuSize;
            }
            if (pPF->bulletFontProperties.is_init())
            {
                auto pBuFont = new PPTX::Logic::TextFont;
                pBuFont->m_name = L"a:buFont";
                pBuFont->typeface = pPF->bulletFontProperties->Name;

                if ( pPF->bulletFontProperties->PitchFamily > 0)
                    pBuFont->pitchFamily = std::to_wstring(pPF->bulletFontProperties->PitchFamily);
                if ( pPF->bulletFontProperties->Charset > 0)
                    pBuFont->charset = std::to_wstring(pPF->bulletFontProperties->Charset);

                oPPr.buTypeface.m_Typeface.reset(pBuFont);
            }

            // Bullets (numbering, else picture, else char, else default)
            if (pPF->bulletBlip.is_init() && pPF->bulletBlip->tmpImagePath.size() && m_pRels != nullptr)
            {
                auto strRID = m_pRels->WriteImage(pPF->bulletBlip->tmpImagePath);
                if (strRID.empty())
                    FillBuChar(oPPr.ParagraphBullet, L'\x2022');    // error rId
                else
                {
                    auto pBuBlip = new PPTX::Logic::BuBlip;
                    pBuBlip->blip.embed = new OOX::RId(strRID);
                    oPPr.ParagraphBullet.m_Bullet.reset(pBuBlip);
                }
            }
            else if (pPF->bulletAutoNum.is_init())
            {
                auto pBuAutoNum = new PPTX::Logic::BuAutoNum;
                oPPr.ParagraphBullet.m_Bullet.reset(pBuAutoNum);
                if (pPF->bulletAutoNum->startAt.is_init() && pPF->bulletAutoNum->startAt.get() != 1)
                    pBuAutoNum->startAt = pPF->bulletAutoNum->startAt.get();
                if (pPF->bulletAutoNum->type.is_init())
                    pBuAutoNum->type = pPF->bulletAutoNum->type.get();
            }
            else if (pPF->bulletChar.is_init())
            {
                FillBuChar(oPPr.ParagraphBullet, pPF->bulletChar.get(), pPF);
            }
            else
            {
                FillBuChar(oPPr.ParagraphBullet, L'\x2022');
            }
        }
        else
        {
            oPPr.buTypeface.m_Typeface.reset(new PPTX::Logic::BuNone);
        }
    }
}

void BulletsConverter::FillBuClr(PPTX::Logic::BulletColor &oBuClr, CColor &oColor)
{
    auto pBuClr = new PPTX::Logic::BuClr;
    pBuClr->Color.SetRGBColor(oColor.GetR(), oColor.GetG(), oColor.GetB());
    oBuClr.m_Color.reset(pBuClr);
}
<commit_msg>fix indent for tab level with bullet<commit_after>#include "BulletsConverter.h"
#include "StylesWriter.h"

using namespace PPT_FORMAT;

BulletsConverter::BulletsConverter(CRelsGenerator* pRels) : m_pRels(pRels) {}

void BulletsConverter::FillPPr(PPTX::Logic::TextParagraphPr &oPPr, CParagraph &paragraph)
{
    oPPr.lvl = paragraph.m_lTextLevel;

    auto* pPF = &(paragraph.m_oPFRun);
    if (pPF)
        ConvertPFRun(oPPr, pPF);
}

void BulletsConverter::ConvertPFRun(PPTX::Logic::TextParagraphPr &oPPr, CTextPFRun *pPF)
{
    const int oneTabSize = 457200;
    const int tabLvl = oPPr.lvl.get_value_or(0);
    int leftMargin = 0;
    if (pPF->leftMargin.is_init())
    {
        leftMargin = pPF->leftMargin.get();
        oPPr.marL = leftMargin;
    }
    if (pPF->indent.is_init())
    {
        if (pPF->hasBullet.get_value_or(false) && tabLvl == -1)
        {
            oPPr.indent = pPF->indent.get() - leftMargin;
        }
        else
        {
            oPPr.indent = pPF->indent.get();
        }
    } else if (pPF->hasBullet.get_value_or(false))
    {
        if (tabLvl != -1)
            oPPr.indent = oneTabSize*tabLvl - leftMargin;
        else
            oPPr.indent = -leftMargin;
    }
    if (pPF->textAlignment.is_init())
    {
        oPPr.algn = new PPTX::Limit::TextAlign;
        oPPr.algn->set(CStylesWriter::GetTextAlign(pPF->textAlignment.get()));
    }
    if (pPF->defaultTabSize.is_init())
    {
        oPPr.defTabSz = pPF->defaultTabSize.get();
    }
    if (pPF->textDirection.is_init())
    {
        if (pPF->textDirection.get() == 1)	oPPr.rtl = true;
        else								oPPr.rtl = false;
    }
    if (pPF->fontAlign.is_init())
    {
        oPPr.fontAlgn = new PPTX::Limit::FontAlign;
        oPPr.fontAlgn->set(CStylesWriter::GetFontAlign(pPF->fontAlign.get()));
    }
    if (pPF->wrapFlags.is_init() && pPF->wrapFlags.get() & 0b111)
    {
        const auto& flags = pPF->wrapFlags.get();
        if (flags & 0b100)
            oPPr.hangingPunct = true;

    }

    ConvertTabStops(oPPr.tabLst, pPF->tabStops);

    if (pPF->lineSpacing.is_init())
    {
        LONG val = pPF->lineSpacing.get();
        auto pLnSpc = new PPTX::Logic::TextSpacing;
        pLnSpc->m_name = L"a:lnSpc";

        if (val > 0)
            pLnSpc->spcPct = val * 12.5;
        else if (val < 0 && val > -13200)
            pLnSpc->spcPct = val * -1000;

        oPPr.lnSpc = pLnSpc;
    }

    if (pPF->spaceAfter.is_init())
    {
        LONG val = pPF->spaceAfter.get();
        auto pSpcAft = new PPTX::Logic::TextSpacing;
        pSpcAft->m_name = L"a:spcAft";
        if (val > 0)
            pSpcAft->spcPts = round(12.5 * pPF->spaceAfter.get());
        else if (val < 0 && val > -13200)
            pSpcAft->spcPts = val * -1000;

        oPPr.spcAft = pSpcAft;
    }
    if (pPF->spaceBefore.is_init())
    {
        LONG val = pPF->spaceBefore.get();
        auto pSpcBef = new PPTX::Logic::TextSpacing;
        pSpcBef->m_name = L"a:spcBef";
        if (val > 0)
            pSpcBef->spcPts = round(12.5 * pPF->spaceBefore.get());
        else if (val < 0 && val > -13200)
            pSpcBef->spcPct = val * -1000;

        oPPr.spcBef = pSpcBef;
    }

    ConvertAllBullets(oPPr, pPF);
}

void BulletsConverter::ConvertTabStops(std::vector<PPTX::Logic::Tab> &arrTabs, std::vector<std::pair<int, int> > &arrTabStops)
{
    for (size_t t = 0 ; t < arrTabStops.size(); t++)
    {
        PPTX::Logic::Tab tab;
        tab.pos = arrTabStops[t].first;
        auto pAlgn = new PPTX::Limit::TextTabAlignType;

        switch (arrTabStops[t].second)
        {
        case 1: pAlgn->set(L"ctr"); break;
        case 2: pAlgn->set(L"r"); break;
        case 3: pAlgn->set(L"dec"); break;
        default: pAlgn->set(L"l");
        }
        tab.algn = pAlgn;

        arrTabs.push_back(tab);
    }
}

void BulletsConverter::FillBuChar(PPTX::Logic::Bullet &oBullet, WCHAR symbol, CTextPFRun *pPF)
{
    auto pBuChar = new PPTX::Logic::BuChar;
    pBuChar->Char.clear();
    if (pPF != nullptr && pPF->bulletFontProperties.IsInit())
    {
        const auto& fontProp = *(pPF->bulletFontProperties);
        if (fontProp.Charset == 10)
        {
            symbol &= 0x00ff;
            symbol |= 0xf000;
        }
    }
    pBuChar->Char.push_back(symbol);
    oBullet.m_Bullet.reset(pBuChar);
}

void BulletsConverter::ConvertAllBullets(PPTX::Logic::TextParagraphPr &oPPr, CTextPFRun *pPF)
{
    if (pPF->hasBullet.is_init())
    {
        if (pPF->hasBullet.get())
        {
            if (pPF->bulletColor.is_init())
            {
                FillBuClr(oPPr.buColor, pPF->bulletColor.get());
            }
            if (pPF->bulletSize.is_init())
            {
                PPTX::WrapperWritingElement* pBuSize(nullptr);
                if (pPF->bulletSize.get() > 24 && pPF->bulletSize.get() < 401)
                {
                    pBuSize = new PPTX::Logic::BuSzPct;
                    static_cast<PPTX::Logic::BuSzPct*>(pBuSize)->val = pPF->bulletSize.get() * 1000 ;
                }
                if (pPF->bulletSize.get() < 0 && pPF->bulletSize.get() > -4001)
                {
                    pBuSize = new PPTX::Logic::BuSzPts;
                    static_cast<PPTX::Logic::BuSzPts*>(pBuSize)->val = - (pPF->bulletSize.get());
                }
                if (pBuSize != nullptr)
                    oPPr.buSize.m_Size = pBuSize;
            }
            if (pPF->bulletFontProperties.is_init())
            {
                auto pBuFont = new PPTX::Logic::TextFont;
                pBuFont->m_name = L"a:buFont";
                pBuFont->typeface = pPF->bulletFontProperties->Name;

                if ( pPF->bulletFontProperties->PitchFamily > 0)
                    pBuFont->pitchFamily = std::to_wstring(pPF->bulletFontProperties->PitchFamily);
                if ( pPF->bulletFontProperties->Charset > 0)
                    pBuFont->charset = std::to_wstring(pPF->bulletFontProperties->Charset);

                oPPr.buTypeface.m_Typeface.reset(pBuFont);
            }

            // Bullets (numbering, else picture, else char, else default)
            if (pPF->bulletBlip.is_init() && pPF->bulletBlip->tmpImagePath.size() && m_pRels != nullptr)
            {
                auto strRID = m_pRels->WriteImage(pPF->bulletBlip->tmpImagePath);
                if (strRID.empty())
                    FillBuChar(oPPr.ParagraphBullet, L'\x2022');    // error rId
                else
                {
                    auto pBuBlip = new PPTX::Logic::BuBlip;
                    pBuBlip->blip.embed = new OOX::RId(strRID);
                    oPPr.ParagraphBullet.m_Bullet.reset(pBuBlip);
                }
            }
            else if (pPF->bulletAutoNum.is_init())
            {
                auto pBuAutoNum = new PPTX::Logic::BuAutoNum;
                oPPr.ParagraphBullet.m_Bullet.reset(pBuAutoNum);
                if (pPF->bulletAutoNum->startAt.is_init() && pPF->bulletAutoNum->startAt.get() != 1)
                    pBuAutoNum->startAt = pPF->bulletAutoNum->startAt.get();
                if (pPF->bulletAutoNum->type.is_init())
                    pBuAutoNum->type = pPF->bulletAutoNum->type.get();
            }
            else if (pPF->bulletChar.is_init())
            {
                FillBuChar(oPPr.ParagraphBullet, pPF->bulletChar.get(), pPF);
            }
            else
            {
                FillBuChar(oPPr.ParagraphBullet, L'\x2022');
            }
        }
        else
        {
            oPPr.buTypeface.m_Typeface.reset(new PPTX::Logic::BuNone);
        }
    }
}

void BulletsConverter::FillBuClr(PPTX::Logic::BulletColor &oBuClr, CColor &oColor)
{
    auto pBuClr = new PPTX::Logic::BuClr;
    pBuClr->Color.SetRGBColor(oColor.GetR(), oColor.GetG(), oColor.GetB());
    oBuClr.m_Color.reset(pBuClr);
}
<|endoftext|>


<commit_before>#include <libgen.h>

#include <iomanip>
#include <iostream>
#include <sstream>

#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/configuration_frame_address.h>
#include <yaml-cpp/yaml.h>

namespace xc7series = prjxray::xilinx::xc7series;

template<typename T>
std::string HexString(T value) {
	std::ostringstream out;
	out << "0x" << std::hex << value;
	return out.str();
}

int main(int argc, char *argv[]) {
	if (argc < 2) {
		std::cerr << "ERROR: no input specified" << std::endl;
		std::cerr << "Usage: " << basename(argv[0])
			  << " <bit_file>"
			  << std::endl;
		return 1;
	}

	auto in_file_name = argv[1];
	auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name);
	if (!in_file) {
		std::cerr << "Unable to open bit file: " << in_file_name
			  << std::endl;
		return 1;
	}

	auto in_bytes = absl::Span<uint8_t>(
			static_cast<uint8_t*>(in_file->data()),
			in_file->size());
	auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes);
	if (!reader) {
		std::cerr << "Input doesn't look like a bitstream"
			  << std::endl;
		return 1;
	}

	bool found_fdri_write = false;
	std::vector<uint32_t> frame_addresses;
	absl::optional<uint32_t> idcode;
	for (auto packet : *reader) {
		if (packet.opcode() !=
		     xc7series::ConfigurationPacket::Opcode::Write) {
			continue;
		}

		if (packet.address() ==
		    xc7series::ConfigurationRegister::FDRI) {
			found_fdri_write = true;
		} else if ((packet.address() ==
			    xc7series::ConfigurationRegister::IDCODE) &&
			   packet.data().size() == 1) {
			idcode = packet.data()[0];
		} else if (found_fdri_write &&
			   (packet.address() ==
			    xc7series::ConfigurationRegister::LOUT) &&
			   packet.data().size() == 1) {
			frame_addresses.push_back(packet.data()[0]);
		}
	}

	if (!idcode) {
		std::cerr << "No IDCODE found." << std::endl;
		return 1;
	}

	if (frame_addresses.empty()) {
		std::cerr << "No LOUT writes found.  Was "
			  << "BITSTREAM.GENERAL.DEBUGBITSTREAM set to YES?"
			  << std::endl;
		return 1;
	}

	YAML::Node config_yaml;
	config_yaml.SetTag("xilinx/xc7series/part");
	config_yaml["idcode"] = HexString(*idcode);

	// So far, the addresses appear to be written in increasing order but
	// there is no guarantee.  Sort them just in case.
	std::sort(frame_addresses.begin(), frame_addresses.end());

	YAML::Node regions = config_yaml["configuration_regions"];
	for (auto start_of_range = frame_addresses.begin();
	     start_of_range != frame_addresses.end();
	     ) {
		auto end_of_range = start_of_range;
		while (end_of_range + 1 != frame_addresses.end() &&
		       *(end_of_range + 1) == *end_of_range + 1) {
			++end_of_range;
		}

		YAML::Node region;
		region["start"] =
			xc7series::ConfigurationFrameAddress(*start_of_range);
		region["end"] =
			xc7series::ConfigurationFrameAddress(*end_of_range);
		regions.push_back(region);

		start_of_range = ++end_of_range;
	}

	std::cout << config_yaml << std::endl;

	return 0;
}
<commit_msg>tools: rewrite gen_part_base_yaml using xc7series::Part<commit_after>#include <libgen.h>

#include <iostream>
#include <vector>

#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/configuration_frame_address.h>
#include <prjxray/xilinx/xc7series/configuration_frame_range.h>
#include <prjxray/xilinx/xc7series/part.h>
#include <yaml-cpp/yaml.h>

namespace xc7series = prjxray::xilinx::xc7series;

int main(int argc, char *argv[]) {
	if (argc < 2) {
		std::cerr << "ERROR: no input specified" << std::endl;
		std::cerr << "Usage: " << basename(argv[0])
			  << " <bit_file>"
			  << std::endl;
		return 1;
	}

	auto in_file_name = argv[1];
	auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name);
	if (!in_file) {
		std::cerr << "Unable to open bit file: " << in_file_name
			  << std::endl;
		return 1;
	}

	auto in_bytes = absl::Span<uint8_t>(
			static_cast<uint8_t*>(in_file->data()),
			in_file->size());
	auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes);
	if (!reader) {
		std::cerr << "Input doesn't look like a bitstream"
			  << std::endl;
		return 1;
	}

	bool found_fdri_write = false;
	std::vector<uint32_t> frame_addresses;
	absl::optional<uint32_t> idcode;
	for (auto packet : *reader) {
		if (packet.opcode() !=
		     xc7series::ConfigurationPacket::Opcode::Write) {
			continue;
		}

		if (packet.address() ==
		    xc7series::ConfigurationRegister::FDRI) {
			found_fdri_write = true;
		} else if ((packet.address() ==
			    xc7series::ConfigurationRegister::IDCODE) &&
			   packet.data().size() == 1) {
			idcode = packet.data()[0];
		} else if (found_fdri_write &&
			   (packet.address() ==
			    xc7series::ConfigurationRegister::LOUT) &&
			   packet.data().size() == 1) {
			frame_addresses.push_back(packet.data()[0]);
		}
	}

	if (!idcode) {
		std::cerr << "No IDCODE found." << std::endl;
		return 1;
	}

	if (frame_addresses.empty()) {
		std::cerr << "No LOUT writes found.  Was "
			  << "BITSTREAM.GENERAL.DEBUGBITSTREAM set to YES?"
			  << std::endl;
		return 1;
	}

	// So far, the addresses appear to be written in increasing order but
	// there is no guarantee.  Sort them just in case.
	std::sort(frame_addresses.begin(), frame_addresses.end());

	std::vector<xc7series::ConfigurationFrameRange> ranges;
	for (auto start_of_range = frame_addresses.begin();
	     start_of_range != frame_addresses.end();
	     ) {
		auto end_of_range = start_of_range;
		while (end_of_range + 1 != frame_addresses.end() &&
		       *(end_of_range + 1) == *end_of_range + 1) {
			++end_of_range;
		}

		ranges.push_back(
			xc7series::ConfigurationFrameRange(*start_of_range,
							   *end_of_range+1));

		start_of_range = ++end_of_range;
	}

	std::cout << YAML::Node(xc7series::Part(*idcode, ranges)) << std::endl;

	return 0;
}
<|endoftext|>


<commit_before>
// GridStructGen.cpp

// Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid

#include "Globals.h"
#include "GridStructGen.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEmptyStructure:

/** A cStructure descendant representing an empty structure.
Used when the generator descended from cGridStructGen doesn't return any structure, to keep at least the
Origin coords so that the structure isn't queried over and over again. */
class cEmptyStructure :
	public cGridStructGen::cStructure
{
	typedef cGridStructGen::cStructure super;

public:
	cEmptyStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) :
		super(a_GridX, a_GridZ, a_OriginX, a_OriginZ)
	{
	}

protected:
	virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override
	{
		// Do nothing
	}
} ;

cGridStructGen::cGridStructGen(
	int a_Seed,
	int a_GridSizeX, int a_GridSizeZ,
	int a_MaxOffsetX, int a_MaxOffsetZ,
	int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
	size_t a_MaxCacheSize
) :
	m_Noise(a_Seed),
	m_GridSizeX(a_GridSizeX),
	m_GridSizeZ(a_GridSizeZ),
	m_MaxOffsetX(a_MaxOffsetX),
	m_MaxOffsetZ(a_MaxOffsetZ),
	m_MaxStructureSizeX(a_MaxStructureSizeX),
	m_MaxStructureSizeZ(a_MaxStructureSizeZ),
	m_MaxCacheSize(a_MaxCacheSize)
{
	size_t NumStructuresPerQuery = (size_t)(((m_MaxStructureSizeX + m_MaxOffsetX) / m_GridSizeX + 1) * ((m_MaxStructureSizeZ + m_MaxOffsetZ) / m_GridSizeZ + 1));
	if (NumStructuresPerQuery > m_MaxCacheSize)
	{
		m_MaxCacheSize = NumStructuresPerQuery * 4;
		LOGINFO(
			"cGridStructGen: The cache size is too small (%u), increasing the cache size to %u to avoid inefficiency.",
			(unsigned)a_MaxCacheSize, (unsigned)m_MaxCacheSize
		);
	}
}

void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures)
{
	// Calculate the min and max grid coords of the structures to be returned:
	int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX - m_MaxOffsetX;
	int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ - m_MaxOffsetZ;
	int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + m_MaxOffsetX + cChunkDef::Width - 1;
	int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + m_MaxOffsetZ + cChunkDef::Width - 1;
	int MinGridX = MinBlockX / m_GridSizeX;
	int MinGridZ = MinBlockZ / m_GridSizeZ;
	int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX;
	int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ;
	int MinX = MinGridX * m_GridSizeX;
	int MaxX = MaxGridX * m_GridSizeX;
	int MinZ = MinGridZ * m_GridSizeZ;
	int MaxZ = MaxGridZ * m_GridSizeZ;

	// Walk the cache, move each structure that we want into a_Structures:
	for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
	{
		if (
			((*itr)->m_OriginX >= MinX) && ((*itr)->m_OriginX < MaxX) &&
			((*itr)->m_OriginZ >= MinZ) && ((*itr)->m_OriginZ < MaxZ)
		)
		{
			// want
			a_Structures.push_back(*itr);
			itr = m_Cache.erase(itr);
		}
		else
		{
			// don't want
			++itr;
		}
	}  // for itr - m_Cache[]

	// Create those structures that haven't been in the cache:
	for (int x = MinGridX; x < MaxGridX; x++)
	{
		int GridX = x * m_GridSizeX;
		for (int z = MinGridZ; z < MaxGridZ; z++)
		{
			int GridZ = z * m_GridSizeZ;
			bool Found = false;
			for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr)
			{
				if (((*itr)->m_GridX == GridX) && ((*itr)->m_GridZ == GridZ))
				{
					Found = true;
					break;
				}
			}  // for itr - a_Structures[]
			if (!Found)
			{
				int OriginX = GridX + ((m_Noise.IntNoise2DInt(GridX + 3, GridZ + 5) / 7) % (m_MaxOffsetX * 2)) - m_MaxOffsetX;
				int OriginZ = GridZ + ((m_Noise.IntNoise2DInt(GridX + 5, GridZ + 3) / 7) % (m_MaxOffsetZ * 2)) - m_MaxOffsetZ;
				cStructurePtr Structure = CreateStructure(GridX, GridZ, OriginX, OriginZ);
				if (Structure.get() == NULL)
				{
					Structure.reset(new cEmptyStructure(GridX, GridZ, OriginX, OriginZ));
				}
				a_Structures.push_back(Structure);
			}
		}  // for z
	}  // for x

	// Copy a_Forts into m_Cache to the beginning:
	cStructurePtrs StructuresCopy (a_Structures);
	m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end());

	// Trim the cache if it's too long:
	size_t CacheSize = 0;
	for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
	{
		CacheSize += (*itr)->GetCacheCost();
		if (CacheSize > m_MaxCacheSize)
		{
			// Erase all items from this one till the cache end
			m_Cache.erase(itr, m_Cache.end());
			break;
		}
	}
}

void cGridStructGen::GenFinish(cChunkDesc & a_ChunkDesc)
{
	int ChunkX = a_ChunkDesc.GetChunkX();
	int ChunkZ = a_ChunkDesc.GetChunkZ();
	cStructurePtrs Structures;
	GetStructuresForChunk(ChunkX, ChunkZ, Structures);
	for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr)
	{
		(*itr)->DrawIntoChunk(a_ChunkDesc);
	}  // for itr - Structures[]
}

<commit_msg>Fixed a caching bug in GridStructGen.<commit_after>
// GridStructGen.cpp

// Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid

#include "Globals.h"
#include "GridStructGen.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEmptyStructure:

/** A cStructure descendant representing an empty structure.
Used when the generator descended from cGridStructGen doesn't return any structure, to keep at least the
Origin coords so that the structure isn't queried over and over again. */
class cEmptyStructure :
	public cGridStructGen::cStructure
{
	typedef cGridStructGen::cStructure super;

public:
	cEmptyStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) :
		super(a_GridX, a_GridZ, a_OriginX, a_OriginZ)
	{
	}

protected:
	virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override
	{
		// Do nothing
	}
} ;

cGridStructGen::cGridStructGen(
	int a_Seed,
	int a_GridSizeX, int a_GridSizeZ,
	int a_MaxOffsetX, int a_MaxOffsetZ,
	int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
	size_t a_MaxCacheSize
) :
	m_Noise(a_Seed),
	m_GridSizeX(a_GridSizeX),
	m_GridSizeZ(a_GridSizeZ),
	m_MaxOffsetX(a_MaxOffsetX),
	m_MaxOffsetZ(a_MaxOffsetZ),
	m_MaxStructureSizeX(a_MaxStructureSizeX),
	m_MaxStructureSizeZ(a_MaxStructureSizeZ),
	m_MaxCacheSize(a_MaxCacheSize)
{
	size_t NumStructuresPerQuery = (size_t)(((m_MaxStructureSizeX + m_MaxOffsetX) / m_GridSizeX + 1) * ((m_MaxStructureSizeZ + m_MaxOffsetZ) / m_GridSizeZ + 1));
	if (NumStructuresPerQuery > m_MaxCacheSize)
	{
		m_MaxCacheSize = NumStructuresPerQuery * 4;
		LOGINFO(
			"cGridStructGen: The cache size is too small (%u), increasing the cache size to %u to avoid inefficiency.",
			(unsigned)a_MaxCacheSize, (unsigned)m_MaxCacheSize
		);
	}
}

void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures)
{
	// Calculate the min and max grid coords of the structures to be returned:
	int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX - m_MaxOffsetX;
	int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ - m_MaxOffsetZ;
	int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + m_MaxOffsetX + cChunkDef::Width - 1;
	int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + m_MaxOffsetZ + cChunkDef::Width - 1;
	int MinGridX = MinBlockX / m_GridSizeX;
	int MinGridZ = MinBlockZ / m_GridSizeZ;
	int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX;
	int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ;
	int MinX = MinGridX * m_GridSizeX;
	int MaxX = MaxGridX * m_GridSizeX;
	int MinZ = MinGridZ * m_GridSizeZ;
	int MaxZ = MaxGridZ * m_GridSizeZ;

	// Walk the cache, move each structure that we want into a_Structures:
	for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
	{
		if (
			((*itr)->m_GridX >= MinX) && ((*itr)->m_GridX < MaxX) &&
			((*itr)->m_GridZ >= MinZ) && ((*itr)->m_GridZ < MaxZ)
		)
		{
			// want
			a_Structures.push_back(*itr);
			itr = m_Cache.erase(itr);
		}
		else
		{
			// don't want
			++itr;
		}
	}  // for itr - m_Cache[]

	// Create those structures that haven't been in the cache:
	for (int x = MinGridX; x < MaxGridX; x++)
	{
		int GridX = x * m_GridSizeX;
		for (int z = MinGridZ; z < MaxGridZ; z++)
		{
			int GridZ = z * m_GridSizeZ;
			bool Found = false;
			for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr)
			{
				if (((*itr)->m_GridX == GridX) && ((*itr)->m_GridZ == GridZ))
				{
					Found = true;
					break;
				}
			}  // for itr - a_Structures[]
			if (!Found)
			{
				int OriginX = GridX + ((m_Noise.IntNoise2DInt(GridX + 3, GridZ + 5) / 7) % (m_MaxOffsetX * 2)) - m_MaxOffsetX;
				int OriginZ = GridZ + ((m_Noise.IntNoise2DInt(GridX + 5, GridZ + 3) / 7) % (m_MaxOffsetZ * 2)) - m_MaxOffsetZ;
				cStructurePtr Structure = CreateStructure(GridX, GridZ, OriginX, OriginZ);
				if (Structure.get() == NULL)
				{
					Structure.reset(new cEmptyStructure(GridX, GridZ, OriginX, OriginZ));
				}
				a_Structures.push_back(Structure);
			}
		}  // for z
	}  // for x

	// Copy a_Forts into m_Cache to the beginning:
	cStructurePtrs StructuresCopy (a_Structures);
	m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end());

	// Trim the cache if it's too long:
	size_t CacheSize = 0;
	for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
	{
		CacheSize += (*itr)->GetCacheCost();
		if (CacheSize > m_MaxCacheSize)
		{
			// Erase all items from this one till the cache end
			m_Cache.erase(itr, m_Cache.end());
			break;
		}
	}
}

void cGridStructGen::GenFinish(cChunkDesc & a_ChunkDesc)
{
	int ChunkX = a_ChunkDesc.GetChunkX();
	int ChunkZ = a_ChunkDesc.GetChunkZ();
	cStructurePtrs Structures;
	GetStructuresForChunk(ChunkX, ChunkZ, Structures);
	for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr)
	{
		(*itr)->DrawIntoChunk(a_ChunkDesc);
	}  // for itr - Structures[]
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006  Thomas Sondergaard   All Rights Reserved.
 *
 * 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
 * BRIAN PAUL 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 "gltrace_support.h"
#include <sstream>
#include <fstream>
#include <iomanip>
#include <execinfo.h>
#include <cxxabi.h>
#include <sys/time.h>

namespace {

  const char *
  demangle (const char * mangled) throw()
  {
    static char buf[4096];
    int status;
    unsigned int length = sizeof(buf)-1;

    memset (buf, 0, sizeof(buf));

    if (!mangled)
      return 0;

    char * demangled =  __cxxabiv1::__cxa_demangle(mangled,
                                                   buf,
                                                   &length,
                                                   &status);
    if (demangled && !status)
      return demangled;
    else
      return mangled;
  }

  void
  printStackTrace (void **stackframes,
		   int stackframe_size,
		   std::ostream & out  )
  {
    char **strings = 0;
    std::stringstream ss;

    // this might actually fail if memory is tight or we are in a
    // signal handler
    strings = backtrace_symbols (stackframes, stackframe_size);

    ss <<  "Backtrace :";

    if (stackframe_size == gltrace::MAX_STACKFRAMES)
      ss << "(possibly incomplete maximal number of frames exceeded):" << std::endl;
    else
      ss << std::endl;

    out << ss.str();

    // the first frame is the constructor of the exception
    // the last frame always seem to be bogus?
    for (int i = 0; strings && i < stackframe_size-1; ++i) {
      char libname[257], funcname[2049];
      unsigned int address=0, funcoffset = 0x0;

      memset (libname,0,sizeof(libname));
      memset (funcname,0,sizeof(funcname));

      strcpy (funcname,"??");
      strcpy (libname, "??");

      int scanned = sscanf (strings[i], "%256[^(] ( %2048[^+] + %x ) [ %x ]",
			    libname,
			    funcname,
			    &funcoffset,
			    &address);

      /* ok, so no function was mentioned in the backtrace */
      if (scanned < 4) {
	scanned = sscanf (strings[i], "%256[^([] [ %x ]",
			  libname,
			  &address);
      }

      if (funcname[0] == '_') {
	const char * demangled;
	if ((demangled = demangle(funcname) ) != funcname) {
	  strncpy (funcname, demangled, sizeof(funcname)-1);
	}
      }
      else
	strcat (funcname," ()");

      out << "\t#" << i << std::hex << " 0x" << address << " in " << funcname
	  << " at 0x" << funcoffset << " (from " << libname << ")" << std::endl;
    }

    free (strings);
  }

} // anon namespace

namespace gltrace {

  std::string getStackTrace(int count, int first) {
    ++first;
    std::stringstream ss;
    const int BA_MAX = 1000;
    assert(count + first <= BA_MAX);
    void *ba[BA_MAX];
    int n = backtrace(ba, count+first);

    printStackTrace( &ba[first], n-first, ss);

    return ss.str();
  }

  std::ostream &timeNow(std::ostream &os) {

    struct timeval now;
    struct tm t;
    static char *months[12] =
      {
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
      };

    gettimeofday (&now, 0);
    localtime_r  ((time_t*) &now.tv_sec, &t);

    os
      << months[t.tm_mon] << " "
      << std::setw(2) << t.tm_mday << " "
      << std::setw(2) << t.tm_hour << ":"
      << std::setw(2) << t.tm_min  << ":"
      << std::setw(2) << t.tm_sec  << "."
      << std::setw(3) << now.tv_usec/1000;
    return os;
  }

  logstream::logstream(const char *filename) {
    if (!filename)
      init(std::cerr.rdbuf());
    else {
      file_os.reset(new std::ofstream(filename));
      if (file_os->good())
	init(file_os->rdbuf());
      else {
	std::cerr << "ERROR: gltrace: Failed to open '" << filename
		  <<  "' for writing. Falling back to stderr." << std::endl;
	init(std::cerr.rdbuf());
      }
    }
    *this << std::setfill('0'); // setw used in timeNow
  }

  Config::Config() :
    logCalls(true),
    checkErrors(true),
    logTime(true),
    log(getenv("GLTRACE_LOGFILE")) {
    if (const char *v = getenv("GLTRACE_LOG_CALLS"))
      logCalls = strncmp("1", v, 1) == 0;
    if (const char *v = getenv("GLTRACE_CHECK_ERRORS"))
      checkErrors = strncmp("1", v, 1) == 0;
    if (const char *v = getenv("GLTRACE_LOG_TIME"))
      logTime = strncmp("1", v, 1) == 0;
  }

  // *The* config
  Config config;

} // namespace gltrace
<commit_msg>include assert.h<commit_after>/*
 * Copyright (C) 2006  Thomas Sondergaard   All Rights Reserved.
 *
 * 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
 * BRIAN PAUL 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 "gltrace_support.h"
#include <assert.h>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <execinfo.h>
#include <cxxabi.h>
#include <sys/time.h>

namespace {

  const char *
  demangle (const char * mangled) throw()
  {
    static char buf[4096];
    int status;
    unsigned int length = sizeof(buf)-1;

    memset (buf, 0, sizeof(buf));

    if (!mangled)
      return 0;

    char * demangled =  __cxxabiv1::__cxa_demangle(mangled,
                                                   buf,
                                                   &length,
                                                   &status);
    if (demangled && !status)
      return demangled;
    else
      return mangled;
  }

  void
  printStackTrace (void **stackframes,
		   int stackframe_size,
		   std::ostream & out  )
  {
    char **strings = 0;
    std::stringstream ss;

    // this might actually fail if memory is tight or we are in a
    // signal handler
    strings = backtrace_symbols (stackframes, stackframe_size);

    ss <<  "Backtrace :";

    if (stackframe_size == gltrace::MAX_STACKFRAMES)
      ss << "(possibly incomplete maximal number of frames exceeded):" << std::endl;
    else
      ss << std::endl;

    out << ss.str();

    // the first frame is the constructor of the exception
    // the last frame always seem to be bogus?
    for (int i = 0; strings && i < stackframe_size-1; ++i) {
      char libname[257], funcname[2049];
      unsigned int address=0, funcoffset = 0x0;

      memset (libname,0,sizeof(libname));
      memset (funcname,0,sizeof(funcname));

      strcpy (funcname,"??");
      strcpy (libname, "??");

      int scanned = sscanf (strings[i], "%256[^(] ( %2048[^+] + %x ) [ %x ]",
			    libname,
			    funcname,
			    &funcoffset,
			    &address);

      /* ok, so no function was mentioned in the backtrace */
      if (scanned < 4) {
	scanned = sscanf (strings[i], "%256[^([] [ %x ]",
			  libname,
			  &address);
      }

      if (funcname[0] == '_') {
	const char * demangled;
	if ((demangled = demangle(funcname) ) != funcname) {
	  strncpy (funcname, demangled, sizeof(funcname)-1);
	}
      }
      else
	strcat (funcname," ()");

      out << "\t#" << i << std::hex << " 0x" << address << " in " << funcname
	  << " at 0x" << funcoffset << " (from " << libname << ")" << std::endl;
    }

    free (strings);
  }

} // anon namespace

namespace gltrace {

  std::string getStackTrace(int count, int first) {
    ++first;
    std::stringstream ss;
    const int BA_MAX = 1000;
    assert(count + first <= BA_MAX);
    void *ba[BA_MAX];
    int n = backtrace(ba, count+first);

    printStackTrace( &ba[first], n-first, ss);

    return ss.str();
  }

  std::ostream &timeNow(std::ostream &os) {

    struct timeval now;
    struct tm t;
    static char *months[12] =
      {
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
      };

    gettimeofday (&now, 0);
    localtime_r  ((time_t*) &now.tv_sec, &t);

    os
      << months[t.tm_mon] << " "
      << std::setw(2) << t.tm_mday << " "
      << std::setw(2) << t.tm_hour << ":"
      << std::setw(2) << t.tm_min  << ":"
      << std::setw(2) << t.tm_sec  << "."
      << std::setw(3) << now.tv_usec/1000;
    return os;
  }

  logstream::logstream(const char *filename) {
    if (!filename)
      init(std::cerr.rdbuf());
    else {
      file_os.reset(new std::ofstream(filename));
      if (file_os->good())
	init(file_os->rdbuf());
      else {
	std::cerr << "ERROR: gltrace: Failed to open '" << filename
		  <<  "' for writing. Falling back to stderr." << std::endl;
	init(std::cerr.rdbuf());
      }
    }
    *this << std::setfill('0'); // setw used in timeNow
  }

  Config::Config() :
    logCalls(true),
    checkErrors(true),
    logTime(true),
    log(getenv("GLTRACE_LOGFILE")) {
    if (const char *v = getenv("GLTRACE_LOG_CALLS"))
      logCalls = strncmp("1", v, 1) == 0;
    if (const char *v = getenv("GLTRACE_CHECK_ERRORS"))
      checkErrors = strncmp("1", v, 1) == 0;
    if (const char *v = getenv("GLTRACE_LOG_TIME"))
      logTime = strncmp("1", v, 1) == 0;
  }

  // *The* config
  Config config;

} // namespace gltrace
<|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/chromeos/wm_ipc.h"

#include <gdk/gdkx.h>
extern "C" {
#include <X11/Xlib.h>
}

#include "base/logging.h"
#include "base/singleton.h"
#include "base/scoped_ptr.h"
#include "chrome/common/x11_util.h"

namespace chromeos {

namespace {

// A value from the Atom enum and the actual name that should be used to
// look up its ID on the X server.
struct AtomInfo {
  WmIpc::AtomType atom;
  const char* name;
};

// Each value from the Atom enum must be present here.
static const AtomInfo kAtomInfos[] = {
  { WmIpc::ATOM_CHROME_WINDOW_TYPE,      "_CHROME_WINDOW_TYPE" },
  { WmIpc::ATOM_CHROME_WM_MESSAGE,       "_CHROME_WM_MESSAGE" },
  { WmIpc::ATOM_MANAGER,                 "MANAGER" },
  { WmIpc::ATOM_NET_SUPPORTING_WM_CHECK, "_NET_SUPPORTING_WM_CHECK" },
  { WmIpc::ATOM_NET_WM_NAME,             "_NET_WM_NAME" },
  { WmIpc::ATOM_PRIMARY,                 "PRIMARY" },
  { WmIpc::ATOM_STRING,                  "STRING" },
  { WmIpc::ATOM_UTF8_STRING,             "UTF8_STRING" },
  { WmIpc::ATOM_WM_NORMAL_HINTS,         "WM_NORMAL_HINTS" },
  { WmIpc::ATOM_WM_S0,                   "WM_S0" },
  { WmIpc::ATOM_WM_STATE,                "WM_STATE" },
  { WmIpc::ATOM_WM_TRANSIENT_FOR,        "WM_TRANSIENT_FOR" },
  { WmIpc::ATOM_WM_SYSTEM_METRICS,       "WM_SYSTEM_METRICS" },
};

bool SetIntProperty(XID xid, Atom xatom, const std::vector<int>& values) {
  DCHECK(!values.empty());

  // TODO: Trap errors and return false on failure.
  XChangeProperty(x11_util::GetXDisplay(),
                  xid,
                  xatom,
                  xatom,
                  32,  // size in bits of items in 'value'
                  PropModeReplace,
                  reinterpret_cast<const unsigned char*>(&values.front()),
                  values.size());  // num items
  XFlush(x11_util::GetXDisplay());
  return true;
}

}  // namespace

// static
WmIpc* WmIpc::instance() {
  static WmIpc* instance = NULL;
  if (!instance)
    instance = Singleton<WmIpc>::get();
  return instance;
}

bool WmIpc::SetWindowType(GtkWidget* widget,
                          WindowType type,
                          const std::vector<int>* params) {
  std::vector<int> values;
  values.push_back(type);
  if (params)
    values.insert(values.end(), params->begin(), params->end());
  return SetIntProperty(x11_util::GetX11WindowFromGtkWidget(widget),
                        type_to_atom_[ATOM_CHROME_WINDOW_TYPE], values);
}

void WmIpc::SendMessage(const Message& msg) {
  XEvent e;
  e.xclient.type = ClientMessage;
  e.xclient.window = wm_;
  e.xclient.message_type = type_to_atom_[ATOM_CHROME_WM_MESSAGE];
  e.xclient.format = 32;  // 32-bit values
  e.xclient.data.l[0] = msg.type();

  // XClientMessageEvent only gives us five 32-bit items, and we're using
  // the first one for our message type.
  DCHECK_LE(msg.max_params(), 4);
  for (int i = 0; i < msg.max_params(); ++i)
    e.xclient.data.l[i+1] = msg.param(i);

  XSendEvent(x11_util::GetXDisplay(),
             wm_,
             False,  // propagate
             0,  // empty event mask
             &e);
}

bool WmIpc::DecodeMessage(const GdkEventClient& event,
                          Message* msg) {
  if (wm_message_atom_ != gdk_x11_atom_to_xatom(event.message_type))
    return false;

  if (event.data_format != 32) {
    DLOG(WARNING) << "Ignoring ClientEventMessage with invalid bit "
                  << "format " << event.data_format
                  << " (expected 32-bit values)";
    return false;
  }

  msg->set_type(static_cast<Message::Type>(event.data.l[0]));
  if (msg->type() < 0 || msg->type() >= Message::kNumTypes) {
    DLOG(WARNING) << "Ignoring ClientEventMessage with invalid message "
                  << "type " << msg->type();
    return false;
  }

  // XClientMessageEvent only gives us five 32-bit items, and we're using
  // the first one for our message type.
  DCHECK_LE(msg->max_params(), 4);
  for (int i = 0; i < msg->max_params(); ++i)
    msg->set_param(i, event.data.l[i+1]);  // l[0] contains message type

  return true;
}

bool WmIpc::DecodeStringMessage(const GdkEventProperty& event,
                                std::string* msg) {
  DCHECK(NULL != msg);
  if (type_to_atom_[ATOM_WM_SYSTEM_METRICS] !=
      gdk_x11_atom_to_xatom(event.atom))
    return false;

  DLOG(WARNING) << "Got property change notification for system metrics.";
  if (GDK_PROPERTY_DELETE == event.state) {
    DLOG(WARNING) << "Ignoring delete EventPropertyNotification";
    return false;
  }

  // We will be using DBus for this communication in the future, so I don't
  // really worry right now that we could generate more than 1KB here.
  // Also, I use "long" rather than int64 because that is what X expects.
  long acceptable_bytes = 1024;
  Atom actual_type;
  int actual_format;
  unsigned long num_items, bytes_left;
  unsigned char *output;
  if (Success != XGetWindowProperty(x11_util::GetXDisplay(),
                                    GDK_WINDOW_XID(event.window),
                                    type_to_atom_[ATOM_WM_SYSTEM_METRICS],
                                    0,
                                    acceptable_bytes,
                                    false,
                                    AnyPropertyType,
                                    &actual_type,
                                    &actual_format,
                                    &num_items,
                                    &bytes_left,
                                    &output)) {
    DLOG(WARNING) << "Could not read system metrics property from X.";
    return false;
  }
  if (actual_format == 0) {
    DLOG(WARNING) << "System Metrics property not set.";
    return false;
  }
  if (actual_format != 8) {
    DLOG(WARNING) << "Message was not encoded as a string of bytes...";
    return false;
  }
  if (bytes_left != 0) {
    DLOG(ERROR) << "We wanted all the bytes at once...";
    return false;
  }
  msg->assign(reinterpret_cast<char*>(output), num_items);
  XFree(output);
  return true;
}

void WmIpc::HandleNonChromeClientMessageEvent(const GdkEventClient& event) {
  // Only do these lookups once; they should never change.
  static GdkAtom manager_gdk_atom =
      gdk_x11_xatom_to_atom(type_to_atom_[ATOM_MANAGER]);
  static Atom wm_s0_atom = type_to_atom_[ATOM_WM_S0];

  if (event.message_type == manager_gdk_atom &&
      static_cast<Atom>(event.data.l[1]) == wm_s0_atom) {
    InitWmInfo();
  }
}

WmIpc::WmIpc() {
  scoped_array<char*> names(new char*[kNumAtoms]);
  scoped_array<Atom> atoms(new Atom[kNumAtoms]);

  for (int i = 0; i < kNumAtoms; ++i) {
    // Need to const_cast because XInternAtoms() wants a char**.
    names[i] = const_cast<char*>(kAtomInfos[i].name);
  }

  XInternAtoms(x11_util::GetXDisplay(), names.get(), kNumAtoms,
               False,  // only_if_exists
               atoms.get());

  for (int i = 0; i < kNumAtoms; ++i) {
    type_to_atom_[kAtomInfos[i].atom] = atoms[i];
    atom_to_string_[atoms[i]] = kAtomInfos[i].name;
  }

  wm_message_atom_ = type_to_atom_[ATOM_CHROME_WM_MESSAGE];

  // Make sure that we're selecting structure changes on the root window;
  // the window manager uses StructureNotifyMask when sending the ClientMessage
  // event to announce that it's taken the manager selection.
  GdkWindow* root = gdk_get_default_root_window();
  GdkEventMask event_mask = gdk_window_get_events(root);
  gdk_window_set_events(
      root, static_cast<GdkEventMask>(event_mask | GDK_STRUCTURE_MASK));

  InitWmInfo();
}

void WmIpc::InitWmInfo() {
  wm_ = XGetSelectionOwner(x11_util::GetXDisplay(), type_to_atom_[ATOM_WM_S0]);

  // Let the window manager know which version of the IPC messages we support.
  Message msg(Message::WM_NOTIFY_IPC_VERSION);
  // TODO: The version number is the latest listed in wm_ipc.h --
  // ideally, once this header is shared between Chrome and the Chrome OS window
  // manager, we'll just define the version statically in the header.
  msg.set_param(0, 1);
  SendMessage(msg);
}

}  // namespace chromeos
<commit_msg>Fixes bug in wm_ipc where we were passing ints to XChangeProperty when we should have been passing longs.<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/chromeos/wm_ipc.h"

#include <gdk/gdkx.h>
extern "C" {
#include <X11/Xlib.h>
}

#include "base/logging.h"
#include "base/singleton.h"
#include "base/scoped_ptr.h"
#include "chrome/common/x11_util.h"

namespace chromeos {

namespace {

// A value from the Atom enum and the actual name that should be used to
// look up its ID on the X server.
struct AtomInfo {
  WmIpc::AtomType atom;
  const char* name;
};

// Each value from the Atom enum must be present here.
static const AtomInfo kAtomInfos[] = {
  { WmIpc::ATOM_CHROME_WINDOW_TYPE,      "_CHROME_WINDOW_TYPE" },
  { WmIpc::ATOM_CHROME_WM_MESSAGE,       "_CHROME_WM_MESSAGE" },
  { WmIpc::ATOM_MANAGER,                 "MANAGER" },
  { WmIpc::ATOM_NET_SUPPORTING_WM_CHECK, "_NET_SUPPORTING_WM_CHECK" },
  { WmIpc::ATOM_NET_WM_NAME,             "_NET_WM_NAME" },
  { WmIpc::ATOM_PRIMARY,                 "PRIMARY" },
  { WmIpc::ATOM_STRING,                  "STRING" },
  { WmIpc::ATOM_UTF8_STRING,             "UTF8_STRING" },
  { WmIpc::ATOM_WM_NORMAL_HINTS,         "WM_NORMAL_HINTS" },
  { WmIpc::ATOM_WM_S0,                   "WM_S0" },
  { WmIpc::ATOM_WM_STATE,                "WM_STATE" },
  { WmIpc::ATOM_WM_TRANSIENT_FOR,        "WM_TRANSIENT_FOR" },
  { WmIpc::ATOM_WM_SYSTEM_METRICS,       "WM_SYSTEM_METRICS" },
};

bool SetIntProperty(XID xid, Atom xatom, const std::vector<int>& values) {
  DCHECK(!values.empty());

  // XChangeProperty expects values of type 32 to be longs.
  scoped_array<long> data(new long[values.size()]);
  for (size_t i = 0; i < values.size(); ++i)
    data[i] = values[i];

  // TODO: Trap errors and return false on failure.
  XChangeProperty(x11_util::GetXDisplay(),
                  xid,
                  xatom,
                  xatom,
                  32,  // size in bits of items in 'value'
                  PropModeReplace,
                  reinterpret_cast<const unsigned char*>(data.get()),
                  values.size());  // num items
  XFlush(x11_util::GetXDisplay());
  return true;
}

}  // namespace

// static
WmIpc* WmIpc::instance() {
  static WmIpc* instance = NULL;
  if (!instance)
    instance = Singleton<WmIpc>::get();
  return instance;
}

bool WmIpc::SetWindowType(GtkWidget* widget,
                          WindowType type,
                          const std::vector<int>* params) {
  std::vector<int> values;
  values.push_back(type);
  if (params)
    values.insert(values.end(), params->begin(), params->end());
  return SetIntProperty(x11_util::GetX11WindowFromGtkWidget(widget),
                        type_to_atom_[ATOM_CHROME_WINDOW_TYPE], values);
}

void WmIpc::SendMessage(const Message& msg) {
  XEvent e;
  e.xclient.type = ClientMessage;
  e.xclient.window = wm_;
  e.xclient.message_type = type_to_atom_[ATOM_CHROME_WM_MESSAGE];
  e.xclient.format = 32;  // 32-bit values
  e.xclient.data.l[0] = msg.type();

  // XClientMessageEvent only gives us five 32-bit items, and we're using
  // the first one for our message type.
  DCHECK_LE(msg.max_params(), 4);
  for (int i = 0; i < msg.max_params(); ++i)
    e.xclient.data.l[i+1] = msg.param(i);

  XSendEvent(x11_util::GetXDisplay(),
             wm_,
             False,  // propagate
             0,  // empty event mask
             &e);
}

bool WmIpc::DecodeMessage(const GdkEventClient& event,
                          Message* msg) {
  if (wm_message_atom_ != gdk_x11_atom_to_xatom(event.message_type))
    return false;

  if (event.data_format != 32) {
    DLOG(WARNING) << "Ignoring ClientEventMessage with invalid bit "
                  << "format " << event.data_format
                  << " (expected 32-bit values)";
    return false;
  }

  msg->set_type(static_cast<Message::Type>(event.data.l[0]));
  if (msg->type() < 0 || msg->type() >= Message::kNumTypes) {
    DLOG(WARNING) << "Ignoring ClientEventMessage with invalid message "
                  << "type " << msg->type();
    return false;
  }

  // XClientMessageEvent only gives us five 32-bit items, and we're using
  // the first one for our message type.
  DCHECK_LE(msg->max_params(), 4);
  for (int i = 0; i < msg->max_params(); ++i)
    msg->set_param(i, event.data.l[i+1]);  // l[0] contains message type

  return true;
}

bool WmIpc::DecodeStringMessage(const GdkEventProperty& event,
                                std::string* msg) {
  DCHECK(NULL != msg);
  if (type_to_atom_[ATOM_WM_SYSTEM_METRICS] !=
      gdk_x11_atom_to_xatom(event.atom))
    return false;

  DLOG(WARNING) << "Got property change notification for system metrics.";
  if (GDK_PROPERTY_DELETE == event.state) {
    DLOG(WARNING) << "Ignoring delete EventPropertyNotification";
    return false;
  }

  // We will be using DBus for this communication in the future, so I don't
  // really worry right now that we could generate more than 1KB here.
  // Also, I use "long" rather than int64 because that is what X expects.
  long acceptable_bytes = 1024;
  Atom actual_type;
  int actual_format;
  unsigned long num_items, bytes_left;
  unsigned char *output;
  if (Success != XGetWindowProperty(x11_util::GetXDisplay(),
                                    GDK_WINDOW_XID(event.window),
                                    type_to_atom_[ATOM_WM_SYSTEM_METRICS],
                                    0,
                                    acceptable_bytes,
                                    false,
                                    AnyPropertyType,
                                    &actual_type,
                                    &actual_format,
                                    &num_items,
                                    &bytes_left,
                                    &output)) {
    DLOG(WARNING) << "Could not read system metrics property from X.";
    return false;
  }
  if (actual_format == 0) {
    DLOG(WARNING) << "System Metrics property not set.";
    return false;
  }
  if (actual_format != 8) {
    DLOG(WARNING) << "Message was not encoded as a string of bytes...";
    return false;
  }
  if (bytes_left != 0) {
    DLOG(ERROR) << "We wanted all the bytes at once...";
    return false;
  }
  msg->assign(reinterpret_cast<char*>(output), num_items);
  XFree(output);
  return true;
}

void WmIpc::HandleNonChromeClientMessageEvent(const GdkEventClient& event) {
  // Only do these lookups once; they should never change.
  static GdkAtom manager_gdk_atom =
      gdk_x11_xatom_to_atom(type_to_atom_[ATOM_MANAGER]);
  static Atom wm_s0_atom = type_to_atom_[ATOM_WM_S0];

  if (event.message_type == manager_gdk_atom &&
      static_cast<Atom>(event.data.l[1]) == wm_s0_atom) {
    InitWmInfo();
  }
}

WmIpc::WmIpc() {
  scoped_array<char*> names(new char*[kNumAtoms]);
  scoped_array<Atom> atoms(new Atom[kNumAtoms]);

  for (int i = 0; i < kNumAtoms; ++i) {
    // Need to const_cast because XInternAtoms() wants a char**.
    names[i] = const_cast<char*>(kAtomInfos[i].name);
  }

  XInternAtoms(x11_util::GetXDisplay(), names.get(), kNumAtoms,
               False,  // only_if_exists
               atoms.get());

  for (int i = 0; i < kNumAtoms; ++i) {
    type_to_atom_[kAtomInfos[i].atom] = atoms[i];
    atom_to_string_[atoms[i]] = kAtomInfos[i].name;
  }

  wm_message_atom_ = type_to_atom_[ATOM_CHROME_WM_MESSAGE];

  // Make sure that we're selecting structure changes on the root window;
  // the window manager uses StructureNotifyMask when sending the ClientMessage
  // event to announce that it's taken the manager selection.
  GdkWindow* root = gdk_get_default_root_window();
  GdkEventMask event_mask = gdk_window_get_events(root);
  gdk_window_set_events(
      root, static_cast<GdkEventMask>(event_mask | GDK_STRUCTURE_MASK));

  InitWmInfo();
}

void WmIpc::InitWmInfo() {
  wm_ = XGetSelectionOwner(x11_util::GetXDisplay(), type_to_atom_[ATOM_WM_S0]);

  // Let the window manager know which version of the IPC messages we support.
  Message msg(Message::WM_NOTIFY_IPC_VERSION);
  // TODO: The version number is the latest listed in wm_ipc.h --
  // ideally, once this header is shared between Chrome and the Chrome OS window
  // manager, we'll just define the version statically in the header.
  msg.set_param(0, 1);
  SendMessage(msg);
}

}  // namespace chromeos
<|endoftext|>