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

#include <EGL/egl.h>

#include <cstddef>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "glad/glad.h"
#include "libshadertrap/api_version.h"
#include "libshadertrap/checker.h"
#include "libshadertrap/command_visitor.h"
#include "libshadertrap/compound_visitor.h"
#include "libshadertrap/executor.h"
#include "libshadertrap/gl_functions.h"
#include "libshadertrap/glslang.h"
#include "libshadertrap/make_unique.h"
#include "libshadertrap/message_consumer.h"
#include "libshadertrap/parser.h"
#include "libshadertrap/shadertrap_program.h"
#include "libshadertrap/token.h"
#include "shadertrap/get_gl_functions.h"

namespace {

const EGLint kWidth = 256;
const EGLint kHeight = 256;
const EGLint kDepthSize = 16;
const EGLint kRequiredEglMinorVersionForGl = 5;

const char* const kOptionPrefix = "--";
const char* const kOptionShowGlInfo = "--show_gl_info";

class ConsoleMessageConsumer : public shadertrap::MessageConsumer {
  void Message(Severity severity, const shadertrap::Token* token,
               const std::string& message) override {
    switch (severity) {
      case MessageConsumer::Severity::kError:
        std::cerr << "ERROR";
        break;
      case MessageConsumer::Severity::kWarning:
        std::cerr << "WARNING";
        break;
    }
    std::cerr << " at ";
    if (token == nullptr) {
      std::cerr << "unknown location";
    } else {
      std::cerr << token->GetLocationString();
    }
    std::cerr << ": " << message << std::endl;
  }
};

std::vector<char> ReadFile(const std::string& input_file) {
  std::ifstream file(input_file);
  std::ostringstream stringstream;
  stringstream << file.rdbuf();
  const std::string& temp = stringstream.str();
  return std::vector<char>(temp.begin(), temp.end());
}

}  // namespace

#define SHOW_GL_STRING(name)                                            \
  do {                                                                  \
    auto* gl_string = glGetString(name);                                \
    if (glGetError() != GL_NO_ERROR) {                                  \
      std::cerr << "Error calling glGetString(" #name ")" << std::endl; \
      return 1;                                                         \
    }                                                                   \
    std::cout << "GL_VENDOR: " << gl_string << std::endl;               \
  } while (false)

int main(int argc, const char** argv) {
  std::vector<std::string> args(argv, argv + argc);
  if (args.size() < 2) {
    std::cerr << "Usage: " << args[0] + "[options] SCRIPT" << std::endl;
    std::cerr << "Options:" << std::endl;
    std::cerr << "  " << kOptionShowGlInfo << std::endl;
    std::cerr << "    Show GL information before running the script"
              << std::endl;
    return 1;
  }

  bool show_gl_info = false;
  std::string script_name;
  std::string option_prefix(kOptionPrefix);
  for (size_t i = 1; i < static_cast<size_t>(argc); i++) {
    std::string argument(argv[i]);
    if (argument == kOptionShowGlInfo) {
      show_gl_info = true;
    } else if (argument.length() >= option_prefix.length() &&
               argument.substr(0, option_prefix.length()) == option_prefix) {
      std::cerr << "Unknown option " << argument << std::endl;
      return 1;
    } else if (!script_name.empty()) {
      std::cerr << "Multiple script names provided." << std::endl;
      return 1;
    } else {
      script_name = argument;
    }
  }

  if (script_name.empty()) {
    std::cerr << "No script name was provided." << std::endl;
    return 1;
  }

  auto char_data = ReadFile(script_name);
  auto data = std::string(char_data.begin(), char_data.end());

  ConsoleMessageConsumer message_consumer;
  shadertrap::Parser parser(data, &message_consumer);
  if (!parser.Parse()) {
    return 1;
  }

  std::unique_ptr<shadertrap::ShaderTrapProgram> shadertrap_program =
      parser.GetParsedProgram();

  shadertrap::ApiVersion api_version = shadertrap_program->GetApiVersion();

  EGLDisplay display;
  EGLConfig config;
  EGLContext context;
  EGLSurface surface;

  std::vector<EGLint> config_attributes = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
                                           EGL_RED_SIZE,     4,
                                           EGL_GREEN_SIZE,   4,
                                           EGL_BLUE_SIZE,    4,
                                           EGL_ALPHA_SIZE,   4,

                                           EGL_CONFORMANT,   EGL_OPENGL_ES3_BIT,
                                           EGL_DEPTH_SIZE,   kDepthSize,
                                           EGL_NONE};

  std::vector<EGLint> context_attributes = {
      EGL_CONTEXT_MAJOR_VERSION,
      static_cast<EGLint>(api_version.GetMajorVersion()),
      EGL_CONTEXT_MINOR_VERSION,
      static_cast<EGLint>(api_version.GetMinorVersion()), EGL_NONE};

  // TODO(afd): For offscreen rendering, do width and height matter?  If no,
  //  are there more sensible default values than these?  If yes, should they be
  //  controllable from the command line?
  std::vector<EGLint> pbuffer_attributes = {EGL_WIDTH,
                                            kWidth,
                                            EGL_HEIGHT,
                                            kHeight,
                                            EGL_TEXTURE_FORMAT,
                                            EGL_NO_TEXTURE,
                                            EGL_TEXTURE_TARGET,
                                            EGL_NO_TEXTURE,
                                            EGL_LARGEST_PBUFFER,
                                            EGL_TRUE,
                                            EGL_NONE};

  display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

  EGLint egl_major_version;
  EGLint egl_minor_version;

  if (eglInitialize(display, &egl_major_version, &egl_minor_version) ==
      EGL_FALSE) {
    std::cerr << "eglInitialize failed." << std::endl;
    return 1;
  }

  if (api_version.GetApi() == shadertrap::ApiVersion::Api::GL &&
      !(egl_major_version > 1 ||
        (egl_major_version == 1 &&
         egl_minor_version >= kRequiredEglMinorVersionForGl))) {
    std::cerr << "EGL and OpenGL are not compatible pre EGL 1.5; found EGL "
              << egl_major_version << "." << egl_minor_version << std::endl;
    return 1;
  }

  if (eglBindAPI(static_cast<EGLenum>(api_version.GetApi() ==
                                              shadertrap::ApiVersion::Api::GL
                                          ? EGL_OPENGL_API
                                          : EGL_OPENGL_ES_API)) == EGL_FALSE) {
    std::cerr << "eglBindAPI failed." << std::endl;
  }

  EGLint num_config;
  if (eglChooseConfig(display, config_attributes.data(), &config, 1,
                      &num_config) == EGL_FALSE) {
    std::cerr << "eglChooseConfig failed." << std::endl;
    return 1;
  }

  if (num_config != 1) {
    std::cerr << "ERROR: eglChooseConfig returned " << num_config
              << " configurations; exactly 1 configuration is required";
    return 1;
  }

  context = eglCreateContext(display, config, EGL_NO_CONTEXT,
                             context_attributes.data());
  if (context == EGL_NO_CONTEXT) {
    std::cerr << "eglCreateContext failed." << std::endl;
    return 1;
  }

  surface = eglCreatePbufferSurface(display, config, pbuffer_attributes.data());
  if (surface == EGL_NO_SURFACE) {
    std::cerr << "eglCreatePbufferSurface failed." << std::endl;
    return 1;
  }

  eglMakeCurrent(display, surface, surface, context);

  if (api_version.GetApi() == shadertrap::ApiVersion::Api::GL) {
    if (gladLoadGLLoader(reinterpret_cast<GLADloadproc>(eglGetProcAddress)) ==
        0) {
      std::cerr << "gladLoadGLLoader failed." << std::endl;
      return 1;
    }
  } else {
    if (gladLoadGLES2Loader(
            reinterpret_cast<GLADloadproc>(eglGetProcAddress)) == 0) {
      std::cerr << "gladLoadGLES2Loader failed." << std::endl;
      return 1;
    }
  }

  if (show_gl_info) {
    SHOW_GL_STRING(GL_VENDOR);
    SHOW_GL_STRING(GL_RENDERER);
    SHOW_GL_STRING(GL_VERSION);
    SHOW_GL_STRING(GL_SHADING_LANGUAGE_VERSION);
  }

  shadertrap::GlFunctions functions = shadertrap::GetGlFunctions();

  std::vector<std::unique_ptr<shadertrap::CommandVisitor>> temp;
  temp.push_back(shadertrap::MakeUnique<shadertrap::Checker>(
      &message_consumer, shadertrap_program->GetApiVersion()));
  temp.push_back(shadertrap::MakeUnique<shadertrap::Executor>(
      &functions, &message_consumer, shadertrap_program->GetApiVersion()));
  shadertrap::CompoundVisitor checker_and_executor(std::move(temp));
  ShInitialize();
  bool success = checker_and_executor.VisitCommands(shadertrap_program.get());
  ShFinalize();
  if (!success) {
    std::cerr << "Errors occurred during execution." << std::endl;
    return 1;
  }
  std::cerr << "SUCCESS!" << std::endl;
  return 0;
}
<commit_msg>Underscores to dashes (#57)<commit_after>// Copyright 2020 The ShaderTrap Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <EGL/egl.h>

#include <cstddef>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "glad/glad.h"
#include "libshadertrap/api_version.h"
#include "libshadertrap/checker.h"
#include "libshadertrap/command_visitor.h"
#include "libshadertrap/compound_visitor.h"
#include "libshadertrap/executor.h"
#include "libshadertrap/gl_functions.h"
#include "libshadertrap/glslang.h"
#include "libshadertrap/make_unique.h"
#include "libshadertrap/message_consumer.h"
#include "libshadertrap/parser.h"
#include "libshadertrap/shadertrap_program.h"
#include "libshadertrap/token.h"
#include "shadertrap/get_gl_functions.h"

namespace {

const EGLint kWidth = 256;
const EGLint kHeight = 256;
const EGLint kDepthSize = 16;
const EGLint kRequiredEglMinorVersionForGl = 5;

const char* const kOptionPrefix = "--";
const char* const kOptionShowGlInfo = "--show-gl-info";

class ConsoleMessageConsumer : public shadertrap::MessageConsumer {
  void Message(Severity severity, const shadertrap::Token* token,
               const std::string& message) override {
    switch (severity) {
      case MessageConsumer::Severity::kError:
        std::cerr << "ERROR";
        break;
      case MessageConsumer::Severity::kWarning:
        std::cerr << "WARNING";
        break;
    }
    std::cerr << " at ";
    if (token == nullptr) {
      std::cerr << "unknown location";
    } else {
      std::cerr << token->GetLocationString();
    }
    std::cerr << ": " << message << std::endl;
  }
};

std::vector<char> ReadFile(const std::string& input_file) {
  std::ifstream file(input_file);
  std::ostringstream stringstream;
  stringstream << file.rdbuf();
  const std::string& temp = stringstream.str();
  return std::vector<char>(temp.begin(), temp.end());
}

}  // namespace

#define SHOW_GL_STRING(name)                                            \
  do {                                                                  \
    auto* gl_string = glGetString(name);                                \
    if (glGetError() != GL_NO_ERROR) {                                  \
      std::cerr << "Error calling glGetString(" #name ")" << std::endl; \
      return 1;                                                         \
    }                                                                   \
    std::cout << "GL_VENDOR: " << gl_string << std::endl;               \
  } while (false)

int main(int argc, const char** argv) {
  std::vector<std::string> args(argv, argv + argc);
  if (args.size() < 2) {
    std::cerr << "Usage: " << args[0] + "[options] SCRIPT" << std::endl;
    std::cerr << "Options:" << std::endl;
    std::cerr << "  " << kOptionShowGlInfo << std::endl;
    std::cerr << "    Show GL information before running the script"
              << std::endl;
    return 1;
  }

  bool show_gl_info = false;
  std::string script_name;
  std::string option_prefix(kOptionPrefix);
  for (size_t i = 1; i < static_cast<size_t>(argc); i++) {
    std::string argument(argv[i]);
    if (argument == kOptionShowGlInfo) {
      show_gl_info = true;
    } else if (argument.length() >= option_prefix.length() &&
               argument.substr(0, option_prefix.length()) == option_prefix) {
      std::cerr << "Unknown option " << argument << std::endl;
      return 1;
    } else if (!script_name.empty()) {
      std::cerr << "Multiple script names provided." << std::endl;
      return 1;
    } else {
      script_name = argument;
    }
  }

  if (script_name.empty()) {
    std::cerr << "No script name was provided." << std::endl;
    return 1;
  }

  auto char_data = ReadFile(script_name);
  auto data = std::string(char_data.begin(), char_data.end());

  ConsoleMessageConsumer message_consumer;
  shadertrap::Parser parser(data, &message_consumer);
  if (!parser.Parse()) {
    return 1;
  }

  std::unique_ptr<shadertrap::ShaderTrapProgram> shadertrap_program =
      parser.GetParsedProgram();

  shadertrap::ApiVersion api_version = shadertrap_program->GetApiVersion();

  EGLDisplay display;
  EGLConfig config;
  EGLContext context;
  EGLSurface surface;

  std::vector<EGLint> config_attributes = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
                                           EGL_RED_SIZE,     4,
                                           EGL_GREEN_SIZE,   4,
                                           EGL_BLUE_SIZE,    4,
                                           EGL_ALPHA_SIZE,   4,

                                           EGL_CONFORMANT,   EGL_OPENGL_ES3_BIT,
                                           EGL_DEPTH_SIZE,   kDepthSize,
                                           EGL_NONE};

  std::vector<EGLint> context_attributes = {
      EGL_CONTEXT_MAJOR_VERSION,
      static_cast<EGLint>(api_version.GetMajorVersion()),
      EGL_CONTEXT_MINOR_VERSION,
      static_cast<EGLint>(api_version.GetMinorVersion()), EGL_NONE};

  // TODO(afd): For offscreen rendering, do width and height matter?  If no,
  //  are there more sensible default values than these?  If yes, should they be
  //  controllable from the command line?
  std::vector<EGLint> pbuffer_attributes = {EGL_WIDTH,
                                            kWidth,
                                            EGL_HEIGHT,
                                            kHeight,
                                            EGL_TEXTURE_FORMAT,
                                            EGL_NO_TEXTURE,
                                            EGL_TEXTURE_TARGET,
                                            EGL_NO_TEXTURE,
                                            EGL_LARGEST_PBUFFER,
                                            EGL_TRUE,
                                            EGL_NONE};

  display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

  EGLint egl_major_version;
  EGLint egl_minor_version;

  if (eglInitialize(display, &egl_major_version, &egl_minor_version) ==
      EGL_FALSE) {
    std::cerr << "eglInitialize failed." << std::endl;
    return 1;
  }

  if (api_version.GetApi() == shadertrap::ApiVersion::Api::GL &&
      !(egl_major_version > 1 ||
        (egl_major_version == 1 &&
         egl_minor_version >= kRequiredEglMinorVersionForGl))) {
    std::cerr << "EGL and OpenGL are not compatible pre EGL 1.5; found EGL "
              << egl_major_version << "." << egl_minor_version << std::endl;
    return 1;
  }

  if (eglBindAPI(static_cast<EGLenum>(api_version.GetApi() ==
                                              shadertrap::ApiVersion::Api::GL
                                          ? EGL_OPENGL_API
                                          : EGL_OPENGL_ES_API)) == EGL_FALSE) {
    std::cerr << "eglBindAPI failed." << std::endl;
  }

  EGLint num_config;
  if (eglChooseConfig(display, config_attributes.data(), &config, 1,
                      &num_config) == EGL_FALSE) {
    std::cerr << "eglChooseConfig failed." << std::endl;
    return 1;
  }

  if (num_config != 1) {
    std::cerr << "ERROR: eglChooseConfig returned " << num_config
              << " configurations; exactly 1 configuration is required";
    return 1;
  }

  context = eglCreateContext(display, config, EGL_NO_CONTEXT,
                             context_attributes.data());
  if (context == EGL_NO_CONTEXT) {
    std::cerr << "eglCreateContext failed." << std::endl;
    return 1;
  }

  surface = eglCreatePbufferSurface(display, config, pbuffer_attributes.data());
  if (surface == EGL_NO_SURFACE) {
    std::cerr << "eglCreatePbufferSurface failed." << std::endl;
    return 1;
  }

  eglMakeCurrent(display, surface, surface, context);

  if (api_version.GetApi() == shadertrap::ApiVersion::Api::GL) {
    if (gladLoadGLLoader(reinterpret_cast<GLADloadproc>(eglGetProcAddress)) ==
        0) {
      std::cerr << "gladLoadGLLoader failed." << std::endl;
      return 1;
    }
  } else {
    if (gladLoadGLES2Loader(
            reinterpret_cast<GLADloadproc>(eglGetProcAddress)) == 0) {
      std::cerr << "gladLoadGLES2Loader failed." << std::endl;
      return 1;
    }
  }

  if (show_gl_info) {
    SHOW_GL_STRING(GL_VENDOR);
    SHOW_GL_STRING(GL_RENDERER);
    SHOW_GL_STRING(GL_VERSION);
    SHOW_GL_STRING(GL_SHADING_LANGUAGE_VERSION);
  }

  shadertrap::GlFunctions functions = shadertrap::GetGlFunctions();

  std::vector<std::unique_ptr<shadertrap::CommandVisitor>> temp;
  temp.push_back(shadertrap::MakeUnique<shadertrap::Checker>(
      &message_consumer, shadertrap_program->GetApiVersion()));
  temp.push_back(shadertrap::MakeUnique<shadertrap::Executor>(
      &functions, &message_consumer, shadertrap_program->GetApiVersion()));
  shadertrap::CompoundVisitor checker_and_executor(std::move(temp));
  ShInitialize();
  bool success = checker_and_executor.VisitCommands(shadertrap_program.get());
  ShFinalize();
  if (!success) {
    std::cerr << "Errors occurred during execution." << std::endl;
    return 1;
  }
  std::cerr << "SUCCESS!" << std::endl;
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// 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 co
// pies 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 al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER 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 "content/nw/src/shell_main_delegate.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/nw/src/common/shell_switches.h"
#include "content/nw/src/nw_version.h"
#include "content/nw/src/renderer/shell_content_renderer_client.h"
#include "content/nw/src/shell_browser_main.h"
#include "content/nw/src/shell_content_browser_client.h"
#include "net/cookies/cookie_monster.h"
#include "third_party/node/src/node_version.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"

#include <stdio.h>

using base::FilePath;

#if defined(OS_MACOSX)
#include "content/shell/paths_mac.h"
#endif  // OS_MACOSX

#if defined(OS_WIN)
#include "base/logging_win.h"
#include <initguid.h>
#endif

#include "ipc/ipc_message.h"  // For IPC_MESSAGE_LOG_ENABLED.

#if defined(IPC_MESSAGE_LOG_ENABLED)
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#include "content/public/common/content_ipc_logging.h"
#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
    content::RegisterIPCLogger(msg_id, logger)
#include "content/nw/src/common/common_message_generator.h"
#include "components/autofill/core/common/autofill_messages.h"
#endif

namespace {

#if defined(OS_WIN)
// If "Content Shell" doesn't show up in your list of trace providers in
// Sawbuck, add these registry entries to your machine (NOTE the optional
// Wow6432Node key for x64 machines):
// 1. Find:  HKLM\SOFTWARE\[Wow6432Node\]Google\Sawbuck\Providers
// 2. Add a subkey with the name "{6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}"
// 3. Add these values:
//    "default_flags"=dword:00000001
//    "default_level"=dword:00000004
//    @="Content Shell"

// {6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}
const GUID kContentShellProviderName = {
    0x6a3e50a4, 0x7e15, 0x4099,
        { 0x84, 0x13, 0xec, 0x94, 0xd8, 0xc2, 0xa4, 0xb6 } };
#endif

void InitLogging() {
  base::FilePath log_filename;
  PathService::Get(base::DIR_EXE, &log_filename);
  log_filename = log_filename.AppendASCII("debug.log");
  logging::LoggingSettings settings;
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableLogging)) {
    settings.logging_dest = logging::LOG_TO_ALL;
    settings.log_file = log_filename.value().c_str();
    settings.delete_old = logging::DELETE_OLD_LOG_FILE;
  }
  logging::InitLogging(settings);
  logging::SetLogItems(true, false, true, false);
}

}  // namespace

