<commit_before>/*
 * Copyright 2017 Google Inc.
 *
 * 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 "font_collection.h"

#include <algorithm>
#include <list>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "font_skia.h"
#include "minikin/Layout.h"
#include "txt/platform.h"
#include "txt/text_style.h"

namespace txt {

namespace {

const std::shared_ptr<minikin::FontFamily> g_null_family;

}  // anonymous namespace

FontCollection::FamilyKey::FamilyKey(const std::vector<std::string>& families,
                                     const std::string& loc) {
  locale = loc;

  std::stringstream stream;
  for_each(families.begin(), families.end(),
           [&stream](const std::string& str) { stream << str << ','; });
  font_families = stream.str();
}

bool FontCollection::FamilyKey::operator==(
    const FontCollection::FamilyKey& other) const {
  return font_families == other.font_families && locale == other.locale;
}

size_t FontCollection::FamilyKey::Hasher::operator()(
    const FontCollection::FamilyKey& key) const {
  return std::hash<std::string>()(key.font_families) ^
         std::hash<std::string>()(key.locale);
}

class TxtFallbackFontProvider
    : public minikin::FontCollection::FallbackFontProvider {
 public:
  TxtFallbackFontProvider(std::shared_ptr<FontCollection> font_collection)
      : font_collection_(font_collection) {}

  virtual const std::shared_ptr<minikin::FontFamily>& matchFallbackFont(
      uint32_t ch,
      std::string locale) {
    std::shared_ptr<FontCollection> fc = font_collection_.lock();
    if (fc) {
      return fc->MatchFallbackFont(ch, locale);
    } else {
      return g_null_family;
    }
  }

 private:
  std::weak_ptr<FontCollection> font_collection_;
};

FontCollection::FontCollection() : enable_font_fallback_(true) {}

FontCollection::~FontCollection() {
  minikin::Layout::purgeCaches();

#if FLUTTER_ENABLE_SKSHAPER
  if (skt_collection_) {
    skt_collection_->clearCaches();
  }
#endif
}

size_t FontCollection::GetFontManagersCount() const {
  return GetFontManagerOrder().size();
}

void FontCollection::SetupDefaultFontManager() {
  default_font_manager_ = GetDefaultFontManager();
}

void FontCollection::SetDefaultFontManager(sk_sp<SkFontMgr> font_manager) {
  default_font_manager_ = font_manager;
}

void FontCollection::SetAssetFontManager(sk_sp<SkFontMgr> font_manager) {
  asset_font_manager_ = font_manager;
}

void FontCollection::SetDynamicFontManager(sk_sp<SkFontMgr> font_manager) {
  dynamic_font_manager_ = font_manager;
}

void FontCollection::SetTestFontManager(sk_sp<SkFontMgr> font_manager) {
  test_font_manager_ = font_manager;
}

// Return the available font managers in the order they should be queried.
std::vector<sk_sp<SkFontMgr>> FontCollection::GetFontManagerOrder() const {
  std::vector<sk_sp<SkFontMgr>> order;
  if (dynamic_font_manager_)
    order.push_back(dynamic_font_manager_);
  if (asset_font_manager_)
    order.push_back(asset_font_manager_);
  if (test_font_manager_)
    order.push_back(test_font_manager_);
  if (default_font_manager_)
    order.push_back(default_font_manager_);
  return order;
}

void FontCollection::DisableFontFallback() {
  enable_font_fallback_ = false;

#if FLUTTER_ENABLE_SKSHAPER
  if (skt_collection_) {
    skt_collection_->disableFontFallback();
  }
#endif
}

std::shared_ptr<minikin::FontCollection>
FontCollection::GetMinikinFontCollectionForFamilies(
    const std::vector<std::string>& font_families,
    const std::string& locale) {
  // Look inside the font collections cache first.
  FamilyKey family_key(font_families, locale);
  auto cached = font_collections_cache_.find(family_key);
  if (cached != font_collections_cache_.end()) {
    return cached->second;
  }

  std::vector<std::shared_ptr<minikin::FontFamily>> minikin_families;

  // Search for all user provided font families.
  for (size_t fallback_index = 0; fallback_index < font_families.size();
       fallback_index++) {
    std::shared_ptr<minikin::FontFamily> minikin_family =
        FindFontFamilyInManagers(font_families[fallback_index]);
    if (minikin_family != nullptr) {
      minikin_families.push_back(minikin_family);
    }
  }
  // Search for default font family if no user font families were found.
  if (minikin_families.empty()) {
    const auto default_font_families = GetDefaultFontFamilies();
    for (const auto& family : default_font_families) {
      std::shared_ptr<minikin::FontFamily> minikin_family =
          FindFontFamilyInManagers(family);
      if (minikin_family != nullptr) {
        minikin_families.push_back(minikin_family);
        break;
      }
    }
  }
  // Default font family also not found. We fail to get a FontCollection.
  if (minikin_families.empty()) {
    font_collections_cache_[family_key] = nullptr;
    return nullptr;
  }
  if (enable_font_fallback_) {
    for (const std::string& fallback_family :
         fallback_fonts_for_locale_[locale]) {
      auto it = fallback_fonts_.find(fallback_family);
      if (it != fallback_fonts_.end()) {
        minikin_families.push_back(it->second);
      }
    }
  }
  // Create the minikin font collection.
  auto font_collection =
      std::make_shared<minikin::FontCollection>(std::move(minikin_families));
  if (enable_font_fallback_) {
    font_collection->set_fallback_font_provider(
        std::make_unique<TxtFallbackFontProvider>(shared_from_this()));
  }

  // Cache the font collection for future queries.
  font_collections_cache_[family_key] = font_collection;

  return font_collection;
}

std::shared_ptr<minikin::FontFamily> FontCollection::FindFontFamilyInManagers(
    const std::string& family_name) {
  TRACE_EVENT0("flutter", "FontCollection::FindFontFamilyInManagers");
  // Search for the font family in each font manager.
  for (sk_sp<SkFontMgr>& manager : GetFontManagerOrder()) {
    std::shared_ptr<minikin::FontFamily> minikin_family =
        CreateMinikinFontFamily(manager, family_name);
    if (!minikin_family)
      continue;
    return minikin_family;
  }
  return nullptr;
}

void FontCollection::SortSkTypefaces(
    std::vector<sk_sp<SkTypeface>>& sk_typefaces) {
  std::sort(
      sk_typefaces.begin(), sk_typefaces.end(),
      [](const sk_sp<SkTypeface>& a, const sk_sp<SkTypeface>& b) {
        SkFontStyle a_style = a->fontStyle();
        SkFontStyle b_style = b->fontStyle();

        int a_delta = std::abs(a_style.width() - SkFontStyle::kNormal_Width);
        int b_delta = std::abs(b_style.width() - SkFontStyle::kNormal_Width);

        if (a_delta != b_delta) {
          // If a family name query is so generic it ends up bringing in fonts
          // of multiple widths (e.g. condensed, expanded), opt to be
          // conservative and select the most standard width.
          //
          // If a specific width is desired, it should be be narrowed down via
          // the family name.
          //
          // The font weights are also sorted lightest to heaviest but Flutter
          // APIs have the weight specified to narrow it down later. The width
          // ordering here is more consequential since TextStyle doesn't have
          // letter width APIs.
          return a_delta < b_delta;
        } else if (a_style.width() != b_style.width()) {
          // However, if the 2 fonts are equidistant from the "normal" width,
          // just arbitrarily but consistently return the more condensed font.
          return a_style.width() < b_style.width();
        } else if (a_style.weight() != b_style.weight()) {
          return a_style.weight() < b_style.weight();
        } else {
          return a_style.slant() < b_style.slant();
        }
        // Use a cascade of conditions so results are consistent each time.
      });
}

std::shared_ptr<minikin::FontFamily> FontCollection::CreateMinikinFontFamily(
    const sk_sp<SkFontMgr>& manager,
    const std::string& family_name) {
  TRACE_EVENT1("flutter", "FontCollection::CreateMinikinFontFamily",
               "family_name", family_name.c_str());
  sk_sp<SkFontStyleSet> font_style_set(
      manager->matchFamily(family_name.c_str()));
  if (font_style_set == nullptr || font_style_set->count() == 0) {
    return nullptr;
  }

  std::vector<sk_sp<SkTypeface>> skia_typefaces;
  for (int i = 0; i < font_style_set->count(); ++i) {
    TRACE_EVENT0("flutter", "CreateSkiaTypeface");
    sk_sp<SkTypeface> skia_typeface(
        sk_sp<SkTypeface>(font_style_set->createTypeface(i)));
    if (skia_typeface != nullptr) {
      skia_typefaces.emplace_back(std::move(skia_typeface));
    }
  }

  SortSkTypefaces(skia_typefaces);

  std::vector<minikin::Font> minikin_fonts;
  for (const sk_sp<SkTypeface>& skia_typeface : skia_typefaces) {
    // Create the minikin font from the skia typeface.
    // Divide by 100 because the weights are given as "100", "200", etc.
    minikin_fonts.emplace_back(
        std::make_shared<FontSkia>(skia_typeface),
        minikin::FontStyle{skia_typeface->fontStyle().weight() / 100,
                           skia_typeface->isItalic()});
  }

  return std::make_shared<minikin::FontFamily>(std::move(minikin_fonts));
}

const std::shared_ptr<minikin::FontFamily>& FontCollection::MatchFallbackFont(
    uint32_t ch,
    std::string locale) {
  // Check if the ch's matched font has been cached. We cache the results of
  // this method as repeated matchFamilyStyleCharacter calls can become
  // extremely laggy when typing a large number of complex emojis.
  auto lookup = fallback_match_cache_.find(ch);
  if (lookup != fallback_match_cache_.end()) {
    return *lookup->second;
  }
  const std::shared_ptr<minikin::FontFamily>* match =
      &DoMatchFallbackFont(ch, locale);
  fallback_match_cache_.insert(std::make_pair(ch, match));
  return *match;
}

const std::shared_ptr<minikin::FontFamily>& FontCollection::DoMatchFallbackFont(
    uint32_t ch,
    std::string locale) {
  for (const sk_sp<SkFontMgr>& manager : GetFontManagerOrder()) {
    std::vector<const char*> bcp47;
    if (!locale.empty())
      bcp47.push_back(locale.c_str());
    sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
        0, SkFontStyle(), bcp47.data(), bcp47.size(), ch));
    if (!typeface)
      continue;

    SkString sk_family_name;
    typeface->getFamilyName(&sk_family_name);
    std::string family_name(sk_family_name.c_str());

    if (std::find(fallback_fonts_for_locale_[locale].begin(),
                  fallback_fonts_for_locale_[locale].end(),
                  family_name) == fallback_fonts_for_locale_[locale].end())
      fallback_fonts_for_locale_[locale].push_back(family_name);

    return GetFallbackFontFamily(manager, family_name);
  }
  return g_null_family;
}

const std::shared_ptr<minikin::FontFamily>&
FontCollection::GetFallbackFontFamily(const sk_sp<SkFontMgr>& manager,
                                      const std::string& family_name) {
  TRACE_EVENT0("flutter", "FontCollection::GetFallbackFontFamily");
  auto fallback_it = fallback_fonts_.find(family_name);
  if (fallback_it != fallback_fonts_.end()) {
    return fallback_it->second;
  }

  std::shared_ptr<minikin::FontFamily> minikin_family =
      CreateMinikinFontFamily(manager, family_name);
  if (!minikin_family)
    return g_null_family;

  auto insert_it =
      fallback_fonts_.insert(std::make_pair(family_name, minikin_family));

  // Clear the cache to force creation of new font collections that will
  // include this fallback font.
  font_collections_cache_.clear();

  return insert_it.first->second;
}

void FontCollection::ClearFontFamilyCache() {
  font_collections_cache_.clear();

#if FLUTTER_ENABLE_SKSHAPER
  if (skt_collection_) {
    skt_collection_->clearCaches();
  }
#endif
}
#if FLUTTER_ENABLE_SKSHAPER

sk_sp<skia::textlayout::FontCollection>
FontCollection::CreateSktFontCollection() {
  if (!skt_collection_) {
    skt_collection_ = sk_make_sp<skia::textlayout::FontCollection>();

    skt_collection_->setDefaultFontManager(default_font_manager_,
                                           GetDefaultFontFamilies()[0].c_str());
    skt_collection_->setAssetFontManager(asset_font_manager_);
    skt_collection_->setDynamicFontManager(dynamic_font_manager_);
    skt_collection_->setTestFontManager(test_font_manager_);
    if (!enable_font_fallback_) {
      skt_collection_->disableFontFallback();
    }
  }

  return skt_collection_;
}

#endif  // FLUTTER_ENABLE_SKSHAPER

}  // namespace txt
<commit_msg>Invalidate the cached SkParagraph font collection when a new font manager is installed (#22157)<commit_after>/*
 * Copyright 2017 Google Inc.
 *
 * 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 "font_collection.h"

#include <algorithm>
#include <list>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "font_skia.h"
#include "minikin/Layout.h"
#include "txt/platform.h"
#include "txt/text_style.h"

namespace txt {

namespace {

const std::shared_ptr<minikin::FontFamily> g_null_family;

}  // anonymous namespace

FontCollection::FamilyKey::FamilyKey(const std::vector<std::string>& families,
                                     const std::string& loc) {
  locale = loc;

  std::stringstream stream;
  for_each(families.begin(), families.end(),
           [&stream](const std::string& str) { stream << str << ','; });
  font_families = stream.str();
}

bool FontCollection::FamilyKey::operator==(
    const FontCollection::FamilyKey& other) const {
  return font_families == other.font_families && locale == other.locale;
}

size_t FontCollection::FamilyKey::Hasher::operator()(
    const FontCollection::FamilyKey& key) const {
  return std::hash<std::string>()(key.font_families) ^
         std::hash<std::string>()(key.locale);
}

class TxtFallbackFontProvider
    : public minikin::FontCollection::FallbackFontProvider {
 public:
  TxtFallbackFontProvider(std::shared_ptr<FontCollection> font_collection)
      : font_collection_(font_collection) {}

  virtual const std::shared_ptr<minikin::FontFamily>& matchFallbackFont(
      uint32_t ch,
      std::string locale) {
    std::shared_ptr<FontCollection> fc = font_collection_.lock();
    if (fc) {
      return fc->MatchFallbackFont(ch, locale);
    } else {
      return g_null_family;
    }
  }

 private:
  std::weak_ptr<FontCollection> font_collection_;
};

FontCollection::FontCollection() : enable_font_fallback_(true) {}

FontCollection::~FontCollection() {
  minikin::Layout::purgeCaches();

#if FLUTTER_ENABLE_SKSHAPER
  if (skt_collection_) {
    skt_collection_->clearCaches();
  }
#endif
}

size_t FontCollection::GetFontManagersCount() const {
  return GetFontManagerOrder().size();
}

void FontCollection::SetupDefaultFontManager() {
  default_font_manager_ = GetDefaultFontManager();
}

void FontCollection::SetDefaultFontManager(sk_sp<SkFontMgr> font_manager) {
  default_font_manager_ = font_manager;

#if FLUTTER_ENABLE_SKSHAPER
  skt_collection_.reset();
#endif
}

void FontCollection::SetAssetFontManager(sk_sp<SkFontMgr> font_manager) {
  asset_font_manager_ = font_manager;

#if FLUTTER_ENABLE_SKSHAPER
  skt_collection_.reset();
#endif
}

void FontCollection::SetDynamicFontManager(sk_sp<SkFontMgr> font_manager) {
  dynamic_font_manager_ = font_manager;

#if FLUTTER_ENABLE_SKSHAPER
  skt_collection_.reset();
#endif
}

void FontCollection::SetTestFontManager(sk_sp<SkFontMgr> font_manager) {
  test_font_manager_ = font_manager;

#if FLUTTER_ENABLE_SKSHAPER
  skt_collection_.reset();
#endif
}

// Return the available font managers in the order they should be queried.
std::vector<sk_sp<SkFontMgr>> FontCollection::GetFontManagerOrder() const {
  std::vector<sk_sp<SkFontMgr>> order;
  if (dynamic_font_manager_)
    order.push_back(dynamic_font_manager_);
  if (asset_font_manager_)
    order.push_back(asset_font_manager_);
  if (test_font_manager_)
    order.push_back(test_font_manager_);
  if (default_font_manager_)
    order.push_back(default_font_manager_);
  return order;
}

void FontCollection::DisableFontFallback() {
  enable_font_fallback_ = false;

#if FLUTTER_ENABLE_SKSHAPER
  if (skt_collection_) {
    skt_collection_->disableFontFallback();
  }
#endif
}

std::shared_ptr<minikin::FontCollection>
FontCollection::GetMinikinFontCollectionForFamilies(
    const std::vector<std::string>& font_families,
    const std::string& locale) {
  // Look inside the font collections cache first.
  FamilyKey family_key(font_families, locale);
  auto cached = font_collections_cache_.find(family_key);
  if (cached != font_collections_cache_.end()) {
    return cached->second;
  }

  std::vector<std::shared_ptr<minikin::FontFamily>> minikin_families;

  // Search for all user provided font families.
  for (size_t fallback_index = 0; fallback_index < font_families.size();
       fallback_index++) {
    std::shared_ptr<minikin::FontFamily> minikin_family =
        FindFontFamilyInManagers(font_families[fallback_index]);
    if (minikin_family != nullptr) {
      minikin_families.push_back(minikin_family);
    }
  }
  // Search for default font family if no user font families were found.
  if (minikin_families.empty()) {
    const auto default_font_families = GetDefaultFontFamilies();
    for (const auto& family : default_font_families) {
      std::shared_ptr<minikin::FontFamily> minikin_family =
          FindFontFamilyInManagers(family);
      if (minikin_family != nullptr) {
        minikin_families.push_back(minikin_family);
        break;
      }
    }
  }
  // Default font family also not found. We fail to get a FontCollection.
  if (minikin_families.empty()) {
    font_collections_cache_[family_key] = nullptr;
    return nullptr;
  }
  if (enable_font_fallback_) {
    for (const std::string& fallback_family :
         fallback_fonts_for_locale_[locale]) {
      auto it = fallback_fonts_.find(fallback_family);
      if (it != fallback_fonts_.end()) {
        minikin_families.push_back(it->second);
      }
    }
  }
  // Create the minikin font collection.
  auto font_collection =
      std::make_shared<minikin::FontCollection>(std::move(minikin_families));
  if (enable_font_fallback_) {
    font_collection->set_fallback_font_provider(
        std::make_unique<TxtFallbackFontProvider>(shared_from_this()));
  }

  // Cache the font collection for future queries.
  font_collections_cache_[family_key] = font_collection;

  return font_collection;
}

std::shared_ptr<minikin::FontFamily> FontCollection::FindFontFamilyInManagers(
    const std::string& family_name) {
  TRACE_EVENT0("flutter", "FontCollection::FindFontFamilyInManagers");
  // Search for the font family in each font manager.
  for (sk_sp<SkFontMgr>& manager : GetFontManagerOrder()) {
    std::shared_ptr<minikin::FontFamily> minikin_family =
        CreateMinikinFontFamily(manager, family_name);
    if (!minikin_family)
      continue;
    return minikin_family;
  }
  return nullptr;
}

void FontCollection::SortSkTypefaces(
    std::vector<sk_sp<SkTypeface>>& sk_typefaces) {
  std::sort(
      sk_typefaces.begin(), sk_typefaces.end(),
      [](const sk_sp<SkTypeface>& a, const sk_sp<SkTypeface>& b) {
        SkFontStyle a_style = a->fontStyle();
        SkFontStyle b_style = b->fontStyle();

        int a_delta = std::abs(a_style.width() - SkFontStyle::kNormal_Width);
        int b_delta = std::abs(b_style.width() - SkFontStyle::kNormal_Width);

        if (a_delta != b_delta) {
          // If a family name query is so generic it ends up bringing in fonts
          // of multiple widths (e.g. condensed, expanded), opt to be
          // conservative and select the most standard width.
          //
          // If a specific width is desired, it should be be narrowed down via
          // the family name.
          //
          // The font weights are also sorted lightest to heaviest but Flutter
          // APIs have the weight specified to narrow it down later. The width
          // ordering here is more consequential since TextStyle doesn't have
          // letter width APIs.
          return a_delta < b_delta;
        } else if (a_style.width() != b_style.width()) {
          // However, if the 2 fonts are equidistant from the "normal" width,
          // just arbitrarily but consistently return the more condensed font.
          return a_style.width() < b_style.width();
        } else if (a_style.weight() != b_style.weight()) {
          return a_style.weight() < b_style.weight();
        } else {
          return a_style.slant() < b_style.slant();
        }
        // Use a cascade of conditions so results are consistent each time.
      });
}

std::shared_ptr<minikin::FontFamily> FontCollection::CreateMinikinFontFamily(
    const sk_sp<SkFontMgr>& manager,
    const std::string& family_name) {
  TRACE_EVENT1("flutter", "FontCollection::CreateMinikinFontFamily",
               "family_name", family_name.c_str());
  sk_sp<SkFontStyleSet> font_style_set(
      manager->matchFamily(family_name.c_str()));
  if (font_style_set == nullptr || font_style_set->count() == 0) {
    return nullptr;
  }

  std::vector<sk_sp<SkTypeface>> skia_typefaces;
  for (int i = 0; i < font_style_set->count(); ++i) {
    TRACE_EVENT0("flutter", "CreateSkiaTypeface");
    sk_sp<SkTypeface> skia_typeface(
        sk_sp<SkTypeface>(font_style_set->createTypeface(i)));
    if (skia_typeface != nullptr) {
      skia_typefaces.emplace_back(std::move(skia_typeface));
    }
  }

  SortSkTypefaces(skia_typefaces);

  std::vector<minikin::Font> minikin_fonts;
  for (const sk_sp<SkTypeface>& skia_typeface : skia_typefaces) {
    // Create the minikin font from the skia typeface.
    // Divide by 100 because the weights are given as "100", "200", etc.
    minikin_fonts.emplace_back(
        std::make_shared<FontSkia>(skia_typeface),
        minikin::FontStyle{skia_typeface->fontStyle().weight() / 100,
                           skia_typeface->isItalic()});
  }

  return std::make_shared<minikin::FontFamily>(std::move(minikin_fonts));
}

const std::shared_ptr<minikin::FontFamily>& FontCollection::MatchFallbackFont(
    uint32_t ch,
    std::string locale) {
  // Check if the ch's matched font has been cached. We cache the results of
  // this method as repeated matchFamilyStyleCharacter calls can become
  // extremely laggy when typing a large number of complex emojis.
  auto lookup = fallback_match_cache_.find(ch);
  if (lookup != fallback_match_cache_.end()) {
    return *lookup->second;
  }
  const std::shared_ptr<minikin::FontFamily>* match =
      &DoMatchFallbackFont(ch, locale);
  fallback_match_cache_.insert(std::make_pair(ch, match));
  return *match;
}

const std::shared_ptr<minikin::FontFamily>& FontCollection::DoMatchFallbackFont(
    uint32_t ch,
    std::string locale) {
  for (const sk_sp<SkFontMgr>& manager : GetFontManagerOrder()) {
    std::vector<const char*> bcp47;
    if (!locale.empty())
      bcp47.push_back(locale.c_str());
    sk_sp<SkTypeface> typeface(manager->matchFamilyStyleCharacter(
        0, SkFontStyle(), bcp47.data(), bcp47.size(), ch));
    if (!typeface)
      continue;

    SkString sk_family_name;
    typeface->getFamilyName(&sk_family_name);
    std::string family_name(sk_family_name.c_str());

    if (std::find(fallback_fonts_for_locale_[locale].begin(),
                  fallback_fonts_for_locale_[locale].end(),
                  family_name) == fallback_fonts_for_locale_[locale].end())
      fallback_fonts_for_locale_[locale].push_back(family_name);

    return GetFallbackFontFamily(manager, family_name);
  }
  return g_null_family;
}

const std::shared_ptr<minikin::FontFamily>&
FontCollection::GetFallbackFontFamily(const sk_sp<SkFontMgr>& manager,
                                      const std::string& family_name) {
  TRACE_EVENT0("flutter", "FontCollection::GetFallbackFontFamily");
  auto fallback_it = fallback_fonts_.find(family_name);
  if (fallback_it != fallback_fonts_.end()) {
    return fallback_it->second;
  }

  std::shared_ptr<minikin::FontFamily> minikin_family =
      CreateMinikinFontFamily(manager, family_name);
  if (!minikin_family)
    return g_null_family;

  auto insert_it =
      fallback_fonts_.insert(std::make_pair(family_name, minikin_family));

  // Clear the cache to force creation of new font collections that will
  // include this fallback font.
  font_collections_cache_.clear();

  return insert_it.first->second;
}

void FontCollection::ClearFontFamilyCache() {
  font_collections_cache_.clear();

#if FLUTTER_ENABLE_SKSHAPER
  if (skt_collection_) {
    skt_collection_->clearCaches();
  }
#endif
}

#if FLUTTER_ENABLE_SKSHAPER

sk_sp<skia::textlayout::FontCollection>
FontCollection::CreateSktFontCollection() {
  if (!skt_collection_) {
    skt_collection_ = sk_make_sp<skia::textlayout::FontCollection>();

    skt_collection_->setDefaultFontManager(default_font_manager_,
                                           GetDefaultFontFamilies()[0].c_str());
    skt_collection_->setAssetFontManager(asset_font_manager_);
    skt_collection_->setDynamicFontManager(dynamic_font_manager_);
    skt_collection_->setTestFontManager(test_font_manager_);
    if (!enable_font_fallback_) {
      skt_collection_->disableFontFallback();
    }
  }

  return skt_collection_;
}

#endif  // FLUTTER_ENABLE_SKSHAPER

}  // namespace txt
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "print_settings.h"

#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "printing/units.h"

namespace printing {

// Global SequenceNumber used for generating unique cookie values.
static base::AtomicSequenceNumber cookie_seq = LAZY_INSTANCE_INITIALIZER;

PageMeasurements::PageMeasurements()
    : page_type(PT_LETTER),
      page_length(0.0f),
      page_width(0.0f) {
}

void PageMeasurements::Clear() {
  page_type = PT_LETTER;
  page_length = 0.0f;
  page_width = 0.0f;
}

bool PageMeasurements::Equals(const PageMeasurements& rhs) const {
  return page_type == rhs.page_type &&
      page_length == rhs.page_length &&
      page_width == rhs.page_width;
}

PrintSettings::PrintSettings()
    : min_shrink(1.25),
      max_shrink(2.0),
      desired_dpi(72),
      selection_only(false),
      to_file(false),
      dpi_(0),
      landscape(false) {
  ResetRequestedPageMargins();
}

void PrintSettings::Clear() {
  ranges.clear();
  min_shrink = 1.25;
  max_shrink = 2.;
  desired_dpi = 72;
  selection_only = false;
  to_file = false;
  printer_name_.clear();
  device_name_.clear();
  page_setup_pixels_.Clear();
  dpi_ = 0;
  landscape = false;
  page_measurements.Clear();
  ResetRequestedPageMargins();
}

void PrintSettings::ResetRequestedPageMargins() {
  // Initial requested margins to = 1.0cm = ~2/5 of inch
  const int margin_printer_units = ConvertUnit(1000, kHundrethsMMPerInch, desired_dpi);
  // Initial requested header/footer margins to = 0.5cm = ~1/5 of inch
  const int header_footer_margins = ConvertUnit(500, kHundrethsMMPerInch, desired_dpi);
  requested_margins.header = header_footer_margins;
  requested_margins.footer = header_footer_margins;
  requested_margins.left = margin_printer_units;
  requested_margins.top = margin_printer_units;
  requested_margins.right = margin_printer_units;
  requested_margins.bottom = margin_printer_units;
}

#ifdef WIN32
void PrintSettings::Init(HDC hdc,
                         const DEVMODE& dev_mode,
                         const PageRanges& new_ranges,
                         const CefString& new_device_name,
                         bool print_selection_only,
                         bool print_to_file) {
  DCHECK(hdc);
  printer_name_ = std::wstring(dev_mode.dmDeviceName);
  device_name_ = new_device_name;
  ranges = new_ranges;
  landscape = dev_mode.dmOrientation == DMORIENT_LANDSCAPE;
  selection_only = print_selection_only;
  to_file = print_to_file;

  bool is_custom_paper = true;
  if (dev_mode.dmFields & DM_PAPERSIZE) {
    switch(dev_mode.dmPaperSize) {
    case DMPAPER_LETTER:
      page_measurements.page_type = PT_LETTER;
      is_custom_paper = false;
      break;
    case DMPAPER_LEGAL:
      page_measurements.page_type = PT_LEGAL;
      is_custom_paper = false;
      break;
    case DMPAPER_EXECUTIVE:
      page_measurements.page_type = PT_EXECUTIVE;
      is_custom_paper = false;
      break;
    case DMPAPER_A3:
      page_measurements.page_type = PT_A3;
      is_custom_paper = false;
      break;
    case DMPAPER_A4:
      page_measurements.page_type = PT_A4;
      is_custom_paper = false;
      break;
    default:
      //we'll translate it as a custom paper size.
      break;
    }
  }

  dpi_ = GetDeviceCaps(hdc, LOGPIXELSX);
  // No printer device is known to advertise different dpi in X and Y axis; even
  // the fax device using the 200x100 dpi setting. It's ought to break so many
  // applications that it's not even needed to care about. WebKit doesn't
  // support different dpi settings in X and Y axis.
  DCHECK_EQ(dpi_, GetDeviceCaps(hdc, LOGPIXELSY));

  DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORX), 0);
  DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORY), 0);

  // Initialize page_setup_pixels_.
  gfx::Size physical_size_pixels(GetDeviceCaps(hdc, PHYSICALWIDTH),
                                 GetDeviceCaps(hdc, PHYSICALHEIGHT));
  gfx::Rect printable_area_pixels(GetDeviceCaps(hdc, PHYSICALOFFSETX),
                                  GetDeviceCaps(hdc, PHYSICALOFFSETY),
                                  GetDeviceCaps(hdc, HORZRES),
                                  GetDeviceCaps(hdc, VERTRES));

  if (is_custom_paper) {
    page_measurements.page_length = ConvertUnitDouble(
      static_cast<double>(physical_size_pixels.height()),
      static_cast<double>(dpi_),
      static_cast<double>(desired_dpi));
    page_measurements.page_width = ConvertUnitDouble(
      static_cast<double>(physical_size_pixels.width()),
      static_cast<double>(dpi_),
      static_cast<double>(desired_dpi));
    if (landscape) {
      double temp = page_measurements.page_length;
      page_measurements.page_length = page_measurements.page_width;
      page_measurements.page_width = temp;
    }

  }
  SetPrinterPrintableArea(physical_size_pixels, printable_area_pixels);
}
#endif

void PrintSettings::SetPrinterPrintableArea(
    gfx::Size const& physical_size_pixels,
    gfx::Rect const& printable_area_pixels) {

  // Hard-code text_height = 0.5cm = ~1/5 of inch
  const int text_height = ConvertUnit(500, kHundrethsMMPerInch, dpi_);

  // Start by setting the user configuration
  page_setup_pixels_.Init(physical_size_pixels,
                          printable_area_pixels,
                          text_height);

  // Now adjust requested margins to the appropriate dpi.
  PageMargins margins;
  margins.header = ConvertUnit(requested_margins.header, desired_dpi, dpi_);
  margins.footer = ConvertUnit(requested_margins.footer, desired_dpi, dpi_);
  margins.left = ConvertUnit(requested_margins.left, desired_dpi, dpi_);
  margins.top = ConvertUnit(requested_margins.top, desired_dpi, dpi_);
  margins.right = ConvertUnit(requested_margins.right, desired_dpi, dpi_);
  margins.bottom = ConvertUnit(requested_margins.bottom, desired_dpi, dpi_);
  page_setup_pixels_.SetRequestedMargins(margins);
}

void PrintSettings::RenderParams(PrintParams* params) const {
  DCHECK(params);
  params->printable_size.SetSize(page_setup_pixels_.content_area().width(),
                                 page_setup_pixels_.content_area().height());
  params->dpi = dpi_;
  // Currently hardcoded at 1.25. See PrintSettings' constructor.
  params->min_shrink = min_shrink;
  // Currently hardcoded at 2.0. See PrintSettings' constructor.
  params->max_shrink = max_shrink;
  // Currently hardcoded at 72dpi. See PrintSettings' constructor.
  params->desired_dpi = desired_dpi;
  // Always use an invalid cookie.
  params->document_cookie = 0;
  params->selection_only = selection_only;
  params->to_file = to_file;
}

bool PrintSettings::Equals(const PrintSettings& rhs) const {
  // Do not test the display device name (printer_name_) for equality since it
  // may sometimes be chopped off at 30 chars. As long as device_name is the
  // same, that's fine.
  return ranges == rhs.ranges &&
      min_shrink == rhs.min_shrink &&
      max_shrink == rhs.max_shrink &&
      desired_dpi == rhs.desired_dpi &&
      device_name_ == rhs.device_name_ &&
      page_setup_pixels_.Equals(rhs.page_setup_pixels_) &&
      dpi_ == rhs.dpi_ &&
      landscape == rhs.landscape &&
      page_measurements.Equals(rhs.page_measurements) &&
      requested_margins.Equals(rhs.requested_margins);
}

int PrintSettings::NewCookie() {
  // A cookie of 0 is used to mark a document as unassigned, count from 1.
  return cookie_seq.GetNext() + 1;
}

void PrintSettings::UpdatePrintOptions(cef_print_options_t& print_options) {

  print_options.page_orientation = (landscape) ? LANDSCAPE : PORTRAIT;
  print_options.paper_metrics.paper_type = page_measurements.page_type;

  if (page_measurements.page_type == PT_CUSTOM) {
    print_options.paper_metrics.length = ConvertUnitDouble(
      page_measurements.page_length, desired_dpi, 1);
    print_options.paper_metrics.width = ConvertUnitDouble(
      page_measurements.page_width, desired_dpi, 1);
  }
  print_options.paper_margins.left = ConvertUnitDouble(
      requested_margins.left, desired_dpi, 1);
  print_options.paper_margins.top = ConvertUnitDouble(
      requested_margins.top, desired_dpi, 1);
  print_options.paper_margins.right = ConvertUnitDouble(
      requested_margins.right, desired_dpi, 1);
  print_options.paper_margins.bottom = ConvertUnitDouble(
      requested_margins.bottom, desired_dpi, 1);
  print_options.paper_margins.header = ConvertUnitDouble(
      requested_margins.header, desired_dpi, 1);
  print_options.paper_margins.footer = ConvertUnitDouble(
      requested_margins.footer, desired_dpi, 1);
}
void PrintSettings::UpdateFromPrintOptions(const cef_print_options_t& print_options) {
  landscape = print_options.page_orientation == LANDSCAPE;
  page_measurements.page_type = print_options.paper_metrics.paper_type;
  if (page_measurements.page_type == PT_CUSTOM) {
    page_measurements.page_length = ConvertUnitDouble(
      print_options.paper_metrics.length, 1, desired_dpi);
    page_measurements.page_width = ConvertUnitDouble(
      print_options.paper_metrics.width, 1, desired_dpi);
  }
  requested_margins.left = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.left, 1, desired_dpi));
  requested_margins.top = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.top, 1, desired_dpi));
  requested_margins.right = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.right, 1, desired_dpi));
  requested_margins.bottom = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.bottom, 1, desired_dpi));
  requested_margins.header = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.header, 1, desired_dpi));
  requested_margins.footer = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.footer, 1, desired_dpi));
}

}  // namespace printing

<commit_msg>Revert revision 395 changes to print_settings.cc.<commit_after>// Copyright (c) 2006-2008 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 "print_settings.h"

#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "printing/units.h"

namespace printing {

// Global SequenceNumber used for generating unique cookie values.
static base::AtomicSequenceNumber cookie_seq(base::LINKER_INITIALIZED);

PageMeasurements::PageMeasurements()
    : page_type(PT_LETTER),
      page_length(0.0f),
      page_width(0.0f) {
}

void PageMeasurements::Clear() {
  page_type = PT_LETTER;
  page_length = 0.0f;
  page_width = 0.0f;
}

bool PageMeasurements::Equals(const PageMeasurements& rhs) const {
  return page_type == rhs.page_type &&
      page_length == rhs.page_length &&
      page_width == rhs.page_width;
}

PrintSettings::PrintSettings()
    : min_shrink(1.25),
      max_shrink(2.0),
      desired_dpi(72),
      selection_only(false),
      to_file(false),
      dpi_(0),
      landscape(false) {
  ResetRequestedPageMargins();
}

void PrintSettings::Clear() {
  ranges.clear();
  min_shrink = 1.25;
  max_shrink = 2.;
  desired_dpi = 72;
  selection_only = false;
  to_file = false;
  printer_name_.clear();
  device_name_.clear();
  page_setup_pixels_.Clear();
  dpi_ = 0;
  landscape = false;
  page_measurements.Clear();
  ResetRequestedPageMargins();
}

void PrintSettings::ResetRequestedPageMargins() {
  // Initial requested margins to = 1.0cm = ~2/5 of inch
  const int margin_printer_units = ConvertUnit(1000, kHundrethsMMPerInch, desired_dpi);
  // Initial requested header/footer margins to = 0.5cm = ~1/5 of inch
  const int header_footer_margins = ConvertUnit(500, kHundrethsMMPerInch, desired_dpi);
  requested_margins.header = header_footer_margins;
  requested_margins.footer = header_footer_margins;
  requested_margins.left = margin_printer_units;
  requested_margins.top = margin_printer_units;
  requested_margins.right = margin_printer_units;
  requested_margins.bottom = margin_printer_units;
}

#ifdef WIN32
void PrintSettings::Init(HDC hdc,
                         const DEVMODE& dev_mode,
                         const PageRanges& new_ranges,
                         const CefString& new_device_name,
                         bool print_selection_only,
                         bool print_to_file) {
  DCHECK(hdc);
  printer_name_ = std::wstring(dev_mode.dmDeviceName);
  device_name_ = new_device_name;
  ranges = new_ranges;
  landscape = dev_mode.dmOrientation == DMORIENT_LANDSCAPE;
  selection_only = print_selection_only;
  to_file = print_to_file;

  bool is_custom_paper = true;
  if (dev_mode.dmFields & DM_PAPERSIZE) {
    switch(dev_mode.dmPaperSize) {
    case DMPAPER_LETTER:
      page_measurements.page_type = PT_LETTER;
      is_custom_paper = false;
      break;
    case DMPAPER_LEGAL:
      page_measurements.page_type = PT_LEGAL;
      is_custom_paper = false;
      break;
    case DMPAPER_EXECUTIVE:
      page_measurements.page_type = PT_EXECUTIVE;
      is_custom_paper = false;
      break;
    case DMPAPER_A3:
      page_measurements.page_type = PT_A3;
      is_custom_paper = false;
      break;
    case DMPAPER_A4:
      page_measurements.page_type = PT_A4;
      is_custom_paper = false;
      break;
    default:
      //we'll translate it as a custom paper size.
      break;
    }
  }

  dpi_ = GetDeviceCaps(hdc, LOGPIXELSX);
  // No printer device is known to advertise different dpi in X and Y axis; even
  // the fax device using the 200x100 dpi setting. It's ought to break so many
  // applications that it's not even needed to care about. WebKit doesn't
  // support different dpi settings in X and Y axis.
  DCHECK_EQ(dpi_, GetDeviceCaps(hdc, LOGPIXELSY));

  DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORX), 0);
  DCHECK_EQ(GetDeviceCaps(hdc, SCALINGFACTORY), 0);

  // Initialize page_setup_pixels_.
  gfx::Size physical_size_pixels(GetDeviceCaps(hdc, PHYSICALWIDTH),
                                 GetDeviceCaps(hdc, PHYSICALHEIGHT));
  gfx::Rect printable_area_pixels(GetDeviceCaps(hdc, PHYSICALOFFSETX),
                                  GetDeviceCaps(hdc, PHYSICALOFFSETY),
                                  GetDeviceCaps(hdc, HORZRES),
                                  GetDeviceCaps(hdc, VERTRES));

  if (is_custom_paper) {
    page_measurements.page_length = ConvertUnitDouble(
      static_cast<double>(physical_size_pixels.height()),
      static_cast<double>(dpi_),
      static_cast<double>(desired_dpi));
    page_measurements.page_width = ConvertUnitDouble(
      static_cast<double>(physical_size_pixels.width()),
      static_cast<double>(dpi_),
      static_cast<double>(desired_dpi));
    if (landscape) {
      double temp = page_measurements.page_length;
      page_measurements.page_length = page_measurements.page_width;
      page_measurements.page_width = temp;
    }

  }
  SetPrinterPrintableArea(physical_size_pixels, printable_area_pixels);
}
#endif

void PrintSettings::SetPrinterPrintableArea(
    gfx::Size const& physical_size_pixels,
    gfx::Rect const& printable_area_pixels) {

  // Hard-code text_height = 0.5cm = ~1/5 of inch
  const int text_height = ConvertUnit(500, kHundrethsMMPerInch, dpi_);

  // Start by setting the user configuration
  page_setup_pixels_.Init(physical_size_pixels,
                          printable_area_pixels,
                          text_height);

  // Now adjust requested margins to the appropriate dpi.
  PageMargins margins;
  margins.header = ConvertUnit(requested_margins.header, desired_dpi, dpi_);
  margins.footer = ConvertUnit(requested_margins.footer, desired_dpi, dpi_);
  margins.left = ConvertUnit(requested_margins.left, desired_dpi, dpi_);
  margins.top = ConvertUnit(requested_margins.top, desired_dpi, dpi_);
  margins.right = ConvertUnit(requested_margins.right, desired_dpi, dpi_);
  margins.bottom = ConvertUnit(requested_margins.bottom, desired_dpi, dpi_);
  page_setup_pixels_.SetRequestedMargins(margins);
}

void PrintSettings::RenderParams(PrintParams* params) const {
  DCHECK(params);
  params->printable_size.SetSize(page_setup_pixels_.content_area().width(),
                                 page_setup_pixels_.content_area().height());
  params->dpi = dpi_;
  // Currently hardcoded at 1.25. See PrintSettings' constructor.
  params->min_shrink = min_shrink;
  // Currently hardcoded at 2.0. See PrintSettings' constructor.
  params->max_shrink = max_shrink;
  // Currently hardcoded at 72dpi. See PrintSettings' constructor.
  params->desired_dpi = desired_dpi;
  // Always use an invalid cookie.
  params->document_cookie = 0;
  params->selection_only = selection_only;
  params->to_file = to_file;
}

bool PrintSettings::Equals(const PrintSettings& rhs) const {
  // Do not test the display device name (printer_name_) for equality since it
  // may sometimes be chopped off at 30 chars. As long as device_name is the
  // same, that's fine.
  return ranges == rhs.ranges &&
      min_shrink == rhs.min_shrink &&
      max_shrink == rhs.max_shrink &&
      desired_dpi == rhs.desired_dpi &&
      device_name_ == rhs.device_name_ &&
      page_setup_pixels_.Equals(rhs.page_setup_pixels_) &&
      dpi_ == rhs.dpi_ &&
      landscape == rhs.landscape &&
      page_measurements.Equals(rhs.page_measurements) &&
      requested_margins.Equals(rhs.requested_margins);
}

int PrintSettings::NewCookie() {
  // A cookie of 0 is used to mark a document as unassigned, count from 1.
  return cookie_seq.GetNext() + 1;
}

void PrintSettings::UpdatePrintOptions(cef_print_options_t& print_options) {

  print_options.page_orientation = (landscape) ? LANDSCAPE : PORTRAIT;
  print_options.paper_metrics.paper_type = page_measurements.page_type;

  if (page_measurements.page_type == PT_CUSTOM) {
    print_options.paper_metrics.length = ConvertUnitDouble(
      page_measurements.page_length, desired_dpi, 1);
    print_options.paper_metrics.width = ConvertUnitDouble(
      page_measurements.page_width, desired_dpi, 1);
  }
  print_options.paper_margins.left = ConvertUnitDouble(
      requested_margins.left, desired_dpi, 1);
  print_options.paper_margins.top = ConvertUnitDouble(
      requested_margins.top, desired_dpi, 1);
  print_options.paper_margins.right = ConvertUnitDouble(
      requested_margins.right, desired_dpi, 1);
  print_options.paper_margins.bottom = ConvertUnitDouble(
      requested_margins.bottom, desired_dpi, 1);
  print_options.paper_margins.header = ConvertUnitDouble(
      requested_margins.header, desired_dpi, 1);
  print_options.paper_margins.footer = ConvertUnitDouble(
      requested_margins.footer, desired_dpi, 1);
}
void PrintSettings::UpdateFromPrintOptions(const cef_print_options_t& print_options) {
  landscape = print_options.page_orientation == LANDSCAPE;
  page_measurements.page_type = print_options.paper_metrics.paper_type;
  if (page_measurements.page_type == PT_CUSTOM) {
    page_measurements.page_length = ConvertUnitDouble(
      print_options.paper_metrics.length, 1, desired_dpi);
    page_measurements.page_width = ConvertUnitDouble(
      print_options.paper_metrics.width, 1, desired_dpi);
  }
  requested_margins.left = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.left, 1, desired_dpi));
  requested_margins.top = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.top, 1, desired_dpi));
  requested_margins.right = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.right, 1, desired_dpi));
  requested_margins.bottom = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.bottom, 1, desired_dpi));
  requested_margins.header = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.header, 1, desired_dpi));
  requested_margins.footer = static_cast<int>(ConvertUnitDouble(
      print_options.paper_margins.footer, 1, desired_dpi));
}

}  // namespace printing

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc.
 *
 *   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 "executors.h"

#include <daemon/mcaudit.h>
#include <daemon/mcbp.h>
#include "engine_wrapper.h"
#include "utilities.h"

void dcp_open_executor(Cookie& cookie) {
    auto packet = cookie.getPacket(Cookie::PacketContent::Full);
    const auto* req = reinterpret_cast<const protocol_binary_request_dcp_open*>(
            packet.data());

    auto ret = cookie.swapAiostat(ENGINE_SUCCESS);

    auto& connection = cookie.getConnection();
    connection.enableDatatype(cb::mcbp::Feature::JSON);

    uint32_t flags = ntohl(req->message.body.flags);
    const bool dcpNotifier = (flags & DCP_OPEN_NOTIFIER) == DCP_OPEN_NOTIFIER;

    if (ret == ENGINE_SUCCESS) {
        cb::rbac::Privilege privilege = cb::rbac::Privilege::DcpProducer;
        if (dcpNotifier) {
            privilege = cb::rbac::Privilege::DcpConsumer;
        }

        ret = mcbp::checkPrivilege(cookie, privilege);

        const uint16_t nkey = ntohs(req->message.header.request.keylen);
        const uint32_t valuelen = ntohl(req->message.header.request.bodylen) -
                                  nkey - req->message.header.request.extlen;

        const auto* name =
                reinterpret_cast<const char*>(req->bytes + sizeof(req->bytes));

        auto dcpOpenFunc = [&]() -> ENGINE_ERROR_CODE {
            return dcpOpen(cookie,
                           req->message.header.request.opaque,
                           ntohl(req->message.body.seqno),
                           flags,
                           {name, nkey},
                           {req->bytes + sizeof(req->bytes) + nkey, valuelen});
        };

        // Collections Prototype: The following code allows the bucket to decide
        // if this stream should be forced to being collection aware. So we can
        // run with collections enabled, but with a non-collection bucket and a
        // collection bucket. This is only whilst collections are in development
        if (ret == ENGINE_SUCCESS) {
            ret = dcpOpenFunc();
            if (settings.isCollectionsPrototypeEnabled() &&
                ret == ENGINE_UNKNOWN_COLLECTION) {
                flags |= DCP_OPEN_COLLECTIONS;
                ret = dcpOpenFunc();
                LOG_INFO(
                        "{}: Retried DCP open with DCP_OPEN_COLLECTIONS ret:{}",
                        connection.getId(),
                        ret);
            }
        }
    }

    ret = connection.remapErrorCode(ret);
    switch (ret) {
    case ENGINE_SUCCESS: {
        const bool dcpXattrAware = (flags & DCP_OPEN_INCLUDE_XATTRS) != 0 &&
                                   connection.selectedBucketIsXattrEnabled();
        const bool dcpNoValue = (flags & DCP_OPEN_NO_VALUE) != 0;
        const bool dcpCollections = (flags & DCP_OPEN_COLLECTIONS) != 0;
        const bool dcpDeleteTimes =
                (flags & DCP_OPEN_INCLUDE_DELETE_TIMES) != 0;
        connection.setDcpXattrAware(dcpXattrAware);
        connection.setDcpNoValue(dcpNoValue);
        connection.setDcpCollectionAware(dcpCollections);
        connection.setDcpDeleteTimeEnabled(dcpDeleteTimes);

        unique_cJSON_ptr json(cJSON_CreateArray());
        const bool dcpProducer =
                (flags & DCP_OPEN_PRODUCER) == DCP_OPEN_PRODUCER;
        if (dcpProducer) {
            cJSON_AddItemToArray(json.get(), cJSON_CreateString("PRODUCER"));
        }

        if (dcpNotifier) {
            cJSON_AddItemToArray(json.get(), cJSON_CreateString("NOTIFIER"));
        }
        if (dcpXattrAware) {
            cJSON_AddItemToArray(json.get(),
                                 cJSON_CreateString("INCLUDE_XATTRS"));
        }
        if (dcpNoValue) {
            cJSON_AddItemToArray(json.get(), cJSON_CreateString("NO_VALUE"));
        }
        if (dcpCollections) {
            cJSON_AddItemToArray(json.get(), cJSON_CreateString("COLLECTIONS"));
        }
        if (dcpDeleteTimes) {
            cJSON_AddItemToArray(json.get(),
                                 cJSON_CreateString("DELETE_TIMES"));
        }
        LOG_INFO("{}: DCP connection opened successfully. flags:{} {}",
                 connection.getId(),
                 to_string(json, false),
                 connection.getDescription().c_str());

        audit_dcp_open(&connection);
        cookie.sendResponse(cb::mcbp::Status::Success);
        break;
    }

    case ENGINE_DISCONNECT:
        connection.setState(McbpStateMachine::State::closing);
        break;

    case ENGINE_EWOULDBLOCK:
        cookie.setEwouldblock(true);
        break;

    default:
        cookie.sendResponse(cb::engine_errc(ret));
    }
}
<commit_msg>MB-26040: DCP conn opened log formatting<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc.
 *
 *   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 "executors.h"

#include <daemon/mcaudit.h>
#include <daemon/mcbp.h>
#include <string>
#include "engine_wrapper.h"
#include "utilities.h"

void dcp_open_executor(Cookie& cookie) {
    auto packet = cookie.getPacket(Cookie::PacketContent::Full);
    const auto* req = reinterpret_cast<const protocol_binary_request_dcp_open*>(
            packet.data());

    auto ret = cookie.swapAiostat(ENGINE_SUCCESS);

    auto& connection = cookie.getConnection();
    connection.enableDatatype(cb::mcbp::Feature::JSON);

    uint32_t flags = ntohl(req->message.body.flags);
    const bool dcpNotifier = (flags & DCP_OPEN_NOTIFIER) == DCP_OPEN_NOTIFIER;

    if (ret == ENGINE_SUCCESS) {
        cb::rbac::Privilege privilege = cb::rbac::Privilege::DcpProducer;
        if (dcpNotifier) {
            privilege = cb::rbac::Privilege::DcpConsumer;
        }

        ret = mcbp::checkPrivilege(cookie, privilege);

        const uint16_t nkey = ntohs(req->message.header.request.keylen);
        const uint32_t valuelen = ntohl(req->message.header.request.bodylen) -
                                  nkey - req->message.header.request.extlen;

        const auto* name =
                reinterpret_cast<const char*>(req->bytes + sizeof(req->bytes));

        auto dcpOpenFunc = [&]() -> ENGINE_ERROR_CODE {
            return dcpOpen(cookie,
                           req->message.header.request.opaque,
                           ntohl(req->message.body.seqno),
                           flags,
                           {name, nkey},
                           {req->bytes + sizeof(req->bytes) + nkey, valuelen});
        };

        // Collections Prototype: The following code allows the bucket to decide
        // if this stream should be forced to being collection aware. So we can
        // run with collections enabled, but with a non-collection bucket and a
        // collection bucket. This is only whilst collections are in development
        if (ret == ENGINE_SUCCESS) {
            ret = dcpOpenFunc();
            if (settings.isCollectionsPrototypeEnabled() &&
                ret == ENGINE_UNKNOWN_COLLECTION) {
                flags |= DCP_OPEN_COLLECTIONS;
                ret = dcpOpenFunc();
                LOG_INFO(
                        "{}: Retried DCP open with DCP_OPEN_COLLECTIONS ret:{}",
                        connection.getId(),
                        ret);
            }
        }
    }

    ret = connection.remapErrorCode(ret);
    switch (ret) {
    case ENGINE_SUCCESS: {
        const bool dcpXattrAware = (flags & DCP_OPEN_INCLUDE_XATTRS) != 0 &&
                                   connection.selectedBucketIsXattrEnabled();
        const bool dcpNoValue = (flags & DCP_OPEN_NO_VALUE) != 0;
        const bool dcpCollections = (flags & DCP_OPEN_COLLECTIONS) != 0;
        const bool dcpDeleteTimes =
                (flags & DCP_OPEN_INCLUDE_DELETE_TIMES) != 0;
        connection.setDcpXattrAware(dcpXattrAware);
        connection.setDcpNoValue(dcpNoValue);
        connection.setDcpCollectionAware(dcpCollections);
        connection.setDcpDeleteTimeEnabled(dcpDeleteTimes);

        // String buffer with max length = total length of all possible contents
        std::string logBuffer;

        const bool dcpProducer =
                (flags & DCP_OPEN_PRODUCER) == DCP_OPEN_PRODUCER;
        if (dcpProducer) {
            logBuffer.append("PRODUCER, ");
        }
        if (dcpNotifier) {
            logBuffer.append("NOTIFIER, ");
        }
        if (dcpXattrAware) {
            logBuffer.append("INCLUDE_XATTRS, ");
        }
        if (dcpNoValue) {
            logBuffer.append("NO_VALUE, ");
        }
        if (dcpCollections) {
            logBuffer.append("COLLECTIONS, ");
        }
        if (dcpDeleteTimes) {
            logBuffer.append("DELETE_TIMES, ");
        }

        // Remove trailing whitespace and comma
        if (!logBuffer.empty()) {
            logBuffer.resize(logBuffer.size() - 2);
        }

        LOG_INFO("{}: DCP connection opened successfully. {} {}",
                 connection.getId(),
                 logBuffer,
                 connection.getDescription().c_str());

        audit_dcp_open(&connection);
        cookie.sendResponse(cb::mcbp::Status::Success);
        break;
    }

    case ENGINE_DISCONNECT:
        connection.setState(McbpStateMachine::State::closing);
        break;

    case ENGINE_EWOULDBLOCK:
        cookie.setEwouldblock(true);
        break;

    default:
        cookie.sendResponse(cb::engine_errc(ret));
    }
}
<|endoftext|>


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

#include "cppqc/Generator.h"
#include "cppqc/Arbitrary.h"

#include <map>
#include <boost/bind.hpp>
#include <boost/assign/list_of.hpp>

using namespace cppqc;

namespace std {
    template<class T1, class T2>
    std::ostream &operator<<(std::ostream &out, const std::pair<T1, T2> &x)
    {
        return out << '(' << x.first << ',' << x.second << ')';
    }
}

const std::map<std::string, boost::function<void ()> >
sampleShrinkOutputCommand = boost::assign::map_list_of<std::string, boost::function<void ()> >
("bool",           boost::bind(sampleShrinkOutput<bool>,                Arbitrary<bool>(),                boost::ref(std::cout), 0, false, 0))
("char",           boost::bind(sampleShrinkOutput<char>,                Arbitrary<char>(),                boost::ref(std::cout), 0, false, 0))
("wchar_t",        boost::bind(sampleShrinkOutput<wchar_t>,             Arbitrary<wchar_t>(),             boost::ref(std::cout), 0, false, 0))
("signed char",    boost::bind(sampleShrinkOutput<signed char>,         Arbitrary<signed char>(),         boost::ref(std::cout), 0, false, 0))
("unsigned char",  boost::bind(sampleShrinkOutput<unsigned char>,       Arbitrary<unsigned char>(),       boost::ref(std::cout), 0, false, 0))
("short",          boost::bind(sampleShrinkOutput<short>,               Arbitrary<short>(),               boost::ref(std::cout), 0, false, 0))
("signed short",   boost::bind(sampleShrinkOutput<signed short>,        Arbitrary<signed short>(),        boost::ref(std::cout), 0, false, 0))
("unsigned short", boost::bind(sampleShrinkOutput<unsigned short>,      Arbitrary<unsigned short>(),      boost::ref(std::cout), 0, false, 0))
("int",            boost::bind(sampleShrinkOutput<int>,                 Arbitrary<int>(),                 boost::ref(std::cout), 0, false, 0))
("signed",         boost::bind(sampleShrinkOutput<signed>,              Arbitrary<signed>(),              boost::ref(std::cout), 0, false, 0))
("unsigned",       boost::bind(sampleShrinkOutput<unsigned>,            Arbitrary<unsigned>(),            boost::ref(std::cout), 0, false, 0))
("signed int",     boost::bind(sampleShrinkOutput<signed int>,          Arbitrary<signed int>(),          boost::ref(std::cout), 0, false, 0))
("unsigned int",   boost::bind(sampleShrinkOutput<unsigned int>,        Arbitrary<unsigned int>(),        boost::ref(std::cout), 0, false, 0))
("long",           boost::bind(sampleShrinkOutput<long>,                Arbitrary<long>(),                boost::ref(std::cout), 0, false, 0))
("signed long",    boost::bind(sampleShrinkOutput<signed long>,         Arbitrary<signed long>(),         boost::ref(std::cout), 0, false, 0))
("unsigned long",  boost::bind(sampleShrinkOutput<unsigned long>,       Arbitrary<unsigned long>(),       boost::ref(std::cout), 0, false, 0))
("float",          boost::bind(sampleShrinkOutput<float>,               Arbitrary<float>(),               boost::ref(std::cout), 0, false, 0))
("double",         boost::bind(sampleShrinkOutput<double>,              Arbitrary<double>(),              boost::ref(std::cout), 0, false, 0))
("long double",    boost::bind(sampleShrinkOutput<long double>,         Arbitrary<long double>(),         boost::ref(std::cout), 0, false, 0))
("pair",           boost::bind(sampleShrinkOutput<std::pair<int,int> >, Arbitrary<std::pair<int,int> >(), boost::ref(std::cout), 0, false, 0))
("string",         boost::bind(sampleShrinkOutput<std::string>,         Arbitrary<std::string>(),         boost::ref(std::cout), 0, false, 0));

int main(int argc, char **argv)
{
    for (int i = 1; i < argc; ++i) {
        std::map<std::string, boost::function<void ()> >::const_iterator it =
            sampleShrinkOutputCommand.find(argv[i]);
        if (it != sampleShrinkOutputCommand.end())
            it->second();
        else
            std::cout << "unrecognized type \"" << argv[i] << "\"\n";
    }
}
<commit_msg>Make the sample shrinks use randomized output<commit_after>/*
 * Copyright (c) 2010, Gregory Rogers All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "cppqc/Generator.h"
#include "cppqc/Arbitrary.h"

#include <map>
#include <boost/bind.hpp>
#include <boost/assign/list_of.hpp>

using namespace cppqc;

namespace std {
    template<class T1, class T2>
    std::ostream &operator<<(std::ostream &out, const std::pair<T1, T2> &x)
    {
        return out << '(' << x.first << ',' << x.second << ')';
    }
}

const std::map<std::string, boost::function<void ()> >
sampleShrinkOutputCommand = boost::assign::map_list_of<std::string, boost::function<void ()> >
("bool",           boost::bind(sampleShrinkOutput<bool>,                Arbitrary<bool>(),                boost::ref(std::cout), 0, true, 0))
("char",           boost::bind(sampleShrinkOutput<char>,                Arbitrary<char>(),                boost::ref(std::cout), 0, true, 0))
("wchar_t",        boost::bind(sampleShrinkOutput<wchar_t>,             Arbitrary<wchar_t>(),             boost::ref(std::cout), 0, true, 0))
("signed char",    boost::bind(sampleShrinkOutput<signed char>,         Arbitrary<signed char>(),         boost::ref(std::cout), 0, true, 0))
("unsigned char",  boost::bind(sampleShrinkOutput<unsigned char>,       Arbitrary<unsigned char>(),       boost::ref(std::cout), 0, true, 0))
("short",          boost::bind(sampleShrinkOutput<short>,               Arbitrary<short>(),               boost::ref(std::cout), 0, true, 0))
("signed short",   boost::bind(sampleShrinkOutput<signed short>,        Arbitrary<signed short>(),        boost::ref(std::cout), 0, true, 0))
("unsigned short", boost::bind(sampleShrinkOutput<unsigned short>,      Arbitrary<unsigned short>(),      boost::ref(std::cout), 0, true, 0))
("int",            boost::bind(sampleShrinkOutput<int>,                 Arbitrary<int>(),                 boost::ref(std::cout), 0, true, 0))
("signed",         boost::bind(sampleShrinkOutput<signed>,              Arbitrary<signed>(),              boost::ref(std::cout), 0, true, 0))
("unsigned",       boost::bind(sampleShrinkOutput<unsigned>,            Arbitrary<unsigned>(),            boost::ref(std::cout), 0, true, 0))
("signed int",     boost::bind(sampleShrinkOutput<signed int>,          Arbitrary<signed int>(),          boost::ref(std::cout), 0, true, 0))
("unsigned int",   boost::bind(sampleShrinkOutput<unsigned int>,        Arbitrary<unsigned int>(),        boost::ref(std::cout), 0, true, 0))
("long",           boost::bind(sampleShrinkOutput<long>,                Arbitrary<long>(),                boost::ref(std::cout), 0, true, 0))
("signed long",    boost::bind(sampleShrinkOutput<signed long>,         Arbitrary<signed long>(),         boost::ref(std::cout), 0, true, 0))
("unsigned long",  boost::bind(sampleShrinkOutput<unsigned long>,       Arbitrary<unsigned long>(),       boost::ref(std::cout), 0, true, 0))
("float",          boost::bind(sampleShrinkOutput<float>,               Arbitrary<float>(),               boost::ref(std::cout), 0, true, 0))
("double",         boost::bind(sampleShrinkOutput<double>,              Arbitrary<double>(),              boost::ref(std::cout), 0, true, 0))
("long double",    boost::bind(sampleShrinkOutput<long double>,         Arbitrary<long double>(),         boost::ref(std::cout), 0, true, 0))
("pair",           boost::bind(sampleShrinkOutput<std::pair<int,int> >, Arbitrary<std::pair<int,int> >(), boost::ref(std::cout), 0, true, 0))
("string",         boost::bind(sampleShrinkOutput<std::string>,         Arbitrary<std::string>(),         boost::ref(std::cout), 0, true, 0));

int main(int argc, char **argv)
{
    for (int i = 1; i < argc; ++i) {
        std::map<std::string, boost::function<void ()> >::const_iterator it =
            sampleShrinkOutputCommand.find(argv[i]);
        if (it != sampleShrinkOutputCommand.end())
            it->second();
        else
            std::cout << "unrecognized type \"" << argv[i] << "\"\n";
    }
}
<|endoftext|>


<commit_before>/**
 * \file
 * Copyright 2014-2015 Benjamin Worpitz
 *
 * This file is part of alpaka.
 *
 * alpaka is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * alpaka is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with alpaka.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include <alpaka/alpaka.hpp>                        // alpaka::exec::create
#include <alpaka/examples/MeasureKernelRunTime.hpp> // measureKernelRunTimeMs
#include <alpaka/examples/accs/EnabledAccs.hpp>     // EnabledAccs

#include <chrono>                                   // std::chrono::high_resolution_clock
#include <cassert>                                  // assert
#include <iostream>                                 // std::cout
#include <typeinfo>                                 // typeid
#include <utility>                                  // std::forward

//#############################################################################
//! A vector addition kernel.
//! \tparam TAcc The accelerator environment to be executed on.
//#############################################################################
class VectorAddKernel
{
public:
    //-----------------------------------------------------------------------------
    //! The kernel entry point.
    //!
    //! \tparam TElem The matrix element type.
    //! \param acc The accelerator to be executed on.
    //! \param A The first source vector.
    //! \param B The second source vector.
    //! \param C The destination vector.
    //! \param numElements The number of elements.
    //-----------------------------------------------------------------------------
    ALPAKA_NO_HOST_ACC_WARNING
    template<
        typename TAcc,
        typename TElem,
        typename TSize>
    ALPAKA_FN_ACC auto operator()(
        TAcc const & acc,
        TElem const * const A,
        TElem const * const B,
        TElem * const C,
        TSize const & numElements) const
    -> void
    {
        static_assert(
            alpaka::dim::Dim<TAcc>::value == 1,
            "The VectorAddKernel expects 1-dimensional indices!");

        auto const gridThreadIdxX(alpaka::idx::getIdx<alpaka::Grid, alpaka::Threads>(acc)[0u]);

        if(gridThreadIdxX < numElements)
        {
            C[gridThreadIdxX] = A[gridThreadIdxX] + B[gridThreadIdxX];
        }
    }
};

//#############################################################################
//! Profiles the vector addition kernel.
//#############################################################################
struct VectorAddKernelTester
{
    template<
        typename TAcc,
        typename TSize>
    auto operator()(
        TSize const & numElements)
    -> void
    {
        std::cout << std::endl;
        std::cout << "################################################################################" << std::endl;

        using Val = float;

        // Create the kernel function object.
        VectorAddKernel kernel;

        // Get the host device.
        auto devHost(alpaka::dev::cpu::getDev());

        // Select a device to execute on.
        alpaka::dev::Dev<TAcc> devAcc(
            alpaka::dev::DevMan<TAcc>::getDevByIdx(0));

        // Get a stream on this device.
        alpaka::examples::Stream<alpaka::dev::Dev<TAcc>> stream(devAcc);

        alpaka::Vec<alpaka::dim::DimInt<1u>, TSize> const extent(
            numElements);

        // Let alpaka calculate good block and grid sizes given our full problem extent.
        alpaka::workdiv::WorkDivMembers<alpaka::dim::DimInt<1u>, TSize> const workDiv(
            alpaka::workdiv::getValidWorkDiv<TAcc>(
                devAcc,
                extent,
                static_cast<TSize>(1u),
                false,
                alpaka::workdiv::GridBlockExtentSubDivRestrictions::Unrestricted));

        std::cout
            << "VectorAddKernelTester("
            << " numElements:" << numElements
            << ", accelerator: " << alpaka::acc::getAccName<TAcc>()
            << ", kernel: " << typeid(kernel).name()
            << ", workDiv: " << workDiv
            << ")" << std::endl;

        // Allocate host memory buffers.
        auto memBufHostA(alpaka::mem::buf::alloc<Val, TSize>(devHost, extent));
        auto memBufHostB(alpaka::mem::buf::alloc<Val, TSize>(devHost, extent));
        auto memBufHostC(alpaka::mem::buf::alloc<Val, TSize>(devHost, extent));

        // Initialize the host input vectors
        for (TSize i(0); i < numElements; ++i)
        {
            alpaka::mem::view::getPtrNative(memBufHostA)[i] = static_cast<Val>(rand());
            alpaka::mem::view::getPtrNative(memBufHostB)[i] = static_cast<Val>(rand());
        }

        // Allocate the buffer on the accelerator.
        auto memBufAccA(alpaka::mem::buf::alloc<Val, TSize>(devAcc, extent));
        auto memBufAccB(alpaka::mem::buf::alloc<Val, TSize>(devAcc, extent));
        auto memBufAccC(alpaka::mem::buf::alloc<Val, TSize>(devAcc, extent));

        // Copy Host -> Acc.
        alpaka::mem::view::copy(stream, memBufAccA, memBufHostA, extent);
        alpaka::mem::view::copy(stream, memBufAccB, memBufHostB, extent);

        // Create the executor task.
        auto const exec(alpaka::exec::create<TAcc>(
            workDiv,
            kernel,
            alpaka::mem::view::getPtrNative(memBufAccA),
            alpaka::mem::view::getPtrNative(memBufAccB),
            alpaka::mem::view::getPtrNative(memBufAccC),
            numElements));

        // Profile the kernel execution.
        std::cout << "Execution time: "
            << alpaka::examples::measureKernelRunTimeMs(
                stream,
                exec)
            << " ms"
            << std::endl;

        // Copy back the result.
        alpaka::mem::view::copy(stream, memBufHostC, memBufAccC, extent);

        // Wait for the stream to finish the memory operation.
        alpaka::wait::wait(stream);

        bool resultCorrect(true);
        auto const pHostData(alpaka::mem::view::getPtrNative(memBufHostC));
        for(TSize i(0u);
            i < numElements;
            ++i)
        {
            auto const & val(pHostData[i]);
            auto const correctResult(alpaka::mem::view::getPtrNative(memBufHostA)[i]+alpaka::mem::view::getPtrNative(memBufHostB)[i]);
            if(val != correctResult)
            {
                std::cout << "C[" << i << "] == " << val << " != " << correctResult << std::endl;
                resultCorrect = false;
            }
        }

        if(resultCorrect)
        {
            std::cout << "Execution results correct!" << std::endl;
        }

        std::cout << "################################################################################" << std::endl;

        allResultsCorrect = allResultsCorrect && resultCorrect;
    }

public:
    bool allResultsCorrect = true;
};

//-----------------------------------------------------------------------------
//! Program entry point.
//-----------------------------------------------------------------------------
auto main()
-> int
{
    try
    {
        std::cout << std::endl;
        std::cout << "################################################################################" << std::endl;
        std::cout << "                            alpaka vector add test                              " << std::endl;
        std::cout << "################################################################################" << std::endl;
        std::cout << std::endl;

        // Logs the enabled accelerators.
        alpaka::examples::accs::writeEnabledAccs<alpaka::dim::DimInt<1u>, std::size_t>(std::cout);

        std::cout << std::endl;

        VectorAddKernelTester vectorAddKernelTester;

        // For different sizes.
#if ALPAKA_INTEGRATION_TEST
        for(std::size_t vecSize(1u); vecSize <= 1u<<9u; vecSize *= 8u)
#else
        for(std::size_t vecSize(1u); vecSize <= 1u<<16u; vecSize *= 2u)
#endif
        {
            std::cout << std::endl;

            // Execute the kernel on all enabled accelerators.
            alpaka::core::forEachType<
                alpaka::examples::accs::EnabledAccs<alpaka::dim::DimInt<1u>, std::size_t>>(
                    vectorAddKernelTester,
                    vecSize);
        }
        return EXIT_SUCCESS;
    }
    catch(std::exception const & e)
    {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    catch(...)
    {
        std::cerr << "Unknown Exception" << std::endl;
        return EXIT_FAILURE;
    }
}
<commit_msg>calculate 3 elements per thread in vecAdd example<commit_after>/**
 * \file
 * Copyright 2014-2015 Benjamin Worpitz
 *
 * This file is part of alpaka.
 *
 * alpaka is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * alpaka is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with alpaka.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include <alpaka/alpaka.hpp>                        // alpaka::exec::create
#include <alpaka/examples/MeasureKernelRunTime.hpp> // measureKernelRunTimeMs
#include <alpaka/examples/accs/EnabledAccs.hpp>     // EnabledAccs

#include <chrono>                                   // std::chrono::high_resolution_clock
#include <cassert>                                  // assert
#include <iostream>                                 // std::cout
#include <typeinfo>                                 // typeid
#include <utility>                                  // std::forward

//#############################################################################
//! A vector addition kernel.
//! \tparam TAcc The accelerator environment to be executed on.
//#############################################################################
class VectorAddKernel
{
public:
    //-----------------------------------------------------------------------------
    //! The kernel entry point.
    //!
    //! \tparam TElem The matrix element type.
    //! \param acc The accelerator to be executed on.
    //! \param A The first source vector.
    //! \param B The second source vector.
    //! \param C The destination vector.
    //! \param numElements The number of elements.
    //-----------------------------------------------------------------------------
    ALPAKA_NO_HOST_ACC_WARNING
    template<
        typename TAcc,
        typename TElem,
        typename TSize>
    ALPAKA_FN_ACC auto operator()(
        TAcc const & acc,
        TElem const * const A,
        TElem const * const B,
        TElem * const C,
        TSize const & numElements) const
    -> void
    {
        static_assert(
            alpaka::dim::Dim<TAcc>::value == 1,
            "The VectorAddKernel expects 1-dimensional indices!");

        auto const gridThreadIdx(alpaka::idx::getIdx<alpaka::Grid, alpaka::Threads>(acc)[0u]);
        auto const threadElemExtent(alpaka::workdiv::getWorkDiv<alpaka::Thread, alpaka::Elems>(acc)[0u]);
        auto const threadFirstElemIdx(gridThreadIdx * threadElemExtent);

        if(threadFirstElemIdx < numElements)
        {
            // Calculate the number of elements to compute in this thread.
            // The result is uniform for all but the last thread.
            auto const elems(threadElemExtent + alpaka::math::min(acc, static_cast<unsigned long long>(0u), static_cast<unsigned long long>(numElements-(threadFirstElemIdx+threadElemExtent))));

            for(TSize i(threadFirstElemIdx); i<(threadFirstElemIdx+elems); ++i)
            {
                C[gridThreadIdx] = A[gridThreadIdx] + B[gridThreadIdx];
            }
        }
    }
};

//#############################################################################
//! Profiles the vector addition kernel.
//#############################################################################
struct VectorAddKernelTester
{
    template<
        typename TAcc,
        typename TSize>
    auto operator()(
        TSize const & numElements)
    -> void
    {
        std::cout << std::endl;
        std::cout << "################################################################################" << std::endl;

        using Val = float;

        // Create the kernel function object.
        VectorAddKernel kernel;

        // Get the host device.
        auto devHost(alpaka::dev::cpu::getDev());

        // Select a device to execute on.
        alpaka::dev::Dev<TAcc> devAcc(
            alpaka::dev::DevMan<TAcc>::getDevByIdx(0));

        // Get a stream on this device.
        alpaka::examples::Stream<alpaka::dev::Dev<TAcc>> stream(devAcc);

        alpaka::Vec<alpaka::dim::DimInt<1u>, TSize> const extent(
            numElements);

        // Let alpaka calculate good block and grid sizes given our full problem extent.
        alpaka::workdiv::WorkDivMembers<alpaka::dim::DimInt<1u>, TSize> const workDiv(
            alpaka::workdiv::getValidWorkDiv<TAcc>(
                devAcc,
                extent,
                static_cast<TSize>(3u),
                false,
                alpaka::workdiv::GridBlockExtentSubDivRestrictions::Unrestricted));

        std::cout
            << "VectorAddKernelTester("
            << " numElements:" << numElements
            << ", accelerator: " << alpaka::acc::getAccName<TAcc>()
            << ", kernel: " << typeid(kernel).name()
            << ", workDiv: " << workDiv
            << ")" << std::endl;

        // Allocate host memory buffers.
        auto memBufHostA(alpaka::mem::buf::alloc<Val, TSize>(devHost, extent));
        auto memBufHostB(alpaka::mem::buf::alloc<Val, TSize>(devHost, extent));
        auto memBufHostC(alpaka::mem::buf::alloc<Val, TSize>(devHost, extent));

        // Initialize the host input vectors
        for (TSize i(0); i < numElements; ++i)
        {
            alpaka::mem::view::getPtrNative(memBufHostA)[i] = static_cast<Val>(rand());
            alpaka::mem::view::getPtrNative(memBufHostB)[i] = static_cast<Val>(rand());
        }

        // Allocate the buffer on the accelerator.
        auto memBufAccA(alpaka::mem::buf::alloc<Val, TSize>(devAcc, extent));
        auto memBufAccB(alpaka::mem::buf::alloc<Val, TSize>(devAcc, extent));
        auto memBufAccC(alpaka::mem::buf::alloc<Val, TSize>(devAcc, extent));

        // Copy Host -> Acc.
        alpaka::mem::view::copy(stream, memBufAccA, memBufHostA, extent);
        alpaka::mem::view::copy(stream, memBufAccB, memBufHostB, extent);

        // Create the executor task.
        auto const exec(alpaka::exec::create<TAcc>(
            workDiv,
            kernel,
            alpaka::mem::view::getPtrNative(memBufAccA),
            alpaka::mem::view::getPtrNative(memBufAccB),
            alpaka::mem::view::getPtrNative(memBufAccC),
            numElements));

        // Profile the kernel execution.
        std::cout << "Execution time: "
            << alpaka::examples::measureKernelRunTimeMs(
                stream,
                exec)
            << " ms"
            << std::endl;

        // Copy back the result.
        alpaka::mem::view::copy(stream, memBufHostC, memBufAccC, extent);

        // Wait for the stream to finish the memory operation.
        alpaka::wait::wait(stream);

        bool resultCorrect(true);
        auto const pHostData(alpaka::mem::view::getPtrNative(memBufHostC));
        for(TSize i(0u);
            i < numElements;
            ++i)
        {
            auto const & val(pHostData[i]);
            auto const correctResult(alpaka::mem::view::getPtrNative(memBufHostA)[i]+alpaka::mem::view::getPtrNative(memBufHostB)[i]);
            if(val != correctResult)
            {
                std::cout << "C[" << i << "] == " << val << " != " << correctResult << std::endl;
                resultCorrect = false;
            }
        }

        if(resultCorrect)
        {
            std::cout << "Execution results correct!" << std::endl;
        }

        std::cout << "################################################################################" << std::endl;

        allResultsCorrect = allResultsCorrect && resultCorrect;
    }

public:
    bool allResultsCorrect = true;
};

//-----------------------------------------------------------------------------
//! Program entry point.
//-----------------------------------------------------------------------------
auto main()
-> int
{
    try
    {
        std::cout << std::endl;
        std::cout << "################################################################################" << std::endl;
        std::cout << "                            alpaka vector add test                              " << std::endl;
        std::cout << "################################################################################" << std::endl;
        std::cout << std::endl;

        // Logs the enabled accelerators.
        alpaka::examples::accs::writeEnabledAccs<alpaka::dim::DimInt<1u>, std::size_t>(std::cout);

        std::cout << std::endl;

        VectorAddKernelTester vectorAddKernelTester;

        // For different sizes.
#if ALPAKA_INTEGRATION_TEST
        for(std::size_t vecSize(1u); vecSize <= 1u<<9u; vecSize *= 8u)
#else
        for(std::size_t vecSize(1u); vecSize <= 1u<<16u; vecSize *= 2u)
#endif
        {
            std::cout << std::endl;

            // Execute the kernel on all enabled accelerators.
            alpaka::core::forEachType<
                alpaka::examples::accs::EnabledAccs<alpaka::dim::DimInt<1u>, std::size_t>>(
                    vectorAddKernelTester,
                    vecSize);
        }
        return EXIT_SUCCESS;
    }
    catch(std::exception const & e)
    {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    catch(...)
    {
        std::cerr << "Unknown Exception" << std::endl;
        return EXIT_FAILURE;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 * 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 <string.h>
#include <stdarg.h>
#include <stdio.h>

#include "ns_types.h"
#include "eventOS_event.h"
#include "eventOS_event_timer.h"
#include "net_interface.h"
#include "socket_api.h"
#include "socket_security.h"
#include "mbed-trace/mbed_trace.h"
#include "common_functions.h"

#include "ns_cmdline.h"
#include "cmd_commands.h"
#include "cmd_lwm2m.h"

#define TRACE_GROUP "cApp"

#define ESC 0x03
#define EVENT_DATA_COMMAND_EXECUTED 6

// Prototypes
void cmd_ready_cb(int retcode);

static void cmdline_event(arm_event_s *event);

/**
* Callback function for thread handling.
*/
void* __thread_poll_function(void*);

