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

#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"

#include <set>

#include "base/base64.h"
#include "base/crypto/signature_verifier.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/scoped_handle.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"  // TODO(viettrungluu): delete me.
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension_unpacker.h"
#include "chrome/common/json_value_serializer.h"
#include "gfx/codec/png_codec.h"
#include "third_party/skia/include/core/SkBitmap.h"

const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24";

SandboxedExtensionUnpacker::SandboxedExtensionUnpacker(
    const FilePath& crx_path,
    const FilePath& temp_path,
    ResourceDispatcherHost* rdh,
    SandboxedExtensionUnpackerClient* client)
    : crx_path_(crx_path), temp_path_(temp_path),
      thread_identifier_(ChromeThread::ID_COUNT),
      rdh_(rdh), client_(client), got_response_(false) {
}

void SandboxedExtensionUnpacker::Start() {
  // We assume that we are started on the thread that the client wants us to do
  // file IO on.
  CHECK(ChromeThread::GetCurrentThreadIdentifier(&thread_identifier_));

  // Create a temporary directory to work in.
  if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) {
    ReportFailure("Could not create temporary directory.");
    return;
  }

  // Initialize the path that will eventually contain the unpacked extension.
  extension_root_ = temp_dir_.path().AppendASCII(
      extension_filenames::kTempExtensionName);

  // Extract the public key and validate the package.
  if (!ValidateSignature())
    return;  // ValidateSignature() already reported the error.

  // Copy the crx file into our working directory.
  FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName());
  if (!file_util::CopyFile(crx_path_, temp_crx_path)) {
    ReportFailure("Failed to copy extension file to temporary directory.");
    return;
  }

  // If we are supposed to use a subprocess, kick off the subprocess.
  //
  // TODO(asargent) we shouldn't need to do this branch here - instead
  // UtilityProcessHost should handle it for us. (http://crbug.com/19192)
  bool use_utility_process = rdh_ &&
      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
  if (use_utility_process) {
    // The utility process will have access to the directory passed to
    // SandboxedExtensionUnpacker.  That directory should not contain a
    // symlink or NTFS reparse point.  When the path is used, following
    // the link/reparse point will cause file system access outside the
    // sandbox path, and the sandbox will deny the operation.
    FilePath link_free_crx_path;
    if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) {
      LOG(ERROR) << "Could not get the normalized path of "
                 << temp_crx_path.value();
#if defined (OS_WIN)
      // On windows, it is possible to mount a disk without the root of that
      // disk having a drive letter.  The sandbox does not support this.
      // See crbug/49530 .
      ReportFailure(
          "Can not unpack extension.  To safely unpack an extension, "
          "there must be a path to your profile directory that starts "
          "with a drive letter and does not contain a junction, mount "
          "point, or symlink.  No such path exists for your profile.");
#else
      ReportFailure(
          "Can not unpack extension.  To safely unpack an extension, "
          "there must be a path to your profile directory that does "
          "not contain a symlink.  No such path exists for your profile.");
#endif
      return;
    }

    ChromeThread::PostTask(
        ChromeThread::IO, FROM_HERE,
        NewRunnableMethod(
            this,
            &SandboxedExtensionUnpacker::StartProcessOnIOThread,
            link_free_crx_path));
  } else {
    // Otherwise, unpack the extension in this process.
    ExtensionUnpacker unpacker(temp_crx_path);
    if (unpacker.Run() && unpacker.DumpImagesToFile() &&
        unpacker.DumpMessageCatalogsToFile()) {
      OnUnpackExtensionSucceeded(*unpacker.parsed_manifest());
    } else {
      OnUnpackExtensionFailed(unpacker.error_message());
    }
  }
}

void SandboxedExtensionUnpacker::StartProcessOnIOThread(
    const FilePath& temp_crx_path) {
  UtilityProcessHost* host = new UtilityProcessHost(
      rdh_, this, thread_identifier_);
  host->StartExtensionUnpacker(temp_crx_path);
}

void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded(
    const DictionaryValue& manifest) {
  // Skip check for unittests.
  if (thread_identifier_ != ChromeThread::ID_COUNT)
    DCHECK(ChromeThread::CurrentlyOn(thread_identifier_));
  got_response_ = true;

  scoped_ptr<DictionaryValue> final_manifest(RewriteManifestFile(manifest));
  if (!final_manifest.get())
    return;

  // Create an extension object that refers to the temporary location the
  // extension was unpacked to. We use this until the extension is finally
  // installed. For example, the install UI shows images from inside the
  // extension.
  extension_.reset(new Extension(extension_root_));

  // Localize manifest now, so confirm UI gets correct extension name.
  std::string error;
  if (!extension_l10n_util::LocalizeExtension(extension_.get(),
                                              final_manifest.get(),
                                              &error)) {
    ReportFailure(error);
    return;
  }

  if (!extension_->InitFromValue(*final_manifest, true, &error)) {
    ReportFailure(std::string("Manifest is invalid: ") + error);
    return;
  }

  if (!RewriteImageFiles())
    return;

  if (!RewriteCatalogFiles())
    return;

  ReportSuccess();
}

void SandboxedExtensionUnpacker::OnUnpackExtensionFailed(
    const std::string& error) {
  DCHECK(ChromeThread::CurrentlyOn(thread_identifier_));
  got_response_ = true;
  ReportFailure(error);
}

void SandboxedExtensionUnpacker::OnProcessCrashed() {
  // Don't report crashes if they happen after we got a response.
  if (got_response_)
    return;

  ReportFailure("Utility process crashed while trying to install.");
}

bool SandboxedExtensionUnpacker::ValidateSignature() {
  ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb"));
  if (!file.get()) {
    ReportFailure("Could not open crx file for reading");
    return false;
  }

  // Read and verify the header.
  ExtensionHeader header;
  size_t len;

  // TODO(erikkay): Yuck.  I'm not a big fan of this kind of code, but it
  // appears that we don't have any endian/alignment aware serialization
  // code in the code base.  So for now, this assumes that we're running
  // on a little endian machine with 4 byte alignment.
  len = fread(&header, 1, sizeof(ExtensionHeader),
      file.get());
  if (len < sizeof(ExtensionHeader)) {
    ReportFailure("Invalid crx header");
    return false;
  }
  if (strncmp(kExtensionHeaderMagic, header.magic,
      sizeof(header.magic))) {
    ReportFailure("Bad magic number");
    return false;
  }
  if (header.version != kCurrentVersion) {
    ReportFailure("Bad version number");
    return false;
  }
  if (header.key_size > kMaxPublicKeySize ||
      header.signature_size > kMaxSignatureSize) {
    ReportFailure("Excessively large key or signature");
    return false;
  }

  std::vector<uint8> key;
  key.resize(header.key_size);
  len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
  if (len < header.key_size) {
    ReportFailure("Invalid public key");
    return false;
  }

  std::vector<uint8> signature;
  signature.resize(header.signature_size);
  len = fread(&signature.front(), sizeof(uint8), header.signature_size,
      file.get());
  if (len < header.signature_size) {
    ReportFailure("Invalid signature");
    return false;
  }

  base::SignatureVerifier verifier;
  if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
                           sizeof(extension_misc::kSignatureAlgorithm),
                           &signature.front(),
                           signature.size(),
                           &key.front(),
                           key.size())) {
    ReportFailure("Signature verification initialization failed. "
                  "This is most likely caused by a public key in "
                  "the wrong format (should encode algorithm).");
    return false;
  }

  unsigned char buf[1 << 12];
  while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
    verifier.VerifyUpdate(buf, len);

  if (!verifier.VerifyFinal()) {
    ReportFailure("Signature verification failed");
    return false;
  }

  base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()),
      key.size()), &public_key_);
  return true;
}

void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) {
  client_->OnUnpackFailure(error);
}

void SandboxedExtensionUnpacker::ReportSuccess() {
  // Client takes ownership of temporary directory and extension.
  client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_,
                           extension_.release());
}

DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile(
    const DictionaryValue& manifest) {
  // Add the public key extracted earlier to the parsed manifest and overwrite
  // the original manifest. We do this to ensure the manifest doesn't contain an
  // exploitable bug that could be used to compromise the browser.
  scoped_ptr<DictionaryValue> final_manifest(
      static_cast<DictionaryValue*>(manifest.DeepCopy()));
  final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_);

  std::string manifest_json;
  JSONStringValueSerializer serializer(&manifest_json);
  serializer.set_pretty_print(true);
  if (!serializer.Serialize(*final_manifest)) {
    ReportFailure("Error serializing manifest.json.");
    return NULL;
  }

  FilePath manifest_path =
      extension_root_.Append(Extension::kManifestFilename);
  if (!file_util::WriteFile(manifest_path,
                            manifest_json.data(), manifest_json.size())) {
    ReportFailure("Error saving manifest.json.");
    return NULL;
  }

  return final_manifest.release();
}

