chromium/chromeos/ash/components/language_packs/handwriting.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/language_packs/handwriting.h"

#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/functional/callback.h"
#include "base/no_destructor.h"
#include "chromeos/ash/components/language_packs/language_pack_manager.h"
#include "chromeos/ash/components/language_packs/language_packs_util.h"
#include "ui/base/ime/ash/extension_ime_util.h"
#include "ui/base/ime/ash/input_method_manager.h"
#include "ui/base/ime/ash/input_method_util.h"

namespace ash::language_packs {

using ::ash::input_method::InputMethodManager;

// TODO: b/294162606 - Move this code to the input_method codebase.
std::optional<std::string> MapEngineIdToHandwritingLocale(
    input_method::InputMethodUtil* const util,
    const std::string& engine_id) {
  const std::string input_method_id =
      extension_ime_util::GetInputMethodIDByEngineID(engine_id);
  return MapInputMethodIdToHandwritingLocale(util, input_method_id);
}

// TODO: b/294162606 - Move this code to the input_method codebase.
std::optional<std::string> MapInputMethodIdToHandwritingLocale(
    input_method::InputMethodUtil* const util,
    const std::string& input_method_id) {
  const input_method::InputMethodDescriptor* descriptor =
      util->GetInputMethodDescriptorFromId(input_method_id);
  if (descriptor == nullptr) {
    return std::nullopt;
  }
  return descriptor->handwriting_language();
}

std::optional<std::string> HandwritingLocaleToDlc(std::string_view locale) {
  // TODO: b/285993323 - Replace this with a set lookup (to see if it is a valid
  // locale) and concatenation (to produce the DLC ID) to eventually deprecate
  // `GetAllLanguagePackDlcIds`.
  return GetDlcIdForLanguagePack(kHandwritingFeatureId, std::string(locale));
}

std::optional<std::string> DlcToHandwritingLocale(std::string_view dlc_id) {
  static const base::NoDestructor<
      const base::flat_map<std::string, std::string>>
      handwriting_locale_from_dlc([] {
        std::vector<std::pair<std::string, std::string>> handwriting_dlcs;

        const base::flat_map<PackSpecPair, std::string>& all_ids =
            GetAllLanguagePackDlcIds();

        // Relies on the fact that handwriting `PackSpecPair`s are "grouped
        // together" in the sorted `flat_map`.
        auto it = all_ids.upper_bound({kHandwritingFeatureId, ""});
        while (it != all_ids.end() &&
               it->first.feature_id == kHandwritingFeatureId) {
          handwriting_dlcs.emplace_back(it->second, it->first.locale);
          it++;
        }

        return handwriting_dlcs;
      }());

  auto it = handwriting_locale_from_dlc->find(dlc_id);
  if (it == handwriting_locale_from_dlc->end()) {
    return std::nullopt;
  }
  return it->second;
}

bool IsHandwritingDlc(std::string_view dlc_id) {
  return DlcToHandwritingLocale(dlc_id).has_value();
}

base::flat_set<std::string> ConvertDlcsWithContentToHandwritingLocales(
    const dlcservice::DlcsWithContent& dlcs_with_content) {
  std::vector<std::string> dlc_locales;

  for (const auto& dlc_info : dlcs_with_content.dlc_infos()) {
    const auto& locale = DlcToHandwritingLocale(dlc_info.id());
    if (locale.has_value()) {
      dlc_locales.push_back(*locale);
    }
  }

  return dlc_locales;
}

}  // namespace ash::language_packs