typedef struct {
  uint8_t tasklet_id;
} cmd_commands_t;

cmd_commands_t  cmd_commands;
pthread_t       input_thread; /* Thread for input_terminal-function */

void initialize_app_commands(int8_t /*rf_driver_id*/)
{
  //initialize ready cb
  cmd_set_ready_cb( cmd_ready_cb );
  lwm2m_command_init();

  cmd_commands.tasklet_id = eventOS_event_handler_create(&cmdline_event, EVENT_TYPE_CMDLINE);
  pthread_create(&input_thread, NULL,__thread_poll_function, NULL);
}

void cmd_ready_cb(int retcode)
{
  tr_debug("cmd_ready_cb(%d)", retcode);
  arm_event_s event;
  event.sender = cmd_commands.tasklet_id;
  event.receiver = cmd_commands.tasklet_id;
  event.event_type = APPLICATION_EVENT;
  event.event_id = EVENT_DATA_COMMAND_EXECUTED;
  event.event_data = retcode;
  eventOS_event_send(&event);
}

static void cmdline_event(arm_event_s *event)
{
    switch( event->event_type )
    {
        case ARM_LIB_TASKLET_INIT_EVENT:
            //tasklet up and running
            tr_warning("cmdline_event-ARM_LIB_TASKLET_INIT_EVENT");
            break;

        case APPLICATION_EVENT:
            if( event->event_id == EVENT_DATA_COMMAND_EXECUTED )
            {
                int retcode = event->event_data;
                cmd_next( retcode );
            }
            break;
        default:
            tr_warning("Unknown event type (type: %i, id: %i)", event->event_type, event->event_id);
        break;
    }
}