namespace content {

ShellMainDelegate::ShellMainDelegate() {
}

ShellMainDelegate::~ShellMainDelegate() {
}

bool ShellMainDelegate::BasicStartupComplete(int* exit_code) {
#if defined(OS_WIN)
  // Enable trace control and transport through event tracing for Windows.
  logging::LogEventProvider::Initialize(kContentShellProviderName);
#endif

  InitLogging();
  net::CookieMonster::EnableFileScheme();

  SetContentClient(&content_client_);
  return false;
}

void ShellMainDelegate::PreSandboxStartup() {
#if defined(OS_MACOSX)
  OverrideFrameworkBundlePath();
  OverrideChildProcessPath();
#endif  // OS_MACOSX
  InitializeResourceBundle();

  CommandLine* command_line = CommandLine::ForCurrentProcess();

  // Just prevent sandbox.
  command_line->AppendSwitch(switches::kNoSandbox);

  // Make sure we keep using only one render process for one app, by using the
  // process-per-tab mode, we can make Chrome only create new site instance
  // when we require to, the default mode is creating different site instances
  // for different domains.
  // This is needed because we want our Window API to have full control of new
  // windows created, which require all windows to be in one render process
  // host.
  command_line->AppendSwitch(switches::kProcessPerTab);

  // Allow file:// URIs can read other file:// URIs by default.
  command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
  command_line->AppendSwitch(switches::kEnableExperimentalWebKitFeatures);
  command_line->AppendSwitch(switches::kEnableCssShaders);
}

int ShellMainDelegate::RunProcess(
    const std::string& process_type,
    const MainFunctionParams& main_function_params) {
  if (!process_type.empty())
    return -1;

  return ShellBrowserMain(main_function_params);
}

void ShellMainDelegate::InitializeResourceBundle() {
  FilePath pak_file;
#if defined(OS_MACOSX)
  pak_file = GetResourcesPakFilePath();
#else
  FilePath pak_dir;
  PathService::Get(base::DIR_MODULE, &pak_dir);
  pak_file = pak_dir.Append(FILE_PATH_LITERAL("nw.pak"));
  CHECK(file_util::PathExists(pak_file)) << "nw.pak is missing";
#endif
  ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
}

ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() {
  browser_client_.reset(new ShellContentBrowserClient);
  return browser_client_.get();
}

ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() {
  renderer_client_.reset(new ShellContentRendererClient);
  return renderer_client_.get();
}

}  // namespace content
<commit_msg>[WIN] fix logging initialization; SEGV on start<commit_after>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// 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 co
// pies 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 al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER 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 "content/nw/src/shell_main_delegate.h"

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/nw/src/common/shell_switches.h"
#include "content/nw/src/nw_version.h"
#include "content/nw/src/renderer/shell_content_renderer_client.h"
#include "content/nw/src/shell_browser_main.h"
#include "content/nw/src/shell_content_browser_client.h"
#include "net/cookies/cookie_monster.h"
#include "third_party/node/src/node_version.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"

#include <stdio.h>

using base::FilePath;

#if defined(OS_MACOSX)
#include "content/shell/paths_mac.h"
#endif  // OS_MACOSX

#if defined(OS_WIN)
#include "base/logging_win.h"
#include <initguid.h>
#endif

#include "ipc/ipc_message.h"  // For IPC_MESSAGE_LOG_ENABLED.

#if defined(IPC_MESSAGE_LOG_ENABLED)
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#include "content/public/common/content_ipc_logging.h"
#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
    content::RegisterIPCLogger(msg_id, logger)
#include "content/nw/src/common/common_message_generator.h"
#include "components/autofill/core/common/autofill_messages.h"
#endif

namespace {

#if defined(OS_WIN)
// If "Content Shell" doesn't show up in your list of trace providers in
// Sawbuck, add these registry entries to your machine (NOTE the optional
// Wow6432Node key for x64 machines):
// 1. Find:  HKLM\SOFTWARE\[Wow6432Node\]Google\Sawbuck\Providers
// 2. Add a subkey with the name "{6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}"
// 3. Add these values:
//    "default_flags"=dword:00000001
//    "default_level"=dword:00000004
//    @="Content Shell"

// {6A3E50A4-7E15-4099-8413-EC94D8C2A4B6}
const GUID kContentShellProviderName = {
    0x6a3e50a4, 0x7e15, 0x4099,
        { 0x84, 0x13, 0xec, 0x94, 0xd8, 0xc2, 0xa4, 0xb6 } };
#endif

void InitLogging() {
  base::FilePath log_filename;
  PathService::Get(base::DIR_EXE, &log_filename);
  log_filename = log_filename.AppendASCII("debug.log");
  logging::LoggingSettings settings;
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableLogging)) {
    settings.logging_dest = logging::LOG_TO_ALL;
    settings.log_file = log_filename.value().c_str();
    settings.delete_old = logging::DELETE_OLD_LOG_FILE;
  }else{
#if defined(OS_WIN)
    settings.logging_dest = logging::LOG_NONE;
#endif
  }
  logging::InitLogging(settings);
  logging::SetLogItems(true, false, true, false);
}

}  // namespace