bool SandboxedExtensionUnpacker::RewriteImageFiles() {
  ExtensionUnpacker::DecodedImages images;
  if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) {
    ReportFailure("Couldn't read image data from disk.");
    return false;
  }

  // Delete any images that may be used by the browser.  We're going to write
  // out our own versions of the parsed images, and we want to make sure the
  // originals are gone for good.
  std::set<FilePath> image_paths = extension_->GetBrowserImages();
  if (image_paths.size() != images.size()) {
    ReportFailure("Decoded images don't match what's in the manifest.");
    return false;
  }

  for (std::set<FilePath>::iterator it = image_paths.begin();
       it != image_paths.end(); ++it) {
    FilePath path = *it;
    if (path.IsAbsolute() || path.ReferencesParent()) {
      ReportFailure("Invalid path for browser image.");
      return false;
    }
    if (!file_util::Delete(extension_root_.Append(path), false)) {
      ReportFailure("Error removing old image file.");
      return false;
    }
  }

  // Write our parsed images back to disk as well.
  for (size_t i = 0; i < images.size(); ++i) {
    const SkBitmap& image = images[i].a;
    FilePath path_suffix = images[i].b;
    if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) {
      ReportFailure("Invalid path for bitmap image.");
      return false;
    }
    FilePath path = extension_root_.Append(path_suffix);

    std::vector<unsigned char> image_data;
    // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even
    // though they may originally be .jpg, etc.  Figure something out.
    // http://code.google.com/p/chromium/issues/detail?id=12459
    if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) {
      ReportFailure("Error re-encoding theme image.");
      return false;
    }

    // Note: we're overwriting existing files that the utility process wrote,
    // so we can be sure the directory exists.
    const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
    if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) {
      ReportFailure("Error saving theme image.");
      return false;
    }
  }

  return true;
}

bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
  DictionaryValue catalogs;
  if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(),
                                                      &catalogs)) {
    ReportFailure("Could not read catalog data from disk.");
    return false;
  }

  // Write our parsed catalogs back to disk.
  for (DictionaryValue::key_iterator key_it = catalogs.begin_keys();
       key_it != catalogs.end_keys(); ++key_it) {
    DictionaryValue* catalog;
    if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) {
      ReportFailure("Invalid catalog data.");
      return false;
    }

    // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())|
    // hack and remove the corresponding #include.
    FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it));
    relative_path = relative_path.Append(Extension::kMessagesFilename);
    if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) {
      ReportFailure("Invalid path for catalog.");
      return false;
    }
    FilePath path = extension_root_.Append(relative_path);

    std::string catalog_json;
    JSONStringValueSerializer serializer(&catalog_json);
    serializer.set_pretty_print(true);
    if (!serializer.Serialize(*catalog)) {
      ReportFailure("Error serializing catalog.");
      return false;
    }

    // Note: we're overwriting existing files that the utility process read,
    // so we can be sure the directory exists.
    if (!file_util::WriteFile(path,
                              catalog_json.c_str(),
                              catalog_json.size())) {
      ReportFailure("Error saving catalog.");
      return false;
    }
  }

  return true;
}
<commit_msg>Added check when unpacking extensions for a null key.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"

#include <set>

#include "base/base64.h"
#include "base/crypto/signature_verifier.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/scoped_handle.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"  // TODO(viettrungluu): delete me.
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension_unpacker.h"
#include "chrome/common/json_value_serializer.h"
#include "gfx/codec/png_codec.h"
#include "third_party/skia/include/core/SkBitmap.h"

const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24";

SandboxedExtensionUnpacker::SandboxedExtensionUnpacker(
    const FilePath& crx_path,
    const FilePath& temp_path,
    ResourceDispatcherHost* rdh,
    SandboxedExtensionUnpackerClient* client)
    : crx_path_(crx_path), temp_path_(temp_path),
      thread_identifier_(ChromeThread::ID_COUNT),
      rdh_(rdh), client_(client), got_response_(false) {
}

void SandboxedExtensionUnpacker::Start() {
  // We assume that we are started on the thread that the client wants us to do
  // file IO on.
  CHECK(ChromeThread::GetCurrentThreadIdentifier(&thread_identifier_));

  // Create a temporary directory to work in.
  if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) {
    ReportFailure("Could not create temporary directory.");
    return;
  }

  // Initialize the path that will eventually contain the unpacked extension.
  extension_root_ = temp_dir_.path().AppendASCII(
      extension_filenames::kTempExtensionName);

  // Extract the public key and validate the package.
  if (!ValidateSignature())
    return;  // ValidateSignature() already reported the error.

  // Copy the crx file into our working directory.
  FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName());
  if (!file_util::CopyFile(crx_path_, temp_crx_path)) {
    ReportFailure("Failed to copy extension file to temporary directory.");
    return;
  }

  // If we are supposed to use a subprocess, kick off the subprocess.
  //
  // TODO(asargent) we shouldn't need to do this branch here - instead
  // UtilityProcessHost should handle it for us. (http://crbug.com/19192)
  bool use_utility_process = rdh_ &&
      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
  if (use_utility_process) {
    // The utility process will have access to the directory passed to
    // SandboxedExtensionUnpacker.  That directory should not contain a
    // symlink or NTFS reparse point.  When the path is used, following
    // the link/reparse point will cause file system access outside the
    // sandbox path, and the sandbox will deny the operation.
    FilePath link_free_crx_path;
    if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) {
      LOG(ERROR) << "Could not get the normalized path of "
                 << temp_crx_path.value();
#if defined (OS_WIN)
      // On windows, it is possible to mount a disk without the root of that
      // disk having a drive letter.  The sandbox does not support this.
      // See crbug/49530 .
      ReportFailure(
          "Can not unpack extension.  To safely unpack an extension, "
          "there must be a path to your profile directory that starts "
          "with a drive letter and does not contain a junction, mount "
          "point, or symlink.  No such path exists for your profile.");
#else
      ReportFailure(
          "Can not unpack extension.  To safely unpack an extension, "
          "there must be a path to your profile directory that does "
          "not contain a symlink.  No such path exists for your profile.");
#endif
      return;
    }

    ChromeThread::PostTask(
        ChromeThread::IO, FROM_HERE,
        NewRunnableMethod(
            this,
            &SandboxedExtensionUnpacker::StartProcessOnIOThread,
            link_free_crx_path));
  } else {
    // Otherwise, unpack the extension in this process.
    ExtensionUnpacker unpacker(temp_crx_path);
    if (unpacker.Run() && unpacker.DumpImagesToFile() &&
        unpacker.DumpMessageCatalogsToFile()) {
      OnUnpackExtensionSucceeded(*unpacker.parsed_manifest());
    } else {
      OnUnpackExtensionFailed(unpacker.error_message());
    }
  }
}

void SandboxedExtensionUnpacker::StartProcessOnIOThread(
    const FilePath& temp_crx_path) {
  UtilityProcessHost* host = new UtilityProcessHost(
      rdh_, this, thread_identifier_);
  host->StartExtensionUnpacker(temp_crx_path);
}

void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded(
    const DictionaryValue& manifest) {
  // Skip check for unittests.
  if (thread_identifier_ != ChromeThread::ID_COUNT)
    DCHECK(ChromeThread::CurrentlyOn(thread_identifier_));
  got_response_ = true;

  scoped_ptr<DictionaryValue> final_manifest(RewriteManifestFile(manifest));
  if (!final_manifest.get())
    return;

  // Create an extension object that refers to the temporary location the
  // extension was unpacked to. We use this until the extension is finally
  // installed. For example, the install UI shows images from inside the
  // extension.
  extension_.reset(new Extension(extension_root_));

  // Localize manifest now, so confirm UI gets correct extension name.
  std::string error;
  if (!extension_l10n_util::LocalizeExtension(extension_.get(),
                                              final_manifest.get(),
                                              &error)) {
    ReportFailure(error);
    return;
  }

  if (!extension_->InitFromValue(*final_manifest, true, &error)) {
    ReportFailure(std::string("Manifest is invalid: ") + error);
    return;
  }

  if (!RewriteImageFiles())
    return;

  if (!RewriteCatalogFiles())
    return;

  ReportSuccess();
}

void SandboxedExtensionUnpacker::OnUnpackExtensionFailed(
    const std::string& error) {
  DCHECK(ChromeThread::CurrentlyOn(thread_identifier_));
  got_response_ = true;
  ReportFailure(error);
}

void SandboxedExtensionUnpacker::OnProcessCrashed() {
  // Don't report crashes if they happen after we got a response.
  if (got_response_)
    return;

  ReportFailure("Utility process crashed while trying to install.");
}

bool SandboxedExtensionUnpacker::ValidateSignature() {
  ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb"));
  if (!file.get()) {
    ReportFailure("Could not open crx file for reading");
    return false;
  }

  // Read and verify the header.
  ExtensionHeader header;
  size_t len;

  // TODO(erikkay): Yuck.  I'm not a big fan of this kind of code, but it
  // appears that we don't have any endian/alignment aware serialization
  // code in the code base.  So for now, this assumes that we're running
  // on a little endian machine with 4 byte alignment.
  len = fread(&header, 1, sizeof(ExtensionHeader),
      file.get());
  if (len < sizeof(ExtensionHeader)) {
    ReportFailure("Invalid crx header");
    return false;
  }
  if (strncmp(kExtensionHeaderMagic, header.magic,
      sizeof(header.magic))) {
    ReportFailure("Bad magic number");
    return false;
  }
  if (header.version != kCurrentVersion) {
    ReportFailure("Bad version number");
    return false;
  }
  if (header.key_size > kMaxPublicKeySize ||
      header.signature_size > kMaxSignatureSize) {
    ReportFailure("Excessively large key or signature");
    return false;
  }
  if (header.key_size == 0) {
    ReportFailure("Key length is zero");
    return false;
  }

  std::vector<uint8> key;
  key.resize(header.key_size);
  len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
  if (len < header.key_size) {
    ReportFailure("Invalid public key");
    return false;
  }

  std::vector<uint8> signature;
  signature.resize(header.signature_size);
  len = fread(&signature.front(), sizeof(uint8), header.signature_size,
      file.get());
  if (len < header.signature_size) {
    ReportFailure("Invalid signature");
    return false;
  }

  base::SignatureVerifier verifier;
  if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
                           sizeof(extension_misc::kSignatureAlgorithm),
                           &signature.front(),
                           signature.size(),
                           &key.front(),
                           key.size())) {
    ReportFailure("Signature verification initialization failed. "
                  "This is most likely caused by a public key in "
                  "the wrong format (should encode algorithm).");
    return false;
  }

  unsigned char buf[1 << 12];
  while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
    verifier.VerifyUpdate(buf, len);

  if (!verifier.VerifyFinal()) {
    ReportFailure("Signature verification failed");
    return false;
  }

  base::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()),
      key.size()), &public_key_);
  return true;
}