void* __thread_poll_function(void*)
{
    int16_t c = getchar();
    while( c >= 0 ) {
        cmd_char_input(c);
        c = getchar();
    }
    return NULL;
}
<commit_msg>Remove inclusion of obsolete socket_security.h<commit_after>/*
 * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 * 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 <string.h>
#include <stdarg.h>
#include <stdio.h>

#include "ns_types.h"
#include "eventOS_event.h"
#include "eventOS_event_timer.h"
#include "net_interface.h"
#include "socket_api.h"
#include "mbed-trace/mbed_trace.h"
#include "common_functions.h"

#include "ns_cmdline.h"
#include "cmd_commands.h"
#include "cmd_lwm2m.h"

#define TRACE_GROUP "cApp"

#define ESC 0x03
#define EVENT_DATA_COMMAND_EXECUTED 6

// Prototypes
void cmd_ready_cb(int retcode);

static void cmdline_event(arm_event_s *event);

/**
* Callback function for thread handling.
*/
void* __thread_poll_function(void*);

typedef struct {
  uint8_t tasklet_id;
} cmd_commands_t;

cmd_commands_t  cmd_commands;
pthread_t       input_thread; /* Thread for input_terminal-function */

void initialize_app_commands(int8_t /*rf_driver_id*/)
{
  //initialize ready cb
  cmd_set_ready_cb( cmd_ready_cb );
  lwm2m_command_init();

  cmd_commands.tasklet_id = eventOS_event_handler_create(&cmdline_event, EVENT_TYPE_CMDLINE);
  pthread_create(&input_thread, NULL,__thread_poll_function, NULL);
}

void cmd_ready_cb(int retcode)
{
  tr_debug("cmd_ready_cb(%d)", retcode);
  arm_event_s event;
  event.sender = cmd_commands.tasklet_id;
  event.receiver = cmd_commands.tasklet_id;
  event.event_type = APPLICATION_EVENT;
  event.event_id = EVENT_DATA_COMMAND_EXECUTED;
  event.event_data = retcode;
  eventOS_event_send(&event);
}

static void cmdline_event(arm_event_s *event)
{
    switch( event->event_type )
    {
        case ARM_LIB_TASKLET_INIT_EVENT:
            //tasklet up and running
            tr_warning("cmdline_event-ARM_LIB_TASKLET_INIT_EVENT");
            break;

        case APPLICATION_EVENT:
            if( event->event_id == EVENT_DATA_COMMAND_EXECUTED )
            {
                int retcode = event->event_data;
                cmd_next( retcode );
            }
            break;
        default:
            tr_warning("Unknown event type (type: %i, id: %i)", event->event_type, event->event_id);
        break;
    }
}

void* __thread_poll_function(void*)
{
    int16_t c = getchar();
    while( c >= 0 ) {
        cmd_char_input(c);
        c = getchar();
    }
    return NULL;
}
<|endoftext|>