namespace content {

ShellMainDelegate::ShellMainDelegate() {
}

ShellMainDelegate::~ShellMainDelegate() {
}

bool ShellMainDelegate::BasicStartupComplete(int* exit_code) {
#if defined(OS_WIN)
  // Enable trace control and transport through event tracing for Windows.
  logging::LogEventProvider::Initialize(kContentShellProviderName);
#endif

  InitLogging();
  net::CookieMonster::EnableFileScheme();

  SetContentClient(&content_client_);
  return false;
}

void ShellMainDelegate::PreSandboxStartup() {
#if defined(OS_MACOSX)
  OverrideFrameworkBundlePath();
  OverrideChildProcessPath();
#endif  // OS_MACOSX
  InitializeResourceBundle();

  CommandLine* command_line = CommandLine::ForCurrentProcess();

  // Just prevent sandbox.
  command_line->AppendSwitch(switches::kNoSandbox);

  // Make sure we keep using only one render process for one app, by using the
  // process-per-tab mode, we can make Chrome only create new site instance
  // when we require to, the default mode is creating different site instances
  // for different domains.
  // This is needed because we want our Window API to have full control of new
  // windows created, which require all windows to be in one render process
  // host.
  command_line->AppendSwitch(switches::kProcessPerTab);

  // Allow file:// URIs can read other file:// URIs by default.
  command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
  command_line->AppendSwitch(switches::kEnableExperimentalWebKitFeatures);
  command_line->AppendSwitch(switches::kEnableCssShaders);
}

int ShellMainDelegate::RunProcess(
    const std::string& process_type,
    const MainFunctionParams& main_function_params) {
  if (!process_type.empty())
    return -1;

  return ShellBrowserMain(main_function_params);
}

void ShellMainDelegate::InitializeResourceBundle() {
  FilePath pak_file;
#if defined(OS_MACOSX)
  pak_file = GetResourcesPakFilePath();
#else
  FilePath pak_dir;
  PathService::Get(base::DIR_MODULE, &pak_dir);
  pak_file = pak_dir.Append(FILE_PATH_LITERAL("nw.pak"));
  CHECK(file_util::PathExists(pak_file)) << "nw.pak is missing";
#endif
  ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
}

ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() {
  browser_client_.reset(new ShellContentBrowserClient);
  return browser_client_.get();
}

ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() {
  renderer_client_.reset(new ShellContentRendererClient);
  return renderer_client_.get();
}

}  // namespace content
<|endoftext|>


<commit_before>#include <errno.h>
#include <libc.h>
#include <spawn.h>
#include <string.h>
#include <thread>

#include "event_consolidator.h"
#include "kdebug_controller.h"
#include "named_mach_port.h"
#include "process_tracer.h"
#include "tracer.h"
#include "tracing_server.h"

extern "C" int reexec_to_match_kernel();
extern char **environ;

namespace shk {
namespace {

int getNumCpus() {
  int num_cpus;
  size_t len = sizeof(num_cpus);
  static int name[] = { CTL_HW, HW_NCPU, 0 };
  if (sysctl(name, 2, &num_cpus, &len, nullptr, 0) < 0) {
    throw std::runtime_error("Failed to get number of CPUs");
  }
  return num_cpus;
}

static const std::string PORT_NAME = "com.pereckerdal.shktrace";

class ProcessTracerDelegate : public ProcessTracer::Delegate {
 public:
  ProcessTracerDelegate(std::unique_ptr<TracingServer::TraceRequest> &&request)
      : _request(std::move(request)) {}

  virtual ~ProcessTracerDelegate() {
    auto events = _consolidator.getConsolidatedEventsAndReset();
    for (const auto &event : events) {
      // TODO(peck): Write something that actually makes sense
      write(event.second + "\n");
    }

    // TODO(peck): Do something about quitting the tracing server as well.
  }

  virtual void fileEvent(EventType type, std::string &&path) override {
    _consolidator.event(type, std::move(path));
  }

 private:
  void write(const std::string &str) {
    auto written = ::write(
        _request->trace_fd.get(),
        str.c_str(),
        str.size());
    if (written != str.size()) {
      fprintf(stderr, "Failed to write to tracing file\n");
      abort();
    }
  }

  // This object is destroyed when tracing has finished. That, in turn, will
  // destroy the TraceRequest, which signals to the traced process that tracing
  // has finished.
  const std::unique_ptr<TracingServer::TraceRequest> _request;
  EventConsolidator _consolidator;
};

std::unique_ptr<TracingServer> runTracingServer(
    dispatch_queue_t queue, MachReceiveRight &&port) {
  auto kdebug_ctrl = makeKdebugController();

  ProcessTracer process_tracer;

  Tracer tracer(
      getNumCpus(),
      *kdebug_ctrl,
      process_tracer);
  tracer.start(queue);

  return makeTracingServer(
      queue,
      std::move(port),
      [&](std::unique_ptr<TracingServer::TraceRequest> &&request) {
        pid_t pid = request->pid_to_trace;
        process_tracer.traceProcess(
            pid,
            std::unique_ptr<ProcessTracer::Delegate>(
                new ProcessTracerDelegate(std::move(request))));
      });
}

std::pair<MachSendRight, bool> connectToServer() {
  auto client_port = openNamedPort(PORT_NAME);
  if (client_port.second == MachOpenPortResult::SUCCESS) {
    return std::make_pair(std::move(client_port.first), true);
  } else if (client_port.second != MachOpenPortResult::NOT_FOUND) {
    fprintf(stderr, "Failed to open Mach port against server\n");
    return std::make_pair(MachSendRight(), false);
  }

  auto server_port = registerNamedPort(PORT_NAME);
  // TODO(peck): handle failure
  // runTracingServer(std::move(server_port.first));

  printf("Need to open\n");
  return std::make_pair(MachSendRight(), false);
}

void dropPrivileges() {
  uid_t newuid = getuid();
  uid_t olduid = geteuid();

  if (newuid != olduid) {
    seteuid(newuid);
    if (setuid(newuid) == -1) {
      abort();
    }
  }
}

int executeCommand(const std::string &cmd) {
  pid_t pid;
  const char *argv[] = { "sh", "-c", cmd.c_str(), NULL };
  int err = posix_spawn(
      &pid,
      "/bin/sh",
      nullptr,
      nullptr,
      const_cast<char **>(argv),
      environ);
  if (err) {
    fprintf(stderr, "Failed to spawn child process: %s\n", strerror(errno));
    return 1;
  }

  int status;
  if (waitpid(pid, &status, 0) == -1) {
    fprintf(stderr, "Failed to wait for child process: %s\n", strerror(errno));
    return 1;
  }

  return WEXITSTATUS(status);
}

std::pair<FileDescriptor, bool> openTraceFile(const std::string &path) {
  int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666);
  return std::make_pair(FileDescriptor(fd), fd != -1);
}

int main(int argc, char *argv[]) {
  if (0 != reexec_to_match_kernel()) {
    fprintf(stderr, "Could not re-execute: %s\n", strerror(errno));
    return 1;
  }

  if (getgid() != getegid()) {
    fprintf(stderr, "This tool must not be run with setgid bit set\n");
    return 1;
  }

  if (geteuid() != 0) {
    fprintf(stderr, "This tool must be run as root\n");
    return 1;
  }

  auto port_pair = makePortPair();
  DispatchQueue queue(dispatch_queue_create(
      "shk-trace-server",
      DISPATCH_QUEUE_SERIAL));

  auto kdebug_ctrl = makeKdebugController();

  ProcessTracer process_tracer;

  Tracer tracer(
      getNumCpus(),
      *kdebug_ctrl,
      process_tracer);
  tracer.start(queue.get());

  auto tracing_server = makeTracingServer(
      queue.get(),
      std::move(port_pair.first),
      [&](std::unique_ptr<TracingServer::TraceRequest> &&request) {
        pid_t pid = request->pid_to_trace;
        process_tracer.traceProcess(
            pid,
            std::unique_ptr<ProcessTracer::Delegate>(
                new ProcessTracerDelegate(std::move(request))));
      });

  //auto mach_port = connectToServer();
  /*if (!mach_port.second) {
    TODO(peck): Do error checking here
    return 1;
  }*/

  dropPrivileges();

  auto trace_fd = openTraceFile("trace.txt");
  if (!trace_fd.second) {
    fprintf(stderr, "Failed to open tracing file: %s\n", strerror(errno));
    return 1;
  }

  auto trace_request = requestTracing(
      std::move(port_pair.second),
      std::move(trace_fd.first));
  if (trace_request.second != MachOpenPortResult::SUCCESS) {
    fprintf(stderr, "Failed to initiate tracing\n");
    return 1;
  }

  int status_code;
  std::thread([&] {
    // Due to a limitation in the tracing information that kdebug provides,
    // the traced program must create a thread, that has its own pid, which
    // will be traced. This thread can then spawn another process.
    //
    // This is because a tracing request contains the pid of the process to
    // be traced. This starts tracing
    //
    // TODO(peck): Restructure / document this so that it becomes sane.
    printf("EXECUTING\n");

    status_code = executeCommand("ls /");
  }).join();

  trace_request.first->wait(MACH_MSG_TIMEOUT_NONE);

  return status_code;
}

}  // anonymous namespace
}  // namespace shk

int main(int argc, char *argv[]) {
  shk::main(argc, argv);
}
<commit_msg>Write the event type to the trace file<commit_after>#include <errno.h>
#include <libc.h>
#include <spawn.h>
#include <string.h>
#include <thread>

#include "event_consolidator.h"
#include "kdebug_controller.h"
#include "named_mach_port.h"
#include "process_tracer.h"
#include "tracer.h"
#include "tracing_server.h"

extern "C" int reexec_to_match_kernel();
extern char **environ;

namespace shk {
namespace {

int getNumCpus() {
  int num_cpus;
  size_t len = sizeof(num_cpus);
  static int name[] = { CTL_HW, HW_NCPU, 0 };
  if (sysctl(name, 2, &num_cpus, &len, nullptr, 0) < 0) {
    throw std::runtime_error("Failed to get number of CPUs");
  }
  return num_cpus;
}

static const std::string PORT_NAME = "com.pereckerdal.shktrace";

class ProcessTracerDelegate : public ProcessTracer::Delegate {
 public:
  ProcessTracerDelegate(std::unique_ptr<TracingServer::TraceRequest> &&request)
      : _request(std::move(request)) {}

  virtual ~ProcessTracerDelegate() {
    auto events = _consolidator.getConsolidatedEventsAndReset();
    for (const auto &event : events) {
      write(eventTypeToString(event.first) + (" " + event.second) + "\n");
    }

    // TODO(peck): Do something about quitting the tracing server as well.
  }

  virtual void fileEvent(EventType type, std::string &&path) override {
    _consolidator.event(type, std::move(path));
  }

 private:
  void write(const std::string &str) {
    auto written = ::write(
        _request->trace_fd.get(),
        str.c_str(),
        str.size());
    if (written != str.size()) {
      fprintf(stderr, "Failed to write to tracing file\n");
      abort();
    }
  }