void SandboxedExtensionUnpacker::ReportFailure(const std::string& error) {
  client_->OnUnpackFailure(error);
}

void SandboxedExtensionUnpacker::ReportSuccess() {
  // Client takes ownership of temporary directory and extension.
  client_->OnUnpackSuccess(temp_dir_.Take(), extension_root_,
                           extension_.release());
}

DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile(
    const DictionaryValue& manifest) {
  // Add the public key extracted earlier to the parsed manifest and overwrite
  // the original manifest. We do this to ensure the manifest doesn't contain an
  // exploitable bug that could be used to compromise the browser.
  scoped_ptr<DictionaryValue> final_manifest(
      static_cast<DictionaryValue*>(manifest.DeepCopy()));
  final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_);

  std::string manifest_json;
  JSONStringValueSerializer serializer(&manifest_json);
  serializer.set_pretty_print(true);
  if (!serializer.Serialize(*final_manifest)) {
    ReportFailure("Error serializing manifest.json.");
    return NULL;
  }

  FilePath manifest_path =
      extension_root_.Append(Extension::kManifestFilename);
  if (!file_util::WriteFile(manifest_path,
                            manifest_json.data(), manifest_json.size())) {
    ReportFailure("Error saving manifest.json.");
    return NULL;
  }

  return final_manifest.release();
}

bool SandboxedExtensionUnpacker::RewriteImageFiles() {
  ExtensionUnpacker::DecodedImages images;
  if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) {
    ReportFailure("Couldn't read image data from disk.");
    return false;
  }

  // Delete any images that may be used by the browser.  We're going to write
  // out our own versions of the parsed images, and we want to make sure the
  // originals are gone for good.
  std::set<FilePath> image_paths = extension_->GetBrowserImages();
  if (image_paths.size() != images.size()) {
    ReportFailure("Decoded images don't match what's in the manifest.");
    return false;
  }

  for (std::set<FilePath>::iterator it = image_paths.begin();
       it != image_paths.end(); ++it) {
    FilePath path = *it;
    if (path.IsAbsolute() || path.ReferencesParent()) {
      ReportFailure("Invalid path for browser image.");
      return false;
    }
    if (!file_util::Delete(extension_root_.Append(path), false)) {
      ReportFailure("Error removing old image file.");
      return false;
    }
  }

  // Write our parsed images back to disk as well.
  for (size_t i = 0; i < images.size(); ++i) {
    const SkBitmap& image = images[i].a;
    FilePath path_suffix = images[i].b;
    if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) {
      ReportFailure("Invalid path for bitmap image.");
      return false;
    }
    FilePath path = extension_root_.Append(path_suffix);

    std::vector<unsigned char> image_data;
    // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even
    // though they may originally be .jpg, etc.  Figure something out.
    // http://code.google.com/p/chromium/issues/detail?id=12459
    if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) {
      ReportFailure("Error re-encoding theme image.");
      return false;
    }

    // Note: we're overwriting existing files that the utility process wrote,
    // so we can be sure the directory exists.
    const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
    if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) {
      ReportFailure("Error saving theme image.");
      return false;
    }
  }

  return true;
}

bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
  DictionaryValue catalogs;
  if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(),
                                                      &catalogs)) {
    ReportFailure("Could not read catalog data from disk.");
    return false;
  }

  // Write our parsed catalogs back to disk.
  for (DictionaryValue::key_iterator key_it = catalogs.begin_keys();
       key_it != catalogs.end_keys(); ++key_it) {
    DictionaryValue* catalog;
    if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) {
      ReportFailure("Invalid catalog data.");
      return false;
    }

    // TODO(viettrungluu): Fix the |FilePath::FromWStringHack(UTF8ToWide())|
    // hack and remove the corresponding #include.
    FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it));
    relative_path = relative_path.Append(Extension::kMessagesFilename);
    if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) {
      ReportFailure("Invalid path for catalog.");
      return false;
    }
    FilePath path = extension_root_.Append(relative_path);

    std::string catalog_json;
    JSONStringValueSerializer serializer(&catalog_json);
    serializer.set_pretty_print(true);
    if (!serializer.Serialize(*catalog)) {
      ReportFailure("Error serializing catalog.");
      return false;
    }

    // Note: we're overwriting existing files that the utility process read,
    // so we can be sure the directory exists.
    if (!file_util::WriteFile(path,
                              catalog_json.c_str(),
                              catalog_json.size())) {
      ReportFailure("Error saving catalog.");
      return false;
    }
  }

  return true;
}
<|endoftext|>


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

#include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"

#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
#include "views/controls/button/image_button.h"
#include "views/controls/textfield/textfield.h"
#include "views/focus/focus_manager.h"

namespace {

const int kKeyboardHeight = 300;
const int kKeyboardSlideDuration = 500;  // In milliseconds

PropertyAccessor<bool>* GetFocusedStateAccessor() {
  static PropertyAccessor<bool> state;
  return &state;
}

bool TabContentsHasFocus(const TabContents* contents) {
  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
  return view->Contains(view->GetFocusManager()->GetFocusedView());
}

}  // namespace

// static
const char TouchBrowserFrameView::kViewClassName[] =
    "browser/ui/touch/frame/TouchBrowserFrameView";

///////////////////////////////////////////////////////////////////////////////
// TouchBrowserFrameView, public:

TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame,
                                             BrowserView* browser_view)
    : OpaqueBrowserFrameView(frame, browser_view),
      keyboard_showing_(false),
      focus_listener_added_(false),
      keyboard_(NULL) {
  registrar_.Add(this,
                 NotificationType::NAV_ENTRY_COMMITTED,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 NotificationType::FOCUS_CHANGED_IN_PAGE,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 NotificationType::TAB_CONTENTS_DESTROYED,
                 NotificationService::AllSources());

  browser_view->browser()->tabstrip_model()->AddObserver(this);

  animation_.reset(new ui::SlideAnimation(this));
  animation_->SetTweenType(ui::Tween::LINEAR);
  animation_->SetSlideDuration(kKeyboardSlideDuration);
}

TouchBrowserFrameView::~TouchBrowserFrameView() {
  browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
}

std::string TouchBrowserFrameView::GetClassName() const {
  return kViewClassName;
}

void TouchBrowserFrameView::Layout() {
  OpaqueBrowserFrameView::Layout();

  if (!keyboard_)
    return;

  keyboard_->SetVisible(keyboard_showing_ || animation_->is_animating());
  gfx::Rect bounds = GetBoundsForReservedArea();
  if (animation_->is_animating() && !keyboard_showing_) {
    // The keyboard is in the process of hiding. So pretend it still has the
    // same bounds as when the keyboard is visible. But
    // |GetBoundsForReservedArea| should not take this into account so that the
    // render view gets the entire area to relayout itself.
    bounds.set_y(bounds.y() - kKeyboardHeight);
    bounds.set_height(kKeyboardHeight);
  }
  keyboard_->SetBoundsRect(bounds);
}

void TouchBrowserFrameView::FocusWillChange(views::View* focused_before,
                                            views::View* focused_now) {
  VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
  VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
  if (before != now) {
    // TODO(varunjain): support other types of keyboard.
    UpdateKeyboardAndLayout(now == GENERIC);
  }
}

///////////////////////////////////////////////////////////////////////////////
// TouchBrowserFrameView, protected:
int TouchBrowserFrameView::GetReservedHeight() const {
  return keyboard_showing_ ? kKeyboardHeight : 0;
}

void TouchBrowserFrameView::ViewHierarchyChanged(bool is_add,
                                                 View* parent,
                                                 View* child) {
  OpaqueBrowserFrameView::ViewHierarchyChanged(is_add, parent, child);
  if (!GetFocusManager())
    return;

  if (is_add && !focus_listener_added_) {
    // Add focus listener when this view is added to the hierarchy.
    GetFocusManager()->AddFocusChangeListener(this);
    focus_listener_added_ = true;
  } else if (!is_add && focus_listener_added_) {
    // Remove focus listener when this view is removed from the hierarchy.
    GetFocusManager()->RemoveFocusChangeListener(this);
    focus_listener_added_ = false;
  }
}

///////////////////////////////////////////////////////////////////////////////
// TouchBrowserFrameView, private:

void TouchBrowserFrameView::InitVirtualKeyboard() {
  if (keyboard_)
    return;

  Profile* keyboard_profile = browser_view()->browser()->profile();
  DCHECK(keyboard_profile) << "Profile required for virtual keyboard.";

  keyboard_ = new KeyboardContainerView(keyboard_profile,
      browser_view()->browser());
  keyboard_->SetVisible(false);
  AddChildView(keyboard_);
}

void TouchBrowserFrameView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
  if (should_show_keyboard)
    InitVirtualKeyboard();

  if (should_show_keyboard == keyboard_showing_)
    return;

  DCHECK(keyboard_);

  keyboard_showing_ = should_show_keyboard;
  if (keyboard_showing_) {
    animation_->Show();

    // We don't re-layout the client view until the animation ends (see
    // AnimationEnded below) because we want the client view to occupy the
    // entire height during the animation.
    Layout();
  } else {
    animation_->Hide();

    browser_view()->set_clip_y(ui::Tween::ValueBetween(
          animation_->GetCurrentValue(), 0, kKeyboardHeight));
    parent()->Layout();
  }
}

TouchBrowserFrameView::VirtualKeyboardType
    TouchBrowserFrameView::DecideKeyboardStateForView(views::View* view) {
  if (!view)
    return NONE;

  std::string cname = view->GetClassName();
  if (cname == views::Textfield::kViewClassName) {
    return GENERIC;
  } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
    TabContents* contents = browser_view()->browser()->GetSelectedTabContents();
    bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
        contents->property_bag()) : NULL;
    if (editable && *editable)
      return GENERIC;
  }
  return NONE;
}

bool TouchBrowserFrameView::HitTest(const gfx::Point& point) const {
  if (OpaqueBrowserFrameView::HitTest(point))
    return true;

  if (close_button()->IsVisible() &&
      close_button()->GetMirroredBounds().Contains(point))
    return true;
  if (restore_button()->IsVisible() &&
      restore_button()->GetMirroredBounds().Contains(point))
    return true;
  if (maximize_button()->IsVisible() &&
      maximize_button()->GetMirroredBounds().Contains(point))
    return true;
  if (minimize_button()->IsVisible() &&
      minimize_button()->GetMirroredBounds().Contains(point))
    return true;

  return false;
}

void TouchBrowserFrameView::TabSelectedAt(TabContentsWrapper* old_contents,
                                          TabContentsWrapper* new_contents,
                                          int index,
                                          bool user_gesture) {
  if (new_contents == old_contents)
    return;

  TabContents* contents = new_contents->tab_contents();
  if (!TabContentsHasFocus(contents))
    return;

  bool* editable = GetFocusedStateAccessor()->GetProperty(
      contents->property_bag());
  UpdateKeyboardAndLayout(editable ? *editable : false);
}

void TouchBrowserFrameView::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
  Browser* browser = browser_view()->browser();
  if (type == NotificationType::FOCUS_CHANGED_IN_PAGE) {
    // Only modify the keyboard state if the currently active tab sent the
    // notification.
    const TabContents* current_tab = browser->GetSelectedTabContents();
    TabContents* source_tab = Source<TabContents>(source).ptr();
    const bool editable = *Details<const bool>(details).ptr();

    if (current_tab == source_tab && TabContentsHasFocus(source_tab))
      UpdateKeyboardAndLayout(editable);

    // Save the state of the focused field so that the keyboard visibility
    // can be determined after tab switching.
    GetFocusedStateAccessor()->SetProperty(
        source_tab->property_bag(), editable);
  } else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
    NavigationController* controller =
        Source<NavigationController>(source).ptr();
    Browser* source_browser = Browser::GetBrowserForController(
        controller, NULL);

    // If the Browser for the keyboard has navigated, re-evaluate the visibility
    // of the keyboard.
    TouchBrowserFrameView::VirtualKeyboardType keyboard_type = NONE;
    views::View* view = GetFocusManager()->GetFocusedView();
    if (view) {
      if (view->GetClassName() == views::Textfield::kViewClassName)
        keyboard_type = GENERIC;
      if (view->GetClassName() == RenderWidgetHostViewViews::kViewClassName) {
        // Reset the state of the focused field in the current tab.
        GetFocusedStateAccessor()->SetProperty(
            controller->tab_contents()->property_bag(), false);
      }
    }
    if (source_browser == browser)
      UpdateKeyboardAndLayout(keyboard_type == GENERIC);
  } else if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
    GetFocusedStateAccessor()->DeleteProperty(
        Source<TabContents>(source).ptr()->property_bag());
  } else if (type == NotificationType::PREF_CHANGED) {
    OpaqueBrowserFrameView::Observe(type, source, details);
  }
}

///////////////////////////////////////////////////////////////////////////////
// ui::AnimationDelegate implementation
void TouchBrowserFrameView::AnimationProgressed(const ui::Animation* anim) {
  ui::Transform transform;
  transform.SetTranslateY(
      ui::Tween::ValueBetween(anim->GetCurrentValue(), kKeyboardHeight, 0));
  keyboard_->SetTransform(transform);
  browser_view()->set_clip_y(
      ui::Tween::ValueBetween(anim->GetCurrentValue(), 0, kKeyboardHeight));
  SchedulePaint();
}

void TouchBrowserFrameView::AnimationEnded(const ui::Animation* animation) {
  browser_view()->set_clip_y(0);
  if (keyboard_showing_) {
    // Because the NonClientFrameView is a sibling of the ClientView, we rely on
    // the parent to resize the ClientView instead of resizing it directly.
    parent()->Layout();

    // The keyboard that pops up may end up hiding the text entry. So make sure
    // the renderer scrolls when necessary to keep the textfield visible.
    RenderViewHost* host =
        browser_view()->browser()->GetSelectedTabContents()->render_view_host();
    host->Send(new ViewMsg_ScrollFocusedEditableNodeIntoView(
        host->routing_id()));
  }
  SchedulePaint();
}
<commit_msg>Add a missing head to fix touch compile.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"

#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"
#include "content/common/view_messages.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
#include "views/controls/button/image_button.h"
#include "views/controls/textfield/textfield.h"
#include "views/focus/focus_manager.h"

namespace {

const int kKeyboardHeight = 300;
const int kKeyboardSlideDuration = 500;  // In milliseconds

PropertyAccessor<bool>* GetFocusedStateAccessor() {
  static PropertyAccessor<bool> state;
  return &state;
}

bool TabContentsHasFocus(const TabContents* contents) {
  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
  return view->Contains(view->GetFocusManager()->GetFocusedView());
}

}  // namespace

// static
const char TouchBrowserFrameView::kViewClassName[] =
    "browser/ui/touch/frame/TouchBrowserFrameView";

///////////////////////////////////////////////////////////////////////////////
// TouchBrowserFrameView, public:

TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame,
                                             BrowserView* browser_view)
    : OpaqueBrowserFrameView(frame, browser_view),
      keyboard_showing_(false),
      focus_listener_added_(false),
      keyboard_(NULL) {
  registrar_.Add(this,
                 NotificationType::NAV_ENTRY_COMMITTED,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 NotificationType::FOCUS_CHANGED_IN_PAGE,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 NotificationType::TAB_CONTENTS_DESTROYED,
                 NotificationService::AllSources());

  browser_view->browser()->tabstrip_model()->AddObserver(this);

  animation_.reset(new ui::SlideAnimation(this));
  animation_->SetTweenType(ui::Tween::LINEAR);
  animation_->SetSlideDuration(kKeyboardSlideDuration);
}

TouchBrowserFrameView::~TouchBrowserFrameView() {
  browser_view()->browser()->tabstrip_model()->RemoveObserver(this);
}

std::string TouchBrowserFrameView::GetClassName() const {
  return kViewClassName;
}

void TouchBrowserFrameView::Layout() {
  OpaqueBrowserFrameView::Layout();

  if (!keyboard_)
    return;

  keyboard_->SetVisible(keyboard_showing_ || animation_->is_animating());
  gfx::Rect bounds = GetBoundsForReservedArea();
  if (animation_->is_animating() && !keyboard_showing_) {
    // The keyboard is in the process of hiding. So pretend it still has the
    // same bounds as when the keyboard is visible. But
    // |GetBoundsForReservedArea| should not take this into account so that the
    // render view gets the entire area to relayout itself.
    bounds.set_y(bounds.y() - kKeyboardHeight);
    bounds.set_height(kKeyboardHeight);
  }
  keyboard_->SetBoundsRect(bounds);
}

void TouchBrowserFrameView::FocusWillChange(views::View* focused_before,
                                            views::View* focused_now) {
  VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
  VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
  if (before != now) {
    // TODO(varunjain): support other types of keyboard.
    UpdateKeyboardAndLayout(now == GENERIC);
  }
}

///////////////////////////////////////////////////////////////////////////////
// TouchBrowserFrameView, protected:
int TouchBrowserFrameView::GetReservedHeight() const {
  return keyboard_showing_ ? kKeyboardHeight : 0;
}

void TouchBrowserFrameView::ViewHierarchyChanged(bool is_add,
                                                 View* parent,
                                                 View* child) {
  OpaqueBrowserFrameView::ViewHierarchyChanged(is_add, parent, child);
  if (!GetFocusManager())
    return;

  if (is_add && !focus_listener_added_) {
    // Add focus listener when this view is added to the hierarchy.
    GetFocusManager()->AddFocusChangeListener(this);
    focus_listener_added_ = true;
  } else if (!is_add && focus_listener_added_) {
    // Remove focus listener when this view is removed from the hierarchy.
    GetFocusManager()->RemoveFocusChangeListener(this);
    focus_listener_added_ = false;
  }
}

///////////////////////////////////////////////////////////////////////////////
// TouchBrowserFrameView, private:

void TouchBrowserFrameView::InitVirtualKeyboard() {
  if (keyboard_)
    return;

  Profile* keyboard_profile = browser_view()->browser()->profile();
  DCHECK(keyboard_profile) << "Profile required for virtual keyboard.";

  keyboard_ = new KeyboardContainerView(keyboard_profile,
      browser_view()->browser());
  keyboard_->SetVisible(false);
  AddChildView(keyboard_);
}

void TouchBrowserFrameView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
  if (should_show_keyboard)
    InitVirtualKeyboard();

  if (should_show_keyboard == keyboard_showing_)
    return;

  DCHECK(keyboard_);

  keyboard_showing_ = should_show_keyboard;
  if (keyboard_showing_) {
    animation_->Show();

    // We don't re-layout the client view until the animation ends (see
    // AnimationEnded below) because we want the client view to occupy the
    // entire height during the animation.
    Layout();
  } else {
    animation_->Hide();

    browser_view()->set_clip_y(ui::Tween::ValueBetween(
          animation_->GetCurrentValue(), 0, kKeyboardHeight));
    parent()->Layout();
  }
}