  // This object is destroyed when tracing has finished. That, in turn, will
  // destroy the TraceRequest, which signals to the traced process that tracing
  // has finished.
  const std::unique_ptr<TracingServer::TraceRequest> _request;
  EventConsolidator _consolidator;
};

std::unique_ptr<TracingServer> runTracingServer(
    dispatch_queue_t queue, MachReceiveRight &&port) {
  auto kdebug_ctrl = makeKdebugController();

  ProcessTracer process_tracer;

  Tracer tracer(
      getNumCpus(),
      *kdebug_ctrl,
      process_tracer);
  tracer.start(queue);

  return makeTracingServer(
      queue,
      std::move(port),
      [&](std::unique_ptr<TracingServer::TraceRequest> &&request) {
        pid_t pid = request->pid_to_trace;
        process_tracer.traceProcess(
            pid,
            std::unique_ptr<ProcessTracer::Delegate>(
                new ProcessTracerDelegate(std::move(request))));
      });
}

std::pair<MachSendRight, bool> connectToServer() {
  auto client_port = openNamedPort(PORT_NAME);
  if (client_port.second == MachOpenPortResult::SUCCESS) {
    return std::make_pair(std::move(client_port.first), true);
  } else if (client_port.second != MachOpenPortResult::NOT_FOUND) {
    fprintf(stderr, "Failed to open Mach port against server\n");
    return std::make_pair(MachSendRight(), false);
  }

  auto server_port = registerNamedPort(PORT_NAME);
  // TODO(peck): handle failure
  // runTracingServer(std::move(server_port.first));

  printf("Need to open\n");
  return std::make_pair(MachSendRight(), false);
}

void dropPrivileges() {
  uid_t newuid = getuid();
  uid_t olduid = geteuid();

  if (newuid != olduid) {
    seteuid(newuid);
    if (setuid(newuid) == -1) {
      abort();
    }
  }
}

int executeCommand(const std::string &cmd) {
  pid_t pid;
  const char *argv[] = { "sh", "-c", cmd.c_str(), NULL };
  int err = posix_spawn(
      &pid,
      "/bin/sh",
      nullptr,
      nullptr,
      const_cast<char **>(argv),
      environ);
  if (err) {
    fprintf(stderr, "Failed to spawn child process: %s\n", strerror(errno));
    return 1;
  }

  int status;
  if (waitpid(pid, &status, 0) == -1) {
    fprintf(stderr, "Failed to wait for child process: %s\n", strerror(errno));
    return 1;
  }

  return WEXITSTATUS(status);
}

std::pair<FileDescriptor, bool> openTraceFile(const std::string &path) {
  int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666);
  return std::make_pair(FileDescriptor(fd), fd != -1);
}

int main(int argc, char *argv[]) {
  if (0 != reexec_to_match_kernel()) {
    fprintf(stderr, "Could not re-execute: %s\n", strerror(errno));
    return 1;
  }

  if (getgid() != getegid()) {
    fprintf(stderr, "This tool must not be run with setgid bit set\n");
    return 1;
  }

  if (geteuid() != 0) {
    fprintf(stderr, "This tool must be run as root\n");
    return 1;
  }

  auto port_pair = makePortPair();
  DispatchQueue queue(dispatch_queue_create(
      "shk-trace-server",
      DISPATCH_QUEUE_SERIAL));

  auto kdebug_ctrl = makeKdebugController();

  ProcessTracer process_tracer;

  Tracer tracer(
      getNumCpus(),
      *kdebug_ctrl,
      process_tracer);
  tracer.start(queue.get());

  auto tracing_server = makeTracingServer(
      queue.get(),
      std::move(port_pair.first),
      [&](std::unique_ptr<TracingServer::TraceRequest> &&request) {
        pid_t pid = request->pid_to_trace;
        process_tracer.traceProcess(
            pid,
            std::unique_ptr<ProcessTracer::Delegate>(
                new ProcessTracerDelegate(std::move(request))));
      });

  //auto mach_port = connectToServer();
  /*if (!mach_port.second) {
    TODO(peck): Do error checking here
    return 1;
  }*/

  dropPrivileges();

  auto trace_fd = openTraceFile("trace.txt");
  if (!trace_fd.second) {
    fprintf(stderr, "Failed to open tracing file: %s\n", strerror(errno));
    return 1;
  }

  auto trace_request = requestTracing(
      std::move(port_pair.second),
      std::move(trace_fd.first));
  if (trace_request.second != MachOpenPortResult::SUCCESS) {
    fprintf(stderr, "Failed to initiate tracing\n");
    return 1;
  }

  int status_code;
  std::thread([&] {
    // Due to a limitation in the tracing information that kdebug provides,
    // the traced program must create a thread, that has its own pid, which
    // will be traced. This thread can then spawn another process.
    //
    // This is because a tracing request contains the pid of the process to
    // be traced. This starts tracing
    //
    // TODO(peck): Restructure / document this so that it becomes sane.
    printf("EXECUTING\n");

    status_code = executeCommand("ls /");
  }).join();

  trace_request.first->wait(MACH_MSG_TIMEOUT_NONE);

  return status_code;
}

}  // anonymous namespace
}  // namespace shk

int main(int argc, char *argv[]) {
  shk::main(argc, argv);
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2008-2017 SLIBIO. All Rights Reserved.
 *
 *  This file is part of the SLib.io project.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "slib/ui/label_view.h"

#include "slib/core/scoped.h"
#include "slib/graphics/util.h"

namespace slib
{
	SLIB_DEFINE_OBJECT(LabelView, View)

	LabelView::LabelView()
	{
		setCreatingNativeWidget(sl_false);
		setSavingCanvasState(sl_false);

		setUsingFont(sl_true);

		m_textAlignment = Alignment::Left;
		m_textColor = Color::Black;
		m_multiLineMode = MultiLineMode::Single;

		setPadding(1, 1, 1, 1, UIUpdateMode::Init);
	}

	LabelView::~LabelView()
	{
	}

	String LabelView::getText()
	{
		return m_text;
	}

	void LabelView::setText(const String& text, UIUpdateMode mode)
	{
		m_text = text;

		if (isNativeWidget()) {
			_setText_NW(text);
		}
		invalidateLayoutFromResizeContent(mode);
	}

	Color LabelView::getTextColor()
	{
		return m_textColor;
	}

	void LabelView::setTextColor(const Color& color, UIUpdateMode mode)
	{
		m_textColor = color;
		if (isNativeWidget()) {
			_setTextColor_NW(color);
		} else {
			if (mode == UIUpdateMode::Redraw) {
				invalidate();
			}
		}
	}

	Alignment LabelView::getGravity()
	{
		return m_textAlignment;
	}

	void LabelView::setGravity(Alignment align, UIUpdateMode mode)
	{
		m_textAlignment = align;
		if (isNativeWidget()) {
			_setTextAlignment_NW(align);
		} else {
			if (mode == UIUpdateMode::Redraw) {
				invalidate();
			}
		}
	}

	MultiLineMode LabelView::getMultiLineMode()
	{
		return m_multiLineMode;
	}

	void LabelView::setMultiLineMode(MultiLineMode multiLineMode, UIUpdateMode updateMode)
	{
		m_multiLineMode = multiLineMode;
		invalidateLayoutFromResizeContent(updateMode);
	}

	void LabelView::onDraw(Canvas* canvas)
	{
		m_textBox.draw(canvas, m_text, getFont(), getBoundsInnerPadding(), isWidthWrapping(), m_multiLineMode, m_textAlignment, m_textColor);
	}

	void LabelView::onMeasureLayout(sl_bool flagHorizontal, sl_bool flagVertical)
	{
		if (!flagVertical && !flagHorizontal) {
			return;
		}

		sl_ui_pos paddingWidth = getPaddingLeft() + getPaddingRight();
		m_textBox.update(m_text, getFont(), (sl_real)(getWidth() - paddingWidth), isWidthWrapping(), m_multiLineMode, m_textAlignment);
		if (flagHorizontal) {
			setMeasuredWidth((sl_ui_pos)(m_textBox.getContentWidth()) + paddingWidth);
		}
		if (flagVertical) {
			setMeasuredHeight((sl_ui_pos)(m_textBox.getContentHeight()) + getPaddingTop() + getPaddingBottom());
		}

	}

#if !(defined(SLIB_PLATFORM_IS_OSX)) && !(defined(SLIB_PLATFORM_IS_IOS)) && !(defined(SLIB_PLATFORM_IS_WIN32)) && !(defined(SLIB_PLATFORM_IS_ANDROID))

	Ref<ViewInstance> LabelView::createNativeWidget(ViewInstance* parent)
	{
		return sl_null;
	}

	void LabelView::_setText_NW(const String& text)
	{
	}

	void LabelView::_setTextColor_NW(const Color& color)
	{
	}

	void LabelView::_setTextAlignment_NW(Alignment align)
	{
	}

	void LabelView::_setFont_NW(const Ref<Font>& font)
	{
	}

	void LabelView::_setBorder_NW(sl_bool flag)
	{
	}

	void LabelView::_setBackgroundColor_NW(const Color& color)
	{
	}

#endif
}
<commit_msg>LabelView::setText() - update text only when the content is changed<commit_after>/*
 *  Copyright (c) 2008-2017 SLIBIO. All Rights Reserved.
 *
 *  This file is part of the SLib.io project.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "slib/ui/label_view.h"

#include "slib/core/scoped.h"
#include "slib/graphics/util.h"

namespace slib
{
	SLIB_DEFINE_OBJECT(LabelView, View)

	LabelView::LabelView()
	{
		setCreatingNativeWidget(sl_false);
		setSavingCanvasState(sl_false);

		setUsingFont(sl_true);

		m_textAlignment = Alignment::Left;
		m_textColor = Color::Black;
		m_multiLineMode = MultiLineMode::Single;

		setPadding(1, 1, 1, 1, UIUpdateMode::Init);
	}

	LabelView::~LabelView()
	{
	}

	String LabelView::getText()
	{
		return m_text;
	}

	void LabelView::setText(const String& text, UIUpdateMode mode)
	{
		if (m_text == text) {
			return;
		}

		m_text = text;

		if (isNativeWidget()) {
			_setText_NW(text);
		}
		invalidateLayoutFromResizeContent(mode);
	}

	Color LabelView::getTextColor()
	{
		return m_textColor;
	}

	void LabelView::setTextColor(const Color& color, UIUpdateMode mode)
	{
		m_textColor = color;
		if (isNativeWidget()) {
			_setTextColor_NW(color);
		} else {
			if (mode == UIUpdateMode::Redraw) {
				invalidate();
			}
		}
	}

	Alignment LabelView::getGravity()
	{
		return m_textAlignment;
	}

	void LabelView::setGravity(Alignment align, UIUpdateMode mode)
	{
		m_textAlignment = align;
		if (isNativeWidget()) {
			_setTextAlignment_NW(align);
		} else {
			if (mode == UIUpdateMode::Redraw) {
				invalidate();
			}
		}
	}

	MultiLineMode LabelView::getMultiLineMode()
	{
		return m_multiLineMode;
	}

	void LabelView::setMultiLineMode(MultiLineMode multiLineMode, UIUpdateMode updateMode)
	{
		m_multiLineMode = multiLineMode;
		invalidateLayoutFromResizeContent(updateMode);
	}

	void LabelView::onDraw(Canvas* canvas)
	{
		m_textBox.draw(canvas, m_text, getFont(), getBoundsInnerPadding(), isWidthWrapping(), m_multiLineMode, m_textAlignment, m_textColor);
	}

	void LabelView::onMeasureLayout(sl_bool flagHorizontal, sl_bool flagVertical)
	{
		if (!flagVertical && !flagHorizontal) {
			return;
		}

		sl_ui_pos paddingWidth = getPaddingLeft() + getPaddingRight();
		m_textBox.update(m_text, getFont(), (sl_real)(getWidth() - paddingWidth), isWidthWrapping(), m_multiLineMode, m_textAlignment);
		if (flagHorizontal) {
			setMeasuredWidth((sl_ui_pos)(m_textBox.getContentWidth()) + paddingWidth);
		}
		if (flagVertical) {
			setMeasuredHeight((sl_ui_pos)(m_textBox.getContentHeight()) + getPaddingTop() + getPaddingBottom());
		}

	}

#if !(defined(SLIB_PLATFORM_IS_OSX)) && !(defined(SLIB_PLATFORM_IS_IOS)) && !(defined(SLIB_PLATFORM_IS_WIN32)) && !(defined(SLIB_PLATFORM_IS_ANDROID))

	Ref<ViewInstance> LabelView::createNativeWidget(ViewInstance* parent)
	{
		return sl_null;
	}

	void LabelView::_setText_NW(const String& text)
	{
	}

	void LabelView::_setTextColor_NW(const Color& color)
	{
	}

	void LabelView::_setTextAlignment_NW(Alignment align)
	{
	}

	void LabelView::_setFont_NW(const Ref<Font>& font)
	{
	}

	void LabelView::_setBorder_NW(sl_bool flag)
	{
	}

	void LabelView::_setBackgroundColor_NW(const Color& color)
	{
	}

#endif
}
<|endoftext|>


<commit_before>/*
Première version du programme de controle des Yi
*/
#include <Arduino.h>
#include <Wire.h>

//const int shutter_pin = 2;
//const int power_pin = 4;
const int powerup_button_pin = 5;
const int powerdown_button_pin = 6;
const int tmlapse_start_pin = 7;
const int tmlapse_stop_pin = 8;
//const int shutter_led_pin = A0;
const int shutter_led_pin = 3;
const int shutter_button_pin = 9;

int pic_count = 0; // picture counter
int after_pic_delay = 800;
volatile int shutter_led_counter = 0;
long old_timestamp = 0;
long current_timestamp = 0;
const byte cam_range = 0b00000001;

// MCP23017 registers (everything except direction defaults to 0)

#define IODIRA   0x00   // IO direction  (0 = output, 1 = input (Default))
#define IODIRB   0x01
#define IOPOLA   0x02   // IO polarity   (0 = normal, 1 = inverse)
#define IOPOLB   0x03
#define GPINTENA 0x04   // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05
#define DEFVALA  0x06   // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB  0x07
#define INTCONA  0x08   // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB  0x09
#define IOCON    0x0A   // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B  // same as 0x0A
#define GPPUA    0x0C   // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB    0x0D
#define INFTFA   0x0E   // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB   0x0F
#define INTCAPA  0x10   // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB  0x11
#define GPIOA    0x12   // Port value. Write to change, read to obtain value
#define GPIOB    0x13
#define OLLATA   0x14   // Output latch. Write to latch output.
#define OLLATB   0x15

#define mcp1 0x20  // MCP23017 n°1 (shutter and power) is on I2C port 0x20
#define mcp2 0x21  // MCP23017 n°2 (shutter led input) is on I2C port 0x21

#define ISR_INDICATOR 12  // pin 12
#define ONBOARD_LED 13    // pin 13
volatile bool sht_led_activity;
int sht_LedToggle_array[8];
unsigned long time = 0;

void expanderWrite (const byte port, const byte reg, const byte data ){
  Wire.beginTransmission (port);
  Wire.write (reg);
  Wire.write (data);
  Wire.endTransmission ();
} // end of expanderWrite

// read a byte from the expander
unsigned int expanderRead (const byte port, const byte reg){
  Wire.beginTransmission (port);
  Wire.write (reg);
  Wire.endTransmission ();
  Wire.requestFrom (port, 1);
  return Wire.read();
} // end of expanderRead

// interrupt service routine, called when pin D2 goes from 0 to 1
void mcp2_interrupt ()
{
  digitalWrite (ISR_INDICATOR, HIGH);  // debugging
  sht_led_activity = true;   // set flag so main loop knows
}  // end of mcp2_interrupt

void myISR() {
  shutter_led_counter++;
}

void setup() {
  // put your setup code here, to run once:

  // Set expander n°1 I/O as output
  expanderWrite(mcp1, IODIRA, 0x00);
  expanderWrite(mcp1, IODIRB, 0x00);

  // Set expander n°2 I/O as output. We will set inputs later
  expanderWrite(mcp2, IODIRA, 0x00);
  expanderWrite(mcp2, IODIRB, 0x00);

  // expander configuration register
  expanderWrite(mcp2, IOCON, 0b00100010); // no mirror interrupts, disable sequential mode, active HIGH

  // enable pull-up on switches
  //expanderWrite (GPPUA, 0xFF);   // pull-up resistor for switch - both ports

  // invert polarity
  //expanderWrite(mcp2, IOPOLA, 0xFF);  // invert polarity of signal - both ports

  // enable all interrupts
  expanderWrite (mcp2, GPINTENA, 0xFF); // enable interrupts - both ports

  // MES TESTS
  //expanderWriteBoth (IOPOLA, 0x00);  // polarity of signal - both ports

  //expanderWriteBoth(DEFVALA, 0b00000000); // defini la valeur par défaut à 0
  expanderWrite(mcp2, INTCONA, 0b00000000);// Active le mode "on change"
  // FIN MES TESTS
  // no interrupt yet
  sht_led_activity = false;

  // read from interrupt capture ports to clear them
  expanderRead (mcp2, INTCAPA);
  expanderRead (mcp2, INTCAPB);

  // pin 19 of MCP23017 is plugged into D2 of the Arduino which is interrupt 0
  attachInterrupt(0, mcp2_interrupt, RISING);

  // pinMode(shutter_pin, OUTPUT);
  // pinMode(power_pin, OUTPUT);
  pinMode(powerup_button_pin, INPUT_PULLUP);
  pinMode(powerdown_button_pin, INPUT_PULLUP);
  pinMode(tmlapse_start_pin, INPUT_PULLUP);
  pinMode(tmlapse_stop_pin, INPUT_PULLUP);
  pinMode(shutter_button_pin, INPUT_PULLUP);
  pinMode(shutter_led_pin, INPUT);
  pinMode(A5, INPUT);
  attachInterrupt(digitalPinToInterrupt(shutter_led_pin), myISR, RISING);
  Serial.begin(9600);
  Serial.println("Starting program");

}

void power_up_Yi(const byte cam_range) {
  Serial.println("Starting the Yi");
  //Set expander n°1 GPIOA to HIGH
  expanderWrite(mcp1, GPIOA, cam_range);

  delay(500);
  //Set expander n°1 GPIOA to LOW
  expanderWrite(mcp1, GPIOA, 0b00000000);

  Serial.println("Pause during the boot");
  delay(10000); //attente mise en route
  Serial.println("The cams should be ready");
}

void power_down_Yi(const byte cam_range) {
  Serial.println("Shutting down the Yi");
  //Set expander n°1 GPIOA to HIGH
  expanderWrite(mcp1, GPIOA, cam_range);

  delay(2500);
  //Set expander n°1 GPIOA to LOW
  expanderWrite(mcp1, GPIOA, 0b00000000);
}

void handle_Sht_led_activity ()
{
  unsigned int sht_LedValue = 0;
  unsigned int sht_LedLastValue = 0;

  sht_led_activity = false;  // ready for next time through the interrupt service routine
  digitalWrite (ISR_INDICATOR, LOW);  // debugging

  // Read port values, as required. Note that this re-arms the interrupts.

  if (expanderRead (mcp2, INFTFB))
    {

    sht_LedValue |= expanderRead (mcp2, INTCAPB);        // port B is in low-order byte
    }

  /*Serial.print("sht_LedValue : ");
  Serial.println(sht_LedValue, BIN);
  Serial.print("last State : ");
  Serial.println(sht_LedLastValue, BIN);
  Serial.print("Ou exclusif : ");
  Serial.println(sht_LedLastValue ^ sht_LedValue, BIN);
  Serial.println("");*/
  Serial.println ("Led toggles");
  //Serial.println ("0                   1");
  Serial.println ("00 01 02 03 04 05 06 07");

  // display which buttons were down at the time of the interrupt
  for (byte sht_Led = 0; sht_Led < 8; sht_Led++)
    {
    // this key down?
    /*Serial.print("sht_Led : ");
    Serial.println(1<< sht_Led, BIN);
    Serial.print("résultat de : ");
    Serial.print(sht_LedLastValue, BIN);
    Serial.print(" ^ ");
    Serial.print(sht_LedValue, BIN);
    Serial.print(" & ");
    Serial.print("1 << ");
    Serial.print(sht_Led, BIN);
    Serial.print(" : ");
    Serial.println(((sht_LedLastValue ^ sht_LedValue) & (1 << sht_Led)));
    Serial.print("calcul d origine : ");
    Serial.println(sht_LedValue & (1 << sht_Led), BIN);*/
    if ((sht_LedLastValue ^ sht_LedValue) & (1 << sht_Led)){
      //Serial.print ("01 ");
      sht_LedToggle_array[sht_Led]+=1;
      Serial.print(sht_LedToggle_array[sht_Led]);
      Serial.print(" ");
      }
    else {
      //Serial.print ("00 ");
      Serial.print(sht_LedToggle_array[sht_Led]);
      Serial.print(" ");
      }

    }
  sht_LedLastValue = sht_LedValue;
  Serial.println ();

  // if a switch is now pressed, turn LED on  (key down event)
  if (sht_LedValue)
    {
    time = millis ();  // remember when
    digitalWrite (ONBOARD_LED, HIGH);  // on-board LED
    }  // end if

}  // end of handle_Sht_led_activity

//Take a picture
long take_picture(const byte cam_range) {
  Serial.println("Taking picture...");
  long pic_start_time = millis();
  byte shutter_led_check = 0b00000000;
  int sht_LedToggle_array[8] = {0,0,0,0,0,0,0,0}; //Reset the array

  //Set expander n°1 GPIOB to HIGH to "press" the shutter button
  expanderWrite(mcp1, GPIOB, cam_range);
  delay(100);
  //Set expander n°1 GPIOB to LOW to "release" the shutter button
  expanderWrite(mcp1, GPIOB, 0b00000000);

  while (shutter_led_check != cam_range) { // Wait for the shutter led return
    if (sht_led_activity) {
      handle_Sht_led_activity();

      for (byte sht_Led = 0; sht_Led < 8; sht_Led++)
      {
        if ((sht_LedToggle_array[sht_Led] == 2) & (cam_range & (1 << sht_Led)))
          shutter_led_check = shutter_led_check & (1 << sht_Led);
        }
      }
    if (millis()-pic_start_time > 2500) {
      Serial.println("No response");
      return 0;
    }
  }
  Serial.println("Shutter leds detected");

  Serial.println("Pause");
  unsigned long delay_Start_Time = millis();
  // Wait for the cams to be ready, and check interrupt in case of a failure
  while (millis() < (delay_Start_Time + after_pic_delay)) {
    if (sht_led_activity) {
      handle_Sht_led_activity();
      for (byte sht_Led = 0; sht_Led < 8; sht_Led++)
      {
        if (sht_LedToggle_array[sht_Led] >= 2)
        {
          Serial.print("Error on cam n°");
          Serial.println(sht_Led);
        }
      }

    }
  return -1;
    }
  Serial.println("End of pause");
  return pic_start_time;
}

void timelapse(const byte cam_range) {
  Serial.println("Starting timelapse");
  int pic_shutter_request = 0;
  int pic_shutter_taken = 0;
  while (true) {
    current_timestamp = take_picture(cam_range);
    pic_shutter_request++;
    Serial.print("Interval : ");
    Serial.print(current_timestamp - old_timestamp);
    Serial.println("ms");
    if (current_timestamp != 0) {
      old_timestamp = current_timestamp;
      pic_shutter_taken++;
      Serial.print("Successful pictures : ");
      Serial.print(pic_shutter_taken);
      Serial.print(" of ");
      Serial.println(pic_shutter_request);
      Serial.print("Missing pictures : ");
      Serial.println(pic_shutter_request - pic_shutter_taken);
    }

    if (digitalRead(tmlapse_stop_pin) == LOW) {
      Serial.println("Timelapse stopped");
      break;
    }
  }
}

void loop() {

  if (digitalRead(powerup_button_pin) == LOW) {
    power_up_Yi(cam_range);
  }

  if (digitalRead(powerdown_button_pin) == LOW) {
    power_down_Yi(cam_range);
  }

  if (digitalRead(shutter_button_pin) == LOW) {
    Serial.println(take_picture(cam_range));
  }

  if (digitalRead(tmlapse_start_pin) == LOW) {
    timelapse(cam_range);
  }

  // turn LED off after 500 ms
  if (millis () > (time + 200) && time != 0)
   {
    digitalWrite (ONBOARD_LED, LOW);
    time = 0;
   }  // end if time up

}
<commit_msg>interrupt management<commit_after>/*
Première version du programme de controle des Yi
*/
#include <Arduino.h>
#include <Wire.h>

//const int shutter_pin = 2;
//const int power_pin = 4;
const int powerup_button_pin = 5;
const int powerdown_button_pin = 6;
const int tmlapse_start_pin = 7;
const int tmlapse_stop_pin = 8;
//const int shutter_led_pin = A0;
const int shutter_led_pin = 3;
const int shutter_button_pin = 9;

int pic_count = 0; // picture counter
int after_pic_delay = 800;
volatile int shutter_led_counter = 0;
long old_timestamp = 0;
long current_timestamp = 0;
const byte cam_range = 0b00000001;

// MCP23017 registers (everything except direction defaults to 0)

#define IODIRA   0x00   // IO direction  (0 = output, 1 = input (Default))
#define IODIRB   0x01
#define IOPOLA   0x02   // IO polarity   (0 = normal, 1 = inverse)
#define IOPOLB   0x03
#define GPINTENA 0x04   // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05
#define DEFVALA  0x06   // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB  0x07
#define INTCONA  0x08   // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB  0x09
#define IOCON    0x0A   // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B  // same as 0x0A
#define GPPUA    0x0C   // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB    0x0D
#define INFTFA   0x0E   // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB   0x0F
#define INTCAPA  0x10   // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB  0x11
#define GPIOA    0x12   // Port value. Write to change, read to obtain value
#define GPIOB    0x13
#define OLLATA   0x14   // Output latch. Write to latch output.
#define OLLATB   0x15

#define mcp1 0x20  // MCP23017 n°1 (shutter and power) is on I2C port 0x20
#define mcp2 0x21  // MCP23017 n°2 (shutter led input) is on I2C port 0x21

#define ISR_INDICATOR 12  // pin 12
#define ONBOARD_LED 13    // pin 13
volatile bool sht_led_activity;
int sht_LedToggle_array[8];
unsigned long time = 0;

void expanderWrite (const byte port, const byte reg, const byte data ){
  Wire.beginTransmission (port);
  Wire.write (reg);
  Wire.write (data);
  Wire.endTransmission ();
} // end of expanderWrite

// read a byte from the expander
unsigned int expanderRead (const byte port, const byte reg){
  Wire.beginTransmission (port);
  Wire.write (reg);
  Wire.endTransmission ();
  Wire.requestFrom (port, 1);
  return Wire.read();
} // end of expanderRead

// interrupt service routine, called when pin D2 goes from 0 to 1
void mcp2_interrupt ()
{
  digitalWrite (ISR_INDICATOR, HIGH);  // debugging
  sht_led_activity = true;   // set flag so main loop knows
}  // end of mcp2_interrupt

void myISR() {
  shutter_led_counter++;
}

void setup() {
  pinMode (ISR_INDICATOR, OUTPUT);  // for testing (ISR indicator)
  pinMode (ONBOARD_LED, OUTPUT);  // for onboard LED
  Serial.begin(9600);
  Serial.println("Starting program");
  Wire.begin ();
  // Set expander n°1 I/O as output
  expanderWrite(mcp1, IODIRA, 0x00);
  expanderWrite(mcp1, IODIRB, 0x00);

  // Set expander n°2 I/O as output. We will set inputs later
  expanderWrite(mcp2, IODIRA, 0x00);
  expanderWrite(mcp2, IODIRB, 0x00);

  // TODO set dynamically the pins as output
  // enable GPIOA pins as input
  expanderWrite(mcp2, IODIRA, 0xFF);
  // enable pull-up on switches
  expanderWrite(mcp2, GPPUA, 0xFF);
  // expander configuration register
  expanderWrite(mcp2, IOCON, 0b01100010); // no mirror interrupts, disable sequential mode, active HIGH

  // invert polarity
  //expanderWrite(mcp2, IOPOLA, 0xFF);  // invert polarity of signal - both ports

  // enable interrupts
  expanderWrite (mcp2, GPINTENA, cam_range); // enable interrupts

  //expanderWriteBoth(DEFVALA, 0b00000000); // defini la valeur par défaut à 0
  expanderWrite(mcp2, INTCONA, 0b00000000);// Active le mode "on change"
  // FIN MES TESTS
  // no interrupt yet
  sht_led_activity = false;

  // read from interrupt capture ports to clear them
  expanderRead (mcp2, INTCAPA);
  expanderRead (mcp2, INTCAPB);

  // pin 19 of MCP23017 is plugged into D2 of the Arduino which is interrupt 0
  attachInterrupt(0, mcp2_interrupt, RISING);
  //attachInterrupt(digitalPinToInterrupt(shutter_led_pin), mcp2_interrupt, CHANGE);

  // pinMode(shutter_pin, OUTPUT);
  // pinMode(power_pin, OUTPUT);
  pinMode(powerup_button_pin, INPUT_PULLUP);
  pinMode(powerdown_button_pin, INPUT_PULLUP);
  pinMode(tmlapse_start_pin, INPUT_PULLUP);
  pinMode(tmlapse_stop_pin, INPUT_PULLUP);
  pinMode(shutter_button_pin, INPUT_PULLUP);
  pinMode(shutter_led_pin, INPUT);
  //pinMode(A5, INPUT);
  //attachInterrupt(digitalPinToInterrupt(shutter_led_pin), myISR, RISING);

}

void power_up_Yi(const byte cam_range) {
  Serial.println("Starting the Yi");
  //Set expander n°1 GPIOA to HIGH
  expanderWrite(mcp1, GPIOA, cam_range);

  delay(500);
  //Set expander n°1 GPIOA to LOW
  expanderWrite(mcp1, GPIOA, 0b00000000);

  Serial.println("Pause during the boot");
  delay(10000); //attente mise en route
  Serial.println("The cams should be ready");
}

void power_down_Yi(const byte cam_range) {
  Serial.println("Shutting down the Yi");
  //Set expander n°1 GPIOA to HIGH
  expanderWrite(mcp1, GPIOA, cam_range);

  delay(2500);
  //Set expander n°1 GPIOA to LOW
  expanderWrite(mcp1, GPIOA, 0b00000000);
}

void handle_Sht_led_activity ()
{
  unsigned int sht_LedValue = 0;
  unsigned int sht_LedLastValue = 0;
  //Serial.println("Inside handle_Sht_led_activity function");
  sht_led_activity = false;  // ready for next time through the interrupt service routine
  digitalWrite (ISR_INDICATOR, LOW);  // debugging

  // Read port values, as required. Note that this re-arms the interrupts.

  if (expanderRead (mcp2, INFTFA))
    {

    sht_LedValue |= expanderRead (mcp2, INTCAPA);        // port B is in low-order byte
    }

    Serial.print("sht_LedValue : ");
    Serial.println(sht_LedValue, BIN);
    Serial.print("last State : ");
    Serial.println(sht_LedLastValue, BIN);
    Serial.print("Ou exclusif : ");
    Serial.println(sht_LedLastValue ^ sht_LedValue, BIN);
    Serial.println("");
  Serial.println ("Shutter Led toggles");
  //Serial.println ("0                   1");
  Serial.println ("0 1 2 3 4 5 6 7");

  // display which buttons were down at the time of the interrupt
  for (byte sht_Led = 0; sht_Led < 8; sht_Led++)
    {
    if ((sht_LedLastValue ^ sht_LedValue) & (1 << sht_Led)){
      //Serial.print ("01 ");
      sht_LedToggle_array[sht_Led]+=1;
      Serial.print(sht_LedToggle_array[sht_Led]);
      Serial.print(" ");
      }
    else {
      //Serial.print ("00 ");
      Serial.print(sht_LedToggle_array[sht_Led]);
      Serial.print(" ");
      }

    }
  sht_LedLastValue = sht_LedValue;
  Serial.println ();

  // if a switch is now pressed, turn LED on  (key down event)
  if (sht_LedValue)
    {
    time = millis ();  // remember when
    digitalWrite (ONBOARD_LED, HIGH);  // on-board LED
    }  // end if

}  // end of handle_Sht_led_activity

//Take a picture
long take_picture(const byte cam_range) {
  Serial.println("Taking picture...");
  long pic_start_time = millis();
  byte shutter_led_check = 0b00000000;
  memset(sht_LedToggle_array,0,sizeof(sht_LedToggle_array
  )); //Reset the array

  //Set expander n°1 GPIOB to HIGH to "press" the shutter button
  expanderWrite(mcp1, GPIOB, cam_range);
  delay(100);
  //Set expander n°1 GPIOB to LOW to "release" the shutter button
  expanderWrite(mcp1, GPIOB, 0b00000000);

  while (shutter_led_check != cam_range) { // Wait for the shutter led return
    if (sht_led_activity) {
      handle_Sht_led_activity();

      for (byte sht_Led = 0; sht_Led < 8; sht_Led++)
      {
        if ((sht_LedToggle_array[sht_Led] == 1) & (cam_range & (1 << sht_Led)))
          {
          shutter_led_check = shutter_led_check ^ (1 << sht_Led);
          Serial.print("1 << sht_Led : ");
          Serial.println(1 << sht_Led, BIN);
          Serial.print("shutter_led_check : ");
          Serial.println(shutter_led_check, BIN);
        }
        }
      }
    if (millis()-pic_start_time > 2500) {
      Serial.println("No response");
      return 0;
    }
  }
  Serial.println("Shutter leds detected");

  Serial.println("Pause");
  unsigned long delay_Start_Time = millis();
  // Wait for the cams to be ready, and check interrupt in case of a failure
  while (millis() < (delay_Start_Time + after_pic_delay)) {
    if (sht_led_activity) {
      handle_Sht_led_activity();
      for (byte sht_Led = 0; sht_Led < 8; sht_Led++)
      {
        if ((sht_LedToggle_array[sht_Led] > 1) & (cam_range & (1 << sht_Led)))
        {
          Serial.print("Error on cam n°");
          Serial.println(sht_Led);
          return -1;
        }
      }

    }

    }
  Serial.println("End of pause");
  return pic_start_time;
}

void timelapse(const byte cam_range) {
  Serial.println("Starting timelapse");
  int pic_shutter_request = 0;
  int pic_shutter_taken = 0;
  while (true) {
    current_timestamp = take_picture(cam_range);
    pic_shutter_request++;
    Serial.print("Interval : ");
    Serial.print(current_timestamp - old_timestamp);
    Serial.println("ms");
    if (current_timestamp != 0) {
      old_timestamp = current_timestamp;
      pic_shutter_taken++;
      Serial.print("Successful pictures : ");
      Serial.print(pic_shutter_taken);
      Serial.print(" of ");
      Serial.println(pic_shutter_request);
      Serial.print("Missing pictures : ");
      Serial.println(pic_shutter_request - pic_shutter_taken);
    }

    if (digitalRead(tmlapse_stop_pin) == LOW) {
      Serial.println("Timelapse stopped");
      break;
    }
  }
}

void loop() {

  if (digitalRead(powerup_button_pin) == LOW) {
    power_up_Yi(cam_range);
  }

  if (digitalRead(powerdown_button_pin) == LOW) {
    power_down_Yi(cam_range);
  }

  if (digitalRead(shutter_button_pin) == LOW) {
    Serial.println(take_picture(cam_range));
  }

  if (digitalRead(tmlapse_start_pin) == LOW) {
    timelapse(cam_range);
  }

  // turn LED off after 500 ms
  if (millis () > (time + 200) && time != 0)
   {
    digitalWrite (ONBOARD_LED, LOW);
    time = 0;
   }  // end if time up

}
<|endoftext|>


<commit_before>#include "scimed/wx.h"
#include <wx/sizer.h>

// todo:
// add loading, zooming and panning in image
// add loading/saving and specifying areas
// add preview pane

class wxImagePanel : public wxPanel
{
  wxImage image;
  wxBitmap resized;
  int w, h;
  bool displayImage_;

 public:
  explicit wxImagePanel(wxFrame* parent)
      : wxPanel(parent), displayImage_(false)
  {
    Bind(wxEVT_SIZE, &wxImagePanel::OnSize, this);
    Bind(wxEVT_PAINT, &wxImagePanel::OnPaint, this);
  }

  bool LoadImage(wxString file, wxBitmapType format) {
    displayImage_ = image.LoadFile(file, format);
    w = -1;
    h = -1;
    // displayImage_ = true;

    if( displayImage_ ) {
      Refresh();
    }

    return displayImage_;
  }

  void OnPaint(wxPaintEvent & evt) {
    if(displayImage_ == false) {
      return;
    }

    wxPaintDC dc(this);

    int neww, newh;
    dc.GetSize( &neww, &newh );

    if( neww != w || newh != h ) {
      resized = wxBitmap( image.Scale( neww, newh /*, wxIMAGE_QUALITY_HIGH*/ ) );
      w = neww;
      h = newh;
      dc.DrawBitmap( resized, 0, 0, false );
    }
    else {
      dc.DrawBitmap( resized, 0, 0, false );
    }
  }

  void OnSize(wxSizeEvent& event){
    Refresh();
    //skip the event.
    event.Skip();
  }

  // some useful events
  /*
   void mouseMoved(wxMouseEvent& event);
   void mouseDown(wxMouseEvent& event);
   void mouseWheelMoved(wxMouseEvent& event);
   void mouseReleased(wxMouseEvent& event);
   void rightClick(wxMouseEvent& event);
   void mouseLeftWindow(wxMouseEvent& event);
   void keyPressed(wxKeyEvent& event);
   void keyReleased(wxKeyEvent& event);
   */
};

// some useful events
/*
 void wxImagePanel::mouseMoved(wxMouseEvent& event) {}
 void wxImagePanel::mouseDown(wxMouseEvent& event) {}
 void wxImagePanel::mouseWheelMoved(wxMouseEvent& event) {}
 void wxImagePanel::mouseReleased(wxMouseEvent& event) {}
 void wxImagePanel::rightClick(wxMouseEvent& event) {}
 void wxImagePanel::mouseLeftWindow(wxMouseEvent& event) {}
 void wxImagePanel::keyPressed(wxKeyEvent& event) {}
 void wxImagePanel::keyReleased(wxKeyEvent& event) {}
 */

class MyFrame: public wxFrame
{
 public:
  MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size), title_(title) {
    SetMenuBar(CreateMenuBar());
    CreateStatusBar();
    SetStatusText("");

    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    drawPane = new wxImagePanel(this);
    sizer->Add(drawPane, 1, wxEXPAND);
    SetSizer(sizer);

    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExit, this, wxID_EXIT);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnAbout, this, wxID_ABOUT);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnSave, this, wxID_SAVE);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnSaveAs, this, wxID_SAVEAS);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnOpen, this, wxID_OPEN);
  }

 private:
  wxImagePanel * drawPane;
  wxString title_;
  wxString filename_;

  void UpdateTitle() {
    if( filename_.IsEmpty() ) {
      SetTitle( title_ );
    }
    else {
      SetTitle( title_ + " - " + filename_ );
    }
  }

  wxMenu* CreateFileMenu() {
    wxMenu *menuFile = new wxMenu;
    menuFile->Append(wxID_OPEN);
    menuFile->Append(wxID_SAVE);
    menuFile->Append(wxID_SAVEAS);
    menuFile->AppendSeparator();
    menuFile->Append(wxID_EXIT);
    return menuFile;
  }

  wxMenu* CreateHelpMenu() {
    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);
    return menuHelp;
  }

  wxMenuBar* CreateMenuBar() {
    wxMenuBar *menuBar = new wxMenuBar;
    menuBar->Append(CreateFileMenu(), "&File");
    menuBar->Append(CreateHelpMenu(), "&Help");
    return menuBar;
  }

  void OnSave(wxCommandEvent& event){
    if( filename_.IsEmpty() ) {
      OnSaveAs(event);
      return;
    }

    // do saving...
  }

  void OnSaveAs(wxCommandEvent& event) {
    wxFileDialog saveFileDialog(this, _("Save scim file"), "", "", "SCIM files (*.png)|*.png", wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
    if (saveFileDialog.ShowModal() == wxID_CANCEL) {
      return;
    }
    filename_ = saveFileDialog.GetPath();
    UpdateTitle();
    OnSave(event);
  }

  void OnOpen(wxCommandEvent& event) {
    wxFileDialog openFileDialog(this, _("Open scim file"), "", "", "SCIM files (*.png)|*.png", wxFD_OPEN|wxFD_FILE_MUST_EXIST);
    if (openFileDialog.ShowModal() == wxID_CANCEL) {
      return;
    }

    if( drawPane->LoadImage(openFileDialog.GetPath(), wxBITMAP_TYPE_PNG) ) {
      filename_ = openFileDialog.GetPath();
    }
    else {
      filename_ = "";
    }
    UpdateTitle();
  }

  void OnExit(wxCommandEvent& event){
    Close(true);
  }

  void OnAbout(wxCommandEvent& event){
    wxMessageBox("Scimed - the Scalable Image Editor", "About Scimed", wxOK | wxICON_INFORMATION);
  }
};