TouchBrowserFrameView::VirtualKeyboardType
    TouchBrowserFrameView::DecideKeyboardStateForView(views::View* view) {
  if (!view)
    return NONE;

  std::string cname = view->GetClassName();
  if (cname == views::Textfield::kViewClassName) {
    return GENERIC;
  } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
    TabContents* contents = browser_view()->browser()->GetSelectedTabContents();
    bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
        contents->property_bag()) : NULL;
    if (editable && *editable)
      return GENERIC;
  }
  return NONE;
}

bool TouchBrowserFrameView::HitTest(const gfx::Point& point) const {
  if (OpaqueBrowserFrameView::HitTest(point))
    return true;

  if (close_button()->IsVisible() &&
      close_button()->GetMirroredBounds().Contains(point))
    return true;
  if (restore_button()->IsVisible() &&
      restore_button()->GetMirroredBounds().Contains(point))
    return true;
  if (maximize_button()->IsVisible() &&
      maximize_button()->GetMirroredBounds().Contains(point))
    return true;
  if (minimize_button()->IsVisible() &&
      minimize_button()->GetMirroredBounds().Contains(point))
    return true;

  return false;
}

void TouchBrowserFrameView::TabSelectedAt(TabContentsWrapper* old_contents,
                                          TabContentsWrapper* new_contents,
                                          int index,
                                          bool user_gesture) {
  if (new_contents == old_contents)
    return;

  TabContents* contents = new_contents->tab_contents();
  if (!TabContentsHasFocus(contents))
    return;

  bool* editable = GetFocusedStateAccessor()->GetProperty(
      contents->property_bag());
  UpdateKeyboardAndLayout(editable ? *editable : false);
}

void TouchBrowserFrameView::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
  Browser* browser = browser_view()->browser();
  if (type == NotificationType::FOCUS_CHANGED_IN_PAGE) {
    // Only modify the keyboard state if the currently active tab sent the
    // notification.
    const TabContents* current_tab = browser->GetSelectedTabContents();
    TabContents* source_tab = Source<TabContents>(source).ptr();
    const bool editable = *Details<const bool>(details).ptr();

    if (current_tab == source_tab && TabContentsHasFocus(source_tab))
      UpdateKeyboardAndLayout(editable);

    // Save the state of the focused field so that the keyboard visibility
    // can be determined after tab switching.
    GetFocusedStateAccessor()->SetProperty(
        source_tab->property_bag(), editable);
  } else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
    NavigationController* controller =
        Source<NavigationController>(source).ptr();
    Browser* source_browser = Browser::GetBrowserForController(
        controller, NULL);

    // If the Browser for the keyboard has navigated, re-evaluate the visibility
    // of the keyboard.
    TouchBrowserFrameView::VirtualKeyboardType keyboard_type = NONE;
    views::View* view = GetFocusManager()->GetFocusedView();
    if (view) {
      if (view->GetClassName() == views::Textfield::kViewClassName)
        keyboard_type = GENERIC;
      if (view->GetClassName() == RenderWidgetHostViewViews::kViewClassName) {
        // Reset the state of the focused field in the current tab.
        GetFocusedStateAccessor()->SetProperty(
            controller->tab_contents()->property_bag(), false);
      }
    }
    if (source_browser == browser)
      UpdateKeyboardAndLayout(keyboard_type == GENERIC);
  } else if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
    GetFocusedStateAccessor()->DeleteProperty(
        Source<TabContents>(source).ptr()->property_bag());
  } else if (type == NotificationType::PREF_CHANGED) {
    OpaqueBrowserFrameView::Observe(type, source, details);
  }
}

///////////////////////////////////////////////////////////////////////////////
// ui::AnimationDelegate implementation
void TouchBrowserFrameView::AnimationProgressed(const ui::Animation* anim) {
  ui::Transform transform;
  transform.SetTranslateY(
      ui::Tween::ValueBetween(anim->GetCurrentValue(), kKeyboardHeight, 0));
  keyboard_->SetTransform(transform);
  browser_view()->set_clip_y(
      ui::Tween::ValueBetween(anim->GetCurrentValue(), 0, kKeyboardHeight));
  SchedulePaint();
}

void TouchBrowserFrameView::AnimationEnded(const ui::Animation* animation) {
  browser_view()->set_clip_y(0);
  if (keyboard_showing_) {
    // Because the NonClientFrameView is a sibling of the ClientView, we rely on
    // the parent to resize the ClientView instead of resizing it directly.
    parent()->Layout();

    // The keyboard that pops up may end up hiding the text entry. So make sure
    // the renderer scrolls when necessary to keep the textfield visible.
    RenderViewHost* host =
        browser_view()->browser()->GetSelectedTabContents()->render_view_host();
    host->Send(new ViewMsg_ScrollFocusedEditableNodeIntoView(
        host->routing_id()));
  }
  SchedulePaint();
}
<|endoftext|>


<commit_before>/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 11/25/2018, 12:58:28 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N, M, K;
int P[310];
int root = 0;
vector<int> children[310];
int cnt_c[310];
int cnt_sum[310];
int S[310];
vector<int> T[310];
bool used[310];
bool ok = true;
vector<int> ans;
int mini = 0;

int calc_S(int v)
{
  if (S[v] != -1)
  {
    return S[v];
  }
  if (v == root)
  {
    return S[v] = 1;
  }
  return S[v] = calc_S(P[v]) + 1;
}

void flush()
{
  if (ok)
  {
    assert((int)ans.size() == M);
    for (auto i = 0; i < M; i++)
    {
      cout << ans[i] + 1;
      if (i < M - 1)
      {
        cout << " ";
      }
    }
  }
  else
  {
    cout << -1 << endl;
  }
}

int calc_c(int v)
{
  cnt_c[v] = 0;
  for (auto x : children[v])
  {
    cnt_c[v] += calc_c(x);
  }
  return cnt_c[v] + 1;
}

int calc_sum(int v)
{
  cnt_sum[v] = 0;
  for (auto x : children[v])
  {
    cnt_sum[v] += calc_sum(x);
  }
  return cnt_sum[v];
}

int calc_mini(int remain)
{
  mini = 0;
  for (auto i = 0; i < 310; i++)
  {
    if (remain <= 0)
    {
      break;
    }
    int x = min((int)T[i].size(), remain);
    mini += i * x;
    remain -= x;
  }
  return mini;
}

void init()
{
  fill(S, S + N, -1);
  for (auto i = 0; i < 310; i++)
  {
    T[i].clear();
  }
  for (auto i = 0; i < N; i++)
  {
    T[calc_S(i)].push_back(i);
  }
  calc_c(root);
  calc_sum(root);
  calc_mini(M - (int)ans.size());
}

void make_used(int v)
{
  used[v] = true;
  for (auto x : children[v])
  {
    make_used(x);
  }
}

bool erasable(int v)
{
  int cost = S[v];
  if (P[v] == -1)
  {
    if (K == 1 && (int)ans.size() == M - 1)
    {
      ans.push_back(v);
      return true;
    }
    return false;
  }
  ans.push_back(v);
  auto it = children[P[v]].begin();
  while (it != children[P[v]].end())
  {
    if (*it == v)
    {
      children[P[v]].erase(it);
      break;
    }
  }
  init();
  if ((int)ans.size() == M - 1)
  {
    if (cost == K)
    {
      return true;
    }
  }
  else if (cnt_c[root] >= M - (int)ans.size() - 1 && mini <= K - cost && K - cost <= cnt_sum[root])
  {
    K -= cost;
    make_used(v);
    return true;
  }
  children[P[v]].push_back(v);
  it = ans.end();
  it--;
  ans.erase(it);
  return false;
}

int main()
{
  cin >> N >> M >> K;
  for (auto i = 0; i < N; i++)
  {
    cin >> P[i];
    P[i]--;
  }
  for (auto i = 0; i < N; i++)
  {
    if (P[i] == -1)
    {
      root = i;
    }
    else
    {
      children[P[i]].push_back(i);
    }
  }
  init();
  fill(used, used + N, false);
  for (auto i = 0; i < M; i++)
  {
    bool valid = false;
    for (auto j = 0; j < N; j++)
    {
      if (used[j])
      {
        continue;
      }
      if (erasable(j))
      {
        cerr << "erase: " << j << endl;
        valid = true;
        break;
      }
    }
    if (!valid)
    {
      ok = false;
      break;
    }
  }
  flush();
}<commit_msg>tried F.cpp to 'F'<commit_after>/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 11/25/2018, 12:58:28 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N, M, K;
int P[310];
int root = 0;
vector<int> children[310];
int cnt_c[310];
int cnt_sum[310];
int S[310];
vector<int> T[310];
bool used[310];
bool ok = true;
vector<int> ans;
int mini = 0;

int calc_S(int v)
{
  if (S[v] != -1)
  {
    return S[v];
  }
  if (v == root)
  {
    return S[v] = 1;
  }
  return S[v] = calc_S(P[v]) + 1;
}

void flush()
{
  if (ok)
  {
    assert((int)ans.size() == M);
    for (auto i = 0; i < M; i++)
    {
      cout << ans[i] + 1;
      if (i < M - 1)
      {
        cout << " ";
      }
    }
  }
  else
  {
    cout << -1 << endl;
  }
}

int calc_c(int v)
{
  cnt_c[v] = 0;
  for (auto x : children[v])
  {
    cnt_c[v] += calc_c(x);
  }
  return cnt_c[v] + 1;
}

int calc_sum(int v)
{
  cnt_sum[v] = 0;
  for (auto x : children[v])
  {
    cnt_sum[v] += calc_sum(x);
  }
  return cnt_sum[v];
}

int calc_mini(int remain)
{
  mini = 0;
  for (auto i = 0; i < 310; i++)
  {
    if (remain <= 0)
    {
      break;
    }
    int x = min((int)T[i].size(), remain);
    mini += i * x;
    remain -= x;
  }
  return mini;
}

void init()
{
  fill(S, S + N, -1);
  for (auto i = 0; i < 310; i++)
  {
    T[i].clear();
  }
  for (auto i = 0; i < N; i++)
  {
    T[calc_S(i)].push_back(i);
  }
  calc_c(root);
  calc_sum(root);
  calc_mini(M - (int)ans.size());
  cerr << "cnt_c[" << root << "] = " << cnt_c[root] << endl;
  cerr << "cnt_sum[" << root << "] = " << cnt_sum[root] << endl;
  cerr << "mini = " << mini << endl;
}

void make_used(int v)
{
  used[v] = true;
  for (auto x : children[v])
  {
    make_used(x);
  }
}

bool erasable(int v)
{
  int cost = S[v];
  if (P[v] == -1)
  {
    if (K == 1 && (int)ans.size() == M - 1)
    {
      ans.push_back(v);
      return true;
    }
    return false;
  }
  ans.push_back(v);
  auto it = children[P[v]].begin();
  while (it != children[P[v]].end())
  {
    if (*it == v)
    {
      children[P[v]].erase(it);
      break;
    }
  }
  init();
  if ((int)ans.size() == M - 1)
  {
    if (cost == K)
    {
      return true;
    }
  }
  else if (cnt_c[root] >= M - (int)ans.size() - 1 && mini <= K - cost && K - cost <= cnt_sum[root])
  {
    K -= cost;
    make_used(v);
    return true;
  }
  children[P[v]].push_back(v);
  it = ans.end();
  it--;
  ans.erase(it);
  return false;
}

int main()
{
  cin >> N >> M >> K;
  for (auto i = 0; i < N; i++)
  {
    cin >> P[i];
    P[i]--;
  }
  for (auto i = 0; i < N; i++)
  {
    if (P[i] == -1)
    {
      root = i;
    }
    else
    {
      children[P[i]].push_back(i);
    }
  }
  init();
  fill(used, used + N, false);
  for (auto i = 0; i < M; i++)
  {
    bool valid = false;
    for (auto j = 0; j < N; j++)
    {
      if (used[j])
      {
        continue;
      }
      if (erasable(j))
      {
        cerr << "erase: " << j << endl;
        valid = true;
        break;
      }
    }
    if (!valid)
    {
      ok = false;
      break;
    }
  }
  flush();
}<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkObjectToObjectMetric.h"

namespace itk
{

//-------------------------------------------------------------------
ObjectToObjectMetric
::ObjectToObjectMetric()
{
  // Don't call SetGradientSource, to avoid valgrind warning.
  this->m_GradientSource = this->GRADIENT_SOURCE_MOVING;
}

//-------------------------------------------------------------------
ObjectToObjectMetric
::~ObjectToObjectMetric()
{}

//-------------------------------------------------------------------
bool
ObjectToObjectMetric
::GetGradientSourceIncludesFixed() const
{
  return m_GradientSource == GRADIENT_SOURCE_FIXED ||
         m_GradientSource == GRADIENT_SOURCE_BOTH;
}

//-------------------------------------------------------------------
bool
ObjectToObjectMetric
::GetGradientSourceIncludesMoving() const
{
  return m_GradientSource == GRADIENT_SOURCE_MOVING ||
         m_GradientSource == GRADIENT_SOURCE_BOTH;
}

//-------------------------------------------------------------------
void
ObjectToObjectMetric
::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
  os << indent << "TODO...";
}

}//namespace itk
<commit_msg>ENH: Populate ObjectToObjectMetric PrintSelf ITK-2634<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkObjectToObjectMetric.h"

namespace itk
{

//-------------------------------------------------------------------
ObjectToObjectMetric
::ObjectToObjectMetric()
{
  // Don't call SetGradientSource, to avoid valgrind warning.
  this->m_GradientSource = this->GRADIENT_SOURCE_MOVING;
}

//-------------------------------------------------------------------
ObjectToObjectMetric
::~ObjectToObjectMetric()
{}

//-------------------------------------------------------------------
bool
ObjectToObjectMetric
::GetGradientSourceIncludesFixed() const
{
  return m_GradientSource == GRADIENT_SOURCE_FIXED ||
         m_GradientSource == GRADIENT_SOURCE_BOTH;
}

//-------------------------------------------------------------------
bool
ObjectToObjectMetric
::GetGradientSourceIncludesMoving() const
{
  return m_GradientSource == GRADIENT_SOURCE_MOVING ||
         m_GradientSource == GRADIENT_SOURCE_BOTH;
}

//-------------------------------------------------------------------
void
ObjectToObjectMetric
::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
  os << indent << "GradientSourceType: ";
  switch( m_GradientSource )
    {
  case GRADIENT_SOURCE_FIXED:
    os << "GRADIENT_SOURCE_FIXED";
    break;
  case GRADIENT_SOURCE_MOVING:
    os << "GRADIENT_SOURCE_MOVING";
    break;
  case GRADIENT_SOURCE_BOTH:
    os << "GRADIENT_SOURCE_BOTH";
    break;
  default:
    itkExceptionMacro(<< "Unknown GradientSource.");
    }
  os << std::endl;
}

}//namespace itk
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 <iostream>
#include "itkImageFilterToVideoFilterWrapper.h"
#include "itkImage.h"
#include "itkRecursiveGaussianImageFilter.h"
#include "itkVideoFileReader.h"
#include "itkVideoFileWriter.h"
#include "itkFileListVideoIOFactory.h"

/**
 * Main test
 */
int itkImageFilterToVideoFilterWrapperTest( int argc, char* argv[] )
{
  // Check parameters
  if (argc < 3)
    {
    std::cerr << "Usage: " << argv[0] << " input_video output_video" << std::endl;
    return EXIT_FAILURE;
    }

  // Typedefs
  typedef unsigned char PixelType;
  typedef itk::Image<PixelType, 2> FrameType;
  typedef itk::VideoStream< FrameType > VideoType;
  typedef itk::RecursiveGaussianImageFilter< FrameType, FrameType > GaussianImageFilterType;
  typedef itk::ImageFilterToVideoFilterWrapper< GaussianImageFilterType >
    GaussianVideoFilterType;
  typedef itk::VideoFileReader< VideoType > VideoReaderType;
  typedef itk::VideoFileWriter< VideoType > VideoWriterType;

  // Register FileListIO with the factory -- shouldn't have to do this. Needs fixing
  itk::ObjectFactoryBase::RegisterFactory( itk::FileListVideoIOFactory::New() );

  // Set up reader and writer
  VideoReaderType::Pointer reader = VideoReaderType::New();
  VideoWriterType::Pointer writer = VideoWriterType::New();
  reader->SetFileName(argv[1]);
  writer->SetFileName(argv[2]);

  // Instantiate a new video filter and an image filter
  GaussianImageFilterType::Pointer imgGauss = GaussianImageFilterType::New();
  GaussianVideoFilterType::Pointer vidGauss = GaussianVideoFilterType::New();

  // Set the parameters on the image filter and plug it into the video filter
  imgGauss->SetSigma(3);
  vidGauss->SetImageFilter(imgGauss);

  // String the pipeline together
  vidGauss->SetInput(reader->GetOutput());
  writer->SetInput(vidGauss->GetOutput());

  // Run the pipeline
  writer->Update();

  //////
  // Return successfully
  //////
  return EXIT_SUCCESS;
}
<commit_msg>ENH: Test output frames<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 <iostream>
#include "itkImageFilterToVideoFilterWrapper.h"
#include "itkImage.h"
#include "itkRecursiveGaussianImageFilter.h"
#include "itkVideoFileReader.h"
#include "itkVideoFileWriter.h"
#include "itkImageFileReader.h"
#include "itkFileListVideoIO.h"
#include "itkFileListVideoIOFactory.h"
#include "itkDifferenceImageFilter.h"

/**
 * Main test
 */
int itkImageFilterToVideoFilterWrapperTest( int argc, char* argv[] )
{
  // Check parameters
  if (argc < 3)
    {
    std::cerr << "Usage: " << argv[0] << " input_video output_video" << std::endl;
    return EXIT_FAILURE;
    }

  // Get the lists of input and output files
  std::vector<std::string> inputFiles = itk::FileListVideoIO::SplitFileNames(argv[1]);
  std::vector<std::string> outputFiles = itk::FileListVideoIO::SplitFileNames(argv[2]);
  if (inputFiles.size() != outputFiles.size())
    {
    std::cerr << "Must specify the same number of input and output frames" << std::endl;
    return EXIT_FAILURE;
    }

  // Typedefs
  typedef unsigned char PixelType;
  typedef itk::Image<PixelType, 2> FrameType;
  typedef itk::VideoStream< FrameType > VideoType;
  typedef itk::RecursiveGaussianImageFilter< FrameType, FrameType > GaussianImageFilterType;
  typedef itk::ImageFilterToVideoFilterWrapper< GaussianImageFilterType >
    GaussianVideoFilterType;
  typedef itk::VideoFileReader< VideoType > VideoReaderType;
  typedef itk::VideoFileWriter< VideoType > VideoWriterType;

  // Register FileListIO with the factory -- shouldn't have to do this. Needs fixing
  itk::ObjectFactoryBase::RegisterFactory( itk::FileListVideoIOFactory::New() );

  // Set up reader and writer
  VideoReaderType::Pointer reader = VideoReaderType::New();
  VideoWriterType::Pointer writer = VideoWriterType::New();
  reader->SetFileName(argv[1]);
  writer->SetFileName(argv[2]);

  // Instantiate a new video filter and an image filter
  GaussianImageFilterType::Pointer imgGauss = GaussianImageFilterType::New();
  GaussianVideoFilterType::Pointer vidGauss = GaussianVideoFilterType::New();

  // Set the parameters on the image filter and plug it into the video filter
  imgGauss->SetSigma(3);
  vidGauss->SetImageFilter(imgGauss);

  // String the pipeline together
  vidGauss->SetInput(reader->GetOutput());
  writer->SetInput(vidGauss->GetOutput());

  // Run the pipeline
  writer->Update();

  //
  // Check output
  //
  typedef itk::ImageFileReader< FrameType > ImageReaderType;
  typedef itk::DifferenceImageFilter< FrameType, FrameType > DifferenceFilterType;
  ImageReaderType::Pointer imReader1 = ImageReaderType::New();
  ImageReaderType::Pointer imReader2 = ImageReaderType::New();
  DifferenceFilterType::Pointer differ = DifferenceFilterType::New();

  imgGauss->SetInput(imReader1->GetOutput());
  differ->SetValidInput(imgGauss->GetOutput());
  differ->SetTestInput(imReader2->GetOutput());

  for (unsigned int i = 0; i < inputFiles.size(); ++i)
    {
    imReader1->SetFileName(inputFiles[i]);
    imReader2->SetFileName(outputFiles[i]);
    differ->Update();
    if (differ->GetTotalDifference() != 0)
      {
      std::cerr << "Frame " << i << " didn't produce the correct output. Difference = "
                << differ->GetTotalDifference() << std::endl;
      return EXIT_FAILURE;
      }
    }

  //////
  // Return successfully
  //////
  return EXIT_SUCCESS;
}
<|endoftext|>


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

BlueBerry Platform

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#ifndef NOMINMAX
#define NOMINMAX
#endif

#include "berryCTKPluginActivator.h"

#include <berryIApplication.h>
#include <berryIConfigurationElement.h>
#include <berryIContributor.h>

#include "berryApplicationContainer.h"
#include "berryPlatform.h"
#include "berryInternalPlatform.h"
#include "berryErrorApplication.h"
#include "berryPreferencesService.h"
#include "berryExtensionRegistry.h"
#include "berryRegistryConstants.h"
#include "berryRegistryProperties.h"
#include "berryRegistryStrategy.h"
#include "berryRegistryContributor.h"

#include <QCoreApplication>
#include <QDebug>

namespace berry {

static const QString XP_APPLICATIONS = "org.blueberry.osgi.applications";

ctkPluginContext* org_blueberry_core_runtime_Activator::context = nullptr;
QScopedPointer<ApplicationContainer> org_blueberry_core_runtime_Activator::appContainer;

const bool org_blueberry_core_runtime_Activator::DEBUG = false;

void org_blueberry_core_runtime_Activator::start(ctkPluginContext* context)
{
  this->context = context;

  BERRY_REGISTER_EXTENSION_CLASS(ErrorApplication, context)

  RegistryProperties::SetContext(context);
  //ProcessCommandLine();
  this->startRegistry();

  preferencesService.reset(new PreferencesService(context->getDataFile("").absolutePath()));
  prefServiceReg = context->registerService<IPreferencesService>(preferencesService.data());

//  // register a listener to catch new plugin installations/resolutions.
//  pluginListener.reset(new CTKPluginListener(m_ExtensionPointService));
//  context->connectPluginListener(pluginListener.data(), SLOT(pluginChanged(ctkPluginEvent)), Qt::DirectConnection);

//  // populate the registry with all the currently installed plugins.
//  // There is a small window here while processPlugins is being
//  // called where the pluginListener may receive a ctkPluginEvent
//  // to add/remove a plugin from the registry.  This is ok since
//  // the registry is a synchronized object and will not add the
//  // same bundle twice.
//  pluginListener->processPlugins(context->getPlugins());

  this->startAppContainer();

  InternalPlatform::GetInstance()->Start(context);

}

void org_blueberry_core_runtime_Activator::stop(ctkPluginContext* context)
{
  InternalPlatform::GetInstance()->Stop(context);

  //pluginListener.reset();

  //Platform::GetServiceRegistry().UnRegisterService(IExtensionPointService::SERVICE_ID);

  prefServiceReg.unregister();
  preferencesService->ShutDown();
  preferencesService.reset();
  prefServiceReg = 0;

  this->stopRegistry();
  RegistryProperties::SetContext(nullptr);

  stopAppContainer();

  this->context = nullptr;
}

ctkPluginContext* org_blueberry_core_runtime_Activator::getPluginContext()
{
  return context;
}

ApplicationContainer* org_blueberry_core_runtime_Activator::GetContainer()
{
  return appContainer.data();
}

#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_CC_MINGW)

#include <dlfcn.h>
QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol)
{
  if (symbol == nullptr) return QString();

  Dl_info info = {nullptr,nullptr,nullptr,nullptr};
  if(dladdr(symbol, &info) == 0)
  {
    return QString();
  }
  else if(info.dli_fname)
  {
    QFile soPath(info.dli_fname);
    int index = soPath.fileName().lastIndexOf('.');
    QString pluginId = soPath.fileName().left(index);
    if (pluginId.startsWith("lib"))
      pluginId = pluginId.mid(3);
    return pluginId.replace('_', '.');
  }
  return QString();
}

#elif defined(Q_CC_MSVC)

#include <ctkBackTrace.h>
#include <windows.h>
#include <dbghelp.h>
QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol)
{
  if (symbol == nullptr) return QString();

  if (ctk::DebugSymInitialize())
  {
    std::vector<char> moduleBuffer(sizeof(IMAGEHLP_MODULE64));
    PIMAGEHLP_MODULE64 pModuleInfo = (PIMAGEHLP_MODULE64)&moduleBuffer.front();
    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
    if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)symbol, pModuleInfo))
    {
      QString pluginId = pModuleInfo->ModuleName;
      return pluginId.replace('_', '.');
    }
  }
  return QString();
}

#endif

QSharedPointer<ctkPlugin> org_blueberry_core_runtime_Activator::GetPlugin(const SmartPointer<IContributor>& contributor)
{
  if (RegistryContributor::Pointer regContributor = contributor.Cast<RegistryContributor>())
  {
    bool okay = false;
    long id = regContributor->GetActualId().toLong(&okay);
    if (okay)
    {
      if (context != nullptr)
      {
        return context->getPlugin(id);
      }
    }
    else
    {
      // try using the name of the contributor below
    }
  }

  auto plugins = context->getPlugins();

  //Return the first plugin that is not installed or uninstalled
  for (auto plugin : plugins)
  {
    if (!(plugin->getState() == ctkPlugin::INSTALLED ||
          plugin->getState() == ctkPlugin::UNINSTALLED))
    {
      return plugin;
    }
  }
  return QSharedPointer<ctkPlugin>();
}

org_blueberry_core_runtime_Activator::org_blueberry_core_runtime_Activator()
  : userRegistryKey(new QObject())
  , masterRegistryKey(new QObject())
{
}

org_blueberry_core_runtime_Activator::~org_blueberry_core_runtime_Activator()
{
}

void org_blueberry_core_runtime_Activator::startRegistry()
{
  // see if the customer suppressed the creation of default registry
  QString property = context->getProperty(RegistryConstants::PROP_DEFAULT_REGISTRY).toString();
  if (property.compare("false", Qt::CaseInsensitive) == 0) return;

  // check to see if we need to use null as a userToken
  if (context->getProperty(RegistryConstants::PROP_REGISTRY_nullptr_USER_TOKEN).toString().compare("true", Qt::CaseInsensitive) == 0)
  {
    userRegistryKey.reset(nullptr);
  }

  // Determine primary and alternative registry locations. BlueBerry extension registry cache
  // can be found in one of the two locations:
  // a) in the local configuration area (standard location passed in by the platform) -> priority
  // b) in the shared configuration area (typically, shared install is used)
  QList<QString> registryLocations;
  QList<bool> readOnlyLocations;

  RegistryStrategy* strategy = nullptr;
  //Location configuration = OSGIUtils.getDefault().getConfigurationLocation();
  QString configuration = context->getDataFile("").absoluteFilePath();
  if (configuration.isEmpty())
  {
    RegistryProperties::SetProperty(RegistryConstants::PROP_NO_REGISTRY_CACHE, "true");
    RegistryProperties::SetProperty(RegistryConstants::PROP_NO_LAZY_REGISTRY_CACHE_LOADING, "true");
    strategy = new RegistryStrategy(QList<QString>(), QList<bool>(), masterRegistryKey.data());
  }
  else
  {
    //File primaryDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR);
    //bool primaryReadOnly = configuration.isReadOnly();
    QString primaryDir = configuration;
    bool primaryReadOnly = false;

    //Location parentLocation = configuration.getParentLocation();
    QString parentLocation;
    if (!parentLocation.isEmpty())
    {
//      File secondaryDir = new File(parentLocation.getURL().getFile() + '/' + IRegistryConstants.RUNTIME_NAME);
//      registryLocations << primaryDir << secondaryDir;
//      readOnlyLocations << primaryReadOnly <<  true; // secondary BlueBerry location is always read only
    }
    else
    {
      registryLocations << primaryDir;
      readOnlyLocations << primaryReadOnly;
    }
    strategy = new RegistryStrategy(registryLocations, readOnlyLocations, masterRegistryKey.data());
  }

  auto   registry = new ExtensionRegistry(strategy, masterRegistryKey.data(), userRegistryKey.data());
  defaultRegistry.reset(registry);

  registryServiceReg = context->registerService<IExtensionRegistry>(registry);
  //commandRegistration = EquinoxUtils.registerCommandProvider(Activator.getContext());
}

void org_blueberry_core_runtime_Activator::stopRegistry()
{
  if (!defaultRegistry.isNull())
  {
    registryServiceReg.unregister();
    defaultRegistry->Stop(masterRegistryKey.data());
  }
//  if (!commandRegistration.isNull())
//  {
//    commandRegistration.unregister();
  //  }
}

void org_blueberry_core_runtime_Activator::startAppContainer()
{
  appContainer.reset(new ApplicationContainer(context, defaultRegistry.data()));
  appContainer->Start();
}

void org_blueberry_core_runtime_Activator::stopAppContainer()
{
  appContainer->Stop();
}

}
<commit_msg>Fix external warning in dbghelp.h<commit_after>/*===================================================================

BlueBerry Platform

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#ifndef NOMINMAX
#define NOMINMAX
#endif

#include "berryCTKPluginActivator.h"

#include <berryIApplication.h>
#include <berryIConfigurationElement.h>
#include <berryIContributor.h>

#include "berryApplicationContainer.h"
#include "berryPlatform.h"
#include "berryInternalPlatform.h"
#include "berryErrorApplication.h"
#include "berryPreferencesService.h"
#include "berryExtensionRegistry.h"
#include "berryRegistryConstants.h"
#include "berryRegistryProperties.h"
#include "berryRegistryStrategy.h"
#include "berryRegistryContributor.h"

#include <QCoreApplication>
#include <QDebug>

namespace berry {

static const QString XP_APPLICATIONS = "org.blueberry.osgi.applications";

ctkPluginContext* org_blueberry_core_runtime_Activator::context = nullptr;
QScopedPointer<ApplicationContainer> org_blueberry_core_runtime_Activator::appContainer;

const bool org_blueberry_core_runtime_Activator::DEBUG = false;

void org_blueberry_core_runtime_Activator::start(ctkPluginContext* context)
{
  this->context = context;

  BERRY_REGISTER_EXTENSION_CLASS(ErrorApplication, context)

  RegistryProperties::SetContext(context);
  //ProcessCommandLine();
  this->startRegistry();

  preferencesService.reset(new PreferencesService(context->getDataFile("").absolutePath()));
  prefServiceReg = context->registerService<IPreferencesService>(preferencesService.data());

//  // register a listener to catch new plugin installations/resolutions.
//  pluginListener.reset(new CTKPluginListener(m_ExtensionPointService));
//  context->connectPluginListener(pluginListener.data(), SLOT(pluginChanged(ctkPluginEvent)), Qt::DirectConnection);

//  // populate the registry with all the currently installed plugins.
//  // There is a small window here while processPlugins is being
//  // called where the pluginListener may receive a ctkPluginEvent
//  // to add/remove a plugin from the registry.  This is ok since
//  // the registry is a synchronized object and will not add the
//  // same bundle twice.
//  pluginListener->processPlugins(context->getPlugins());

  this->startAppContainer();

  InternalPlatform::GetInstance()->Start(context);

}

void org_blueberry_core_runtime_Activator::stop(ctkPluginContext* context)
{
  InternalPlatform::GetInstance()->Stop(context);

  //pluginListener.reset();

  //Platform::GetServiceRegistry().UnRegisterService(IExtensionPointService::SERVICE_ID);

  prefServiceReg.unregister();
  preferencesService->ShutDown();
  preferencesService.reset();
  prefServiceReg = 0;

  this->stopRegistry();
  RegistryProperties::SetContext(nullptr);

  stopAppContainer();

  this->context = nullptr;
}

ctkPluginContext* org_blueberry_core_runtime_Activator::getPluginContext()
{
  return context;
}

ApplicationContainer* org_blueberry_core_runtime_Activator::GetContainer()
{
  return appContainer.data();
}

#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_CC_MINGW)

#include <dlfcn.h>
QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol)
{
  if (symbol == nullptr) return QString();

  Dl_info info = {nullptr,nullptr,nullptr,nullptr};
  if(dladdr(symbol, &info) == 0)
  {
    return QString();
  }
  else if(info.dli_fname)
  {
    QFile soPath(info.dli_fname);
    int index = soPath.fileName().lastIndexOf('.');
    QString pluginId = soPath.fileName().left(index);
    if (pluginId.startsWith("lib"))
      pluginId = pluginId.mid(3);
    return pluginId.replace('_', '.');
  }
  return QString();
}

#elif defined(Q_CC_MSVC)

#include <ctkBackTrace.h>
#include <windows.h>

#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable: 4091)
#endif

#include <dbghelp.h>

#ifdef _MSC_VER
#  pragma warning(pop)
#endif

QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol)
{
  if (symbol == nullptr) return QString();

  if (ctk::DebugSymInitialize())
  {
    std::vector<char> moduleBuffer(sizeof(IMAGEHLP_MODULE64));
    PIMAGEHLP_MODULE64 pModuleInfo = (PIMAGEHLP_MODULE64)&moduleBuffer.front();
    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
    if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)symbol, pModuleInfo))
    {
      QString pluginId = pModuleInfo->ModuleName;
      return pluginId.replace('_', '.');
    }
  }
  return QString();
}

#endif

QSharedPointer<ctkPlugin> org_blueberry_core_runtime_Activator::GetPlugin(const SmartPointer<IContributor>& contributor)
{
  if (RegistryContributor::Pointer regContributor = contributor.Cast<RegistryContributor>())
  {
    bool okay = false;
    long id = regContributor->GetActualId().toLong(&okay);
    if (okay)
    {
      if (context != nullptr)
      {
        return context->getPlugin(id);
      }
    }
    else
    {
      // try using the name of the contributor below
    }
  }

  auto plugins = context->getPlugins();

  //Return the first plugin that is not installed or uninstalled
  for (auto plugin : plugins)
  {
    if (!(plugin->getState() == ctkPlugin::INSTALLED ||
          plugin->getState() == ctkPlugin::UNINSTALLED))
    {
      return plugin;
    }
  }
  return QSharedPointer<ctkPlugin>();
}

org_blueberry_core_runtime_Activator::org_blueberry_core_runtime_Activator()
  : userRegistryKey(new QObject())
  , masterRegistryKey(new QObject())
{
}

org_blueberry_core_runtime_Activator::~org_blueberry_core_runtime_Activator()
{
}

void org_blueberry_core_runtime_Activator::startRegistry()
{
  // see if the customer suppressed the creation of default registry
  QString property = context->getProperty(RegistryConstants::PROP_DEFAULT_REGISTRY).toString();
  if (property.compare("false", Qt::CaseInsensitive) == 0) return;

  // check to see if we need to use null as a userToken
  if (context->getProperty(RegistryConstants::PROP_REGISTRY_nullptr_USER_TOKEN).toString().compare("true", Qt::CaseInsensitive) == 0)
  {
    userRegistryKey.reset(nullptr);
  }

  // Determine primary and alternative registry locations. BlueBerry extension registry cache
  // can be found in one of the two locations:
  // a) in the local configuration area (standard location passed in by the platform) -> priority
  // b) in the shared configuration area (typically, shared install is used)
  QList<QString> registryLocations;
  QList<bool> readOnlyLocations;

  RegistryStrategy* strategy = nullptr;
  //Location configuration = OSGIUtils.getDefault().getConfigurationLocation();
  QString configuration = context->getDataFile("").absoluteFilePath();
  if (configuration.isEmpty())
  {
    RegistryProperties::SetProperty(RegistryConstants::PROP_NO_REGISTRY_CACHE, "true");
    RegistryProperties::SetProperty(RegistryConstants::PROP_NO_LAZY_REGISTRY_CACHE_LOADING, "true");
    strategy = new RegistryStrategy(QList<QString>(), QList<bool>(), masterRegistryKey.data());
  }
  else
  {
    //File primaryDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR);
    //bool primaryReadOnly = configuration.isReadOnly();
    QString primaryDir = configuration;
    bool primaryReadOnly = false;

    //Location parentLocation = configuration.getParentLocation();
    QString parentLocation;
    if (!parentLocation.isEmpty())
    {
//      File secondaryDir = new File(parentLocation.getURL().getFile() + '/' + IRegistryConstants.RUNTIME_NAME);
//      registryLocations << primaryDir << secondaryDir;
//      readOnlyLocations << primaryReadOnly <<  true; // secondary BlueBerry location is always read only
    }
    else
    {
      registryLocations << primaryDir;
      readOnlyLocations << primaryReadOnly;
    }
    strategy = new RegistryStrategy(registryLocations, readOnlyLocations, masterRegistryKey.data());
  }

  auto   registry = new ExtensionRegistry(strategy, masterRegistryKey.data(), userRegistryKey.data());
  defaultRegistry.reset(registry);

  registryServiceReg = context->registerService<IExtensionRegistry>(registry);
  //commandRegistration = EquinoxUtils.registerCommandProvider(Activator.getContext());
}

void org_blueberry_core_runtime_Activator::stopRegistry()
{
  if (!defaultRegistry.isNull())
  {
    registryServiceReg.unregister();
    defaultRegistry->Stop(masterRegistryKey.data());
  }
//  if (!commandRegistration.isNull())
//  {
//    commandRegistration.unregister();
  //  }
}

void org_blueberry_core_runtime_Activator::startAppContainer()
{
  appContainer.reset(new ApplicationContainer(context, defaultRegistry.data()));
  appContainer->Start();
}

void org_blueberry_core_runtime_Activator::stopAppContainer()
{
  appContainer->Stop();
}

}
<|endoftext|>