////////////////////////////////////////////////////////////////////////////////

class MyApp: public wxApp
{
 public:
  virtual bool OnInit() {
    wxInitAllImageHandlers();
    MyFrame *frame = new MyFrame( "Scimed", wxPoint(50, 50), wxSize(450, 340) );
    frame->Show( true );
    return true;
  }
};
wxIMPLEMENT_APP(MyApp);
<commit_msg>renamed panel<commit_after>#include "scimed/wx.h"
#include <wx/sizer.h>

// todo:
// add loading, zooming and panning in image
// add loading/saving and specifying areas
// add preview pane

class ImagePanel : public wxPanel
{
  wxImage image;
  wxBitmap resized;
  int w, h;
  bool displayImage_;

 public:
  explicit ImagePanel(wxFrame* parent)
      : wxPanel(parent), displayImage_(false)
  {
    Bind(wxEVT_SIZE, &ImagePanel::OnSize, this);
    Bind(wxEVT_PAINT, &ImagePanel::OnPaint, this);
  }

  bool LoadImage(wxString file, wxBitmapType format) {
    displayImage_ = image.LoadFile(file, format);
    w = -1;
    h = -1;
    // displayImage_ = true;

    if( displayImage_ ) {
      Refresh();
    }

    return displayImage_;
  }

  void OnPaint(wxPaintEvent & evt) {
    if(displayImage_ == false) {
      return;
    }

    wxPaintDC dc(this);

    int neww, newh;
    dc.GetSize( &neww, &newh );

    if( neww != w || newh != h ) {
      resized = wxBitmap( image.Scale( neww, newh /*, wxIMAGE_QUALITY_HIGH*/ ) );
      w = neww;
      h = newh;
      dc.DrawBitmap( resized, 0, 0, false );
    }
    else {
      dc.DrawBitmap( resized, 0, 0, false );
    }
  }

  void OnSize(wxSizeEvent& event){
    Refresh();
    //skip the event.
    event.Skip();
  }

  // some useful events
  /*
   void mouseMoved(wxMouseEvent& event);
   void mouseDown(wxMouseEvent& event);
   void mouseWheelMoved(wxMouseEvent& event);
   void mouseReleased(wxMouseEvent& event);
   void rightClick(wxMouseEvent& event);
   void mouseLeftWindow(wxMouseEvent& event);
   void keyPressed(wxKeyEvent& event);
   void keyReleased(wxKeyEvent& event);
   */
};

// some useful events
/*
 void ImagePanel::mouseMoved(wxMouseEvent& event) {}
 void ImagePanel::mouseDown(wxMouseEvent& event) {}
 void ImagePanel::mouseWheelMoved(wxMouseEvent& event) {}
 void ImagePanel::mouseReleased(wxMouseEvent& event) {}
 void ImagePanel::rightClick(wxMouseEvent& event) {}
 void ImagePanel::mouseLeftWindow(wxMouseEvent& event) {}
 void ImagePanel::keyPressed(wxKeyEvent& event) {}
 void ImagePanel::keyReleased(wxKeyEvent& event) {}
 */

class MyFrame: public wxFrame
{
 public:
  MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size), title_(title) {
    SetMenuBar(CreateMenuBar());
    CreateStatusBar();
    SetStatusText("");

    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    drawPane = new ImagePanel(this);
    sizer->Add(drawPane, 1, wxEXPAND);
    SetSizer(sizer);

    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExit, this, wxID_EXIT);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnAbout, this, wxID_ABOUT);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnSave, this, wxID_SAVE);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnSaveAs, this, wxID_SAVEAS);
    Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnOpen, this, wxID_OPEN);
  }

 private:
  ImagePanel * drawPane;
  wxString title_;
  wxString filename_;

  void UpdateTitle() {
    if( filename_.IsEmpty() ) {
      SetTitle( title_ );
    }
    else {
      SetTitle( title_ + " - " + filename_ );
    }
  }

  wxMenu* CreateFileMenu() {
    wxMenu *menuFile = new wxMenu;
    menuFile->Append(wxID_OPEN);
    menuFile->Append(wxID_SAVE);
    menuFile->Append(wxID_SAVEAS);
    menuFile->AppendSeparator();
    menuFile->Append(wxID_EXIT);
    return menuFile;
  }

  wxMenu* CreateHelpMenu() {
    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);
    return menuHelp;
  }

  wxMenuBar* CreateMenuBar() {
    wxMenuBar *menuBar = new wxMenuBar;
    menuBar->Append(CreateFileMenu(), "&File");
    menuBar->Append(CreateHelpMenu(), "&Help");
    return menuBar;
  }

  void OnSave(wxCommandEvent& event){
    if( filename_.IsEmpty() ) {
      OnSaveAs(event);
      return;
    }

    // do saving...
  }

  void OnSaveAs(wxCommandEvent& event) {
    wxFileDialog saveFileDialog(this, _("Save scim file"), "", "", "SCIM files (*.png)|*.png", wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
    if (saveFileDialog.ShowModal() == wxID_CANCEL) {
      return;
    }
    filename_ = saveFileDialog.GetPath();
    UpdateTitle();
    OnSave(event);
  }

  void OnOpen(wxCommandEvent& event) {
    wxFileDialog openFileDialog(this, _("Open scim file"), "", "", "SCIM files (*.png)|*.png", wxFD_OPEN|wxFD_FILE_MUST_EXIST);
    if (openFileDialog.ShowModal() == wxID_CANCEL) {
      return;
    }

    if( drawPane->LoadImage(openFileDialog.GetPath(), wxBITMAP_TYPE_PNG) ) {
      filename_ = openFileDialog.GetPath();
    }
    else {
      filename_ = "";
    }
    UpdateTitle();
  }

  void OnExit(wxCommandEvent& event){
    Close(true);
  }

  void OnAbout(wxCommandEvent& event){
    wxMessageBox("Scimed - the Scalable Image Editor", "About Scimed", wxOK | wxICON_INFORMATION);
  }
};

////////////////////////////////////////////////////////////////////////////////

class MyApp: public wxApp
{
 public:
  virtual bool OnInit() {
    wxInitAllImageHandlers();
    MyFrame *frame = new MyFrame( "Scimed", wxPoint(50, 50), wxSize(450, 340) );
    frame->Show( true );
    return true;
  }
};
wxIMPLEMENT_APP(MyApp);
<|endoftext|>


<commit_before>#include <libmesh/equation_systems.h>
#include <libmesh/replicated_mesh.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/dof_map.h>
#include <libmesh/system.h>
#include <libmesh/mesh_function.h>
#include <libmesh/numeric_vector.h>
#include <libmesh/elem.h>

#include "test_comm.h"
#include "libmesh_cppunit.h"

using namespace libMesh;

Number projection_function (const Point & p,
                            const Parameters &,
                            const std::string &,
                            const std::string &)
{
  return
    cos(.5*libMesh::pi*p(0)) *
    sin(.5*libMesh::pi*p(1)) *
    cos(.5*libMesh::pi*p(2));
}

Number trilinear_function (const Point & p,
                           const Parameters &,
                           const std::string &,
                           const std::string &)
{
  return 8*p(0) + 80*p(1) + 800*p(2);
}

class MeshFunctionTest : public CppUnit::TestCase
{
  /**
   * Tests for general MeshFunction capability.
   */
public:
  LIBMESH_CPPUNIT_TEST_SUITE( MeshFunctionTest );

#if LIBMESH_DIM > 1
  CPPUNIT_TEST( test_subdomain_id_sets );
#endif
#if LIBMESH_DIM > 2
#ifdef LIBMESH_ENABLE_AMR
  CPPUNIT_TEST( test_p_level );
#endif
#endif

  CPPUNIT_TEST_SUITE_END();

protected:

public:
  void setUp() {}

  void tearDown() {}

  // test that mesh function works correctly with subdomain id sets.
  void test_subdomain_id_sets()
  {
    LOG_UNIT_TEST;

    ReplicatedMesh mesh(*TestCommWorld);

    MeshTools::Generation::build_square (mesh,
                                         4, 4,
                                         0., 1.,
                                         0., 1.,
                                         QUAD4);

    // Set a subdomain id for all elements, based on location.
    for (auto & elem : mesh.active_element_ptr_range())
      {
        Point c = elem->vertex_average();
        elem->subdomain_id() =
          subdomain_id_type(c(0)*4) + subdomain_id_type(c(1)*4)*10;
      }

    // Add a discontinuous variable so we can easily see what side of
    // an interface we're querying
    EquationSystems es(mesh);
    System & sys = es.add_system<System> ("SimpleSystem");
    unsigned int u_var = sys.add_variable("u", CONSTANT, MONOMIAL);

    es.init();
    sys.project_solution(trilinear_function, nullptr, es.parameters);

    MeshFunction mesh_function (sys.get_equation_systems(),
                                *sys.current_local_solution,
                                sys.get_dof_map(),
                                {u_var});

    // Checkerboard pattern
    const std::set<subdomain_id_type> sbdids1 {0,2,11,13,20,22,31,33};
    const std::set<subdomain_id_type> sbdids2 {1,3,10,12,21,23,30,32};
    mesh_function.init();
    mesh_function.enable_out_of_mesh_mode(DenseVector<Number>());
    mesh_function.set_subdomain_ids(&sbdids1);

    DenseVector<Number> vec_values;
    const std::string dummy;

    // Make sure the MeshFunction's values interpolate the projected solution
    // at the nodes
    for (auto & elem : mesh.active_local_element_ptr_range())
      {
        const Point c = elem->vertex_average();
        const Real expected_value =
          libmesh_real(trilinear_function(c, es.parameters, dummy, dummy));
        const std::vector<Point> offsets
          {{0,-1/8.}, {1/8.,0}, {0,1/8.}, {-1/8.,0}};
        for (Point offset : offsets)
          {
            const Point p = c + offset;
            mesh_function(p, 0, vec_values, &sbdids1);
            const Number retval1 = vec_values.empty() ? -12345 : vec_values(0);
            mesh_function(p, 0, vec_values, &sbdids2);
            const Number retval2 = vec_values.empty() ? -12345 : vec_values(0);
            mesh_function(c, 0, vec_values, nullptr);
            const Number retval3 = vec_values.empty() ? -12345 : vec_values(0);

            LIBMESH_ASSERT_FP_EQUAL(libmesh_real(retval3), expected_value,
                                    TOLERANCE * TOLERANCE);

            if (sbdids1.count(elem->subdomain_id()))
              {
                CPPUNIT_ASSERT(!sbdids2.count(elem->subdomain_id()));
                LIBMESH_ASSERT_FP_EQUAL(libmesh_real(retval1), expected_value,
                                        TOLERANCE * TOLERANCE);

                mesh_function(c, 0, vec_values, &sbdids2);
                CPPUNIT_ASSERT(vec_values.empty());
              }
            else
              {
                LIBMESH_ASSERT_FP_EQUAL(libmesh_real(retval2), expected_value,
                                        TOLERANCE * TOLERANCE);

                mesh_function(c, 0, vec_values, &sbdids1);
                CPPUNIT_ASSERT(vec_values.empty());
              }
          }
      }
  }

  // test that mesh function works correctly with non-zero
  // Elem::p_level() values.
#ifdef LIBMESH_ENABLE_AMR
  void test_p_level()
  {
    LOG_UNIT_TEST;

    ReplicatedMesh mesh(*TestCommWorld);

    MeshTools::Generation::build_cube (mesh,
                                       5, 5, 5,
                                       0., 1.,
                                       0., 1.,
                                       0., 1.,
                                       HEX20);

    // Bump the p-level for all elements. We will create a system with
    // a FIRST, LAGRANGE variable and then use the additional p-level
    // to solve with quadratic elements. Note: set_p_level(1) actually
    // _increases_ the existing variable order by 1, it does not set
    // it to 1.
    for (auto & elem : mesh.active_element_ptr_range())
      elem->set_p_level(1);

    EquationSystems es(mesh);
    System & sys = es.add_system<System> ("SimpleSystem");
    unsigned int u_var = sys.add_variable("u", FIRST, LAGRANGE);

    es.init();
    sys.project_solution(projection_function, nullptr, es.parameters);

    std::unique_ptr<NumericVector<Number>> mesh_function_vector
      = NumericVector<Number>::build(sys.comm());
    mesh_function_vector->init(sys.n_dofs(), sys.n_local_dofs(),
                               sys.get_dof_map().get_send_list(), false,
                               GHOSTED);

    sys.solution->localize(*mesh_function_vector,
                           sys.get_dof_map().get_send_list());

    // So the MeshFunction knows which variables to compute values for.
    // std::make_unique doesn't like if we try to use {u_var} in-place?
    std::vector<unsigned int> variables {u_var};

    auto mesh_function =
      std::make_unique<MeshFunction>(sys.get_equation_systems(),
                                        *mesh_function_vector,
                                        sys.get_dof_map(),
                                        variables);

    mesh_function->init();
    mesh_function->set_point_locator_tolerance(0.0001);
    DenseVector<Number> vec_values;
    std::string dummy;

    // Make sure the MeshFunction's values interpolate the projected solution
    // at the nodes
    for (const auto & node : mesh.local_node_ptr_range())
      {
        (*mesh_function)(*node, /*time=*/ 0., vec_values);
        Number mesh_function_value =
          projection_function(*node,
                              es.parameters,
                              dummy,
                              dummy);

        LIBMESH_ASSERT_FP_EQUAL
          (libmesh_real(vec_values(0)),
           libmesh_real(mesh_function_value),
           TOLERANCE*TOLERANCE);
      }
  }
#endif // LIBMESH_ENABLE_AMR
};

CPPUNIT_TEST_SUITE_REGISTRATION( MeshFunctionTest );
<commit_msg>Fix clang warning<commit_after>#include <libmesh/equation_systems.h>
#include <libmesh/replicated_mesh.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/dof_map.h>
#include <libmesh/system.h>
#include <libmesh/mesh_function.h>
#include <libmesh/numeric_vector.h>
#include <libmesh/elem.h>

#include "test_comm.h"
#include "libmesh_cppunit.h"

using namespace libMesh;

Number projection_function (const Point & p,
                            const Parameters &,
                            const std::string &,
                            const std::string &)
{
  return
    cos(.5*libMesh::pi*p(0)) *
    sin(.5*libMesh::pi*p(1)) *
    cos(.5*libMesh::pi*p(2));
}

Number trilinear_function (const Point & p,
                           const Parameters &,
                           const std::string &,
                           const std::string &)
{
  return 8*p(0) + 80*p(1) + 800*p(2);
}

class MeshFunctionTest : public CppUnit::TestCase
{
  /**
   * Tests for general MeshFunction capability.
   */
public:
  LIBMESH_CPPUNIT_TEST_SUITE( MeshFunctionTest );

#if LIBMESH_DIM > 1
  CPPUNIT_TEST( test_subdomain_id_sets );
#endif
#if LIBMESH_DIM > 2
#ifdef LIBMESH_ENABLE_AMR
  CPPUNIT_TEST( test_p_level );
#endif
#endif

  CPPUNIT_TEST_SUITE_END();

protected:

public:
  void setUp() {}

  void tearDown() {}

  // test that mesh function works correctly with subdomain id sets.
  void test_subdomain_id_sets()
  {
    LOG_UNIT_TEST;

    ReplicatedMesh mesh(*TestCommWorld);

    MeshTools::Generation::build_square (mesh,
                                         4, 4,
                                         0., 1.,
                                         0., 1.,
                                         QUAD4);

    // Set a subdomain id for all elements, based on location.
    for (auto & elem : mesh.active_element_ptr_range())
      {
        Point c = elem->vertex_average();
        elem->subdomain_id() =
          subdomain_id_type(c(0)*4) + subdomain_id_type(c(1)*4)*10;
      }

    // Add a discontinuous variable so we can easily see what side of
    // an interface we're querying
    EquationSystems es(mesh);
    System & sys = es.add_system<System> ("SimpleSystem");
    unsigned int u_var = sys.add_variable("u", CONSTANT, MONOMIAL);

    es.init();
    sys.project_solution(trilinear_function, nullptr, es.parameters);

    MeshFunction mesh_function (sys.get_equation_systems(),
                                *sys.current_local_solution,
                                sys.get_dof_map(),
                                u_var);

    // Checkerboard pattern
    const std::set<subdomain_id_type> sbdids1 {0,2,11,13,20,22,31,33};
    const std::set<subdomain_id_type> sbdids2 {1,3,10,12,21,23,30,32};
    mesh_function.init();
    mesh_function.enable_out_of_mesh_mode(DenseVector<Number>());
    mesh_function.set_subdomain_ids(&sbdids1);

    DenseVector<Number> vec_values;
    const std::string dummy;

    // Make sure the MeshFunction's values interpolate the projected solution
    // at the nodes
    for (auto & elem : mesh.active_local_element_ptr_range())
      {
        const Point c = elem->vertex_average();
        const Real expected_value =
          libmesh_real(trilinear_function(c, es.parameters, dummy, dummy));
        const std::vector<Point> offsets
          {{0,-1/8.}, {1/8.,0}, {0,1/8.}, {-1/8.,0}};
        for (Point offset : offsets)
          {
            const Point p = c + offset;
            mesh_function(p, 0, vec_values, &sbdids1);
            const Number retval1 = vec_values.empty() ? -12345 : vec_values(0);
            mesh_function(p, 0, vec_values, &sbdids2);
            const Number retval2 = vec_values.empty() ? -12345 : vec_values(0);
            mesh_function(c, 0, vec_values, nullptr);
            const Number retval3 = vec_values.empty() ? -12345 : vec_values(0);

            LIBMESH_ASSERT_FP_EQUAL(libmesh_real(retval3), expected_value,
                                    TOLERANCE * TOLERANCE);

            if (sbdids1.count(elem->subdomain_id()))
              {
                CPPUNIT_ASSERT(!sbdids2.count(elem->subdomain_id()));
                LIBMESH_ASSERT_FP_EQUAL(libmesh_real(retval1), expected_value,
                                        TOLERANCE * TOLERANCE);

                mesh_function(c, 0, vec_values, &sbdids2);
                CPPUNIT_ASSERT(vec_values.empty());
              }
            else
              {
                LIBMESH_ASSERT_FP_EQUAL(libmesh_real(retval2), expected_value,
                                        TOLERANCE * TOLERANCE);

                mesh_function(c, 0, vec_values, &sbdids1);
                CPPUNIT_ASSERT(vec_values.empty());
              }
          }
      }
  }

  // test that mesh function works correctly with non-zero
  // Elem::p_level() values.
#ifdef LIBMESH_ENABLE_AMR
  void test_p_level()
  {
    LOG_UNIT_TEST;

    ReplicatedMesh mesh(*TestCommWorld);

    MeshTools::Generation::build_cube (mesh,
                                       5, 5, 5,
                                       0., 1.,
                                       0., 1.,
                                       0., 1.,
                                       HEX20);

    // Bump the p-level for all elements. We will create a system with
    // a FIRST, LAGRANGE variable and then use the additional p-level
    // to solve with quadratic elements. Note: set_p_level(1) actually
    // _increases_ the existing variable order by 1, it does not set
    // it to 1.
    for (auto & elem : mesh.active_element_ptr_range())
      elem->set_p_level(1);

    EquationSystems es(mesh);
    System & sys = es.add_system<System> ("SimpleSystem");
    unsigned int u_var = sys.add_variable("u", FIRST, LAGRANGE);

    es.init();
    sys.project_solution(projection_function, nullptr, es.parameters);

    std::unique_ptr<NumericVector<Number>> mesh_function_vector
      = NumericVector<Number>::build(sys.comm());
    mesh_function_vector->init(sys.n_dofs(), sys.n_local_dofs(),
                               sys.get_dof_map().get_send_list(), false,
                               GHOSTED);

    sys.solution->localize(*mesh_function_vector,
                           sys.get_dof_map().get_send_list());

    // So the MeshFunction knows which variables to compute values for.
    // std::make_unique doesn't like if we try to use {u_var} in-place?
    std::vector<unsigned int> variables {u_var};

    auto mesh_function =
      std::make_unique<MeshFunction>(sys.get_equation_systems(),
                                        *mesh_function_vector,
                                        sys.get_dof_map(),
                                        variables);

    mesh_function->init();
    mesh_function->set_point_locator_tolerance(0.0001);
    DenseVector<Number> vec_values;
    std::string dummy;

    // Make sure the MeshFunction's values interpolate the projected solution
    // at the nodes
    for (const auto & node : mesh.local_node_ptr_range())
      {
        (*mesh_function)(*node, /*time=*/ 0., vec_values);
        Number mesh_function_value =
          projection_function(*node,
                              es.parameters,
                              dummy,
                              dummy);

        LIBMESH_ASSERT_FP_EQUAL
          (libmesh_real(vec_values(0)),
           libmesh_real(mesh_function_value),
           TOLERANCE*TOLERANCE);
      }
  }
#endif // LIBMESH_ENABLE_AMR
};

CPPUNIT_TEST_SUITE_REGISTRATION( MeshFunctionTest );
<|endoftext|>