chromium/extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.cc

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

#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h"

#include <optional>
#include <string>
#include <utility>

#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "build/chromeos_buildflags.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
#include "extensions/common/api/virtual_keyboard_private.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/clipboard/clipboard_history_item.h"
#include "base/barrier_closure.h"
#include "base/task/thread_pool.h"
#include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/color/color_provider.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

namespace extensions {

namespace {

const char kNotYetImplementedError[] =;
const char kVirtualKeyboardNotEnabled[] =;
const char kSetDraggableAreaFailed[] =;
const char kSetAreaToRemainOnScreenFailed[] =;
const char kSetWindowBoundsInScreenFailed[] =;
const char kUnknownError[] =;

#if BUILDFLAG(IS_CHROMEOS_ASH)
const char kGetClipboardHistoryFailed[] =
    "Getting the clipboard history failed";
const char kPasteClipboardItemFailed[] = "Pasting the clipboard item failed";
const char kDeleteClipboardItemFailed[] = "Deleting the clipboard item failed";
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

keyboard;

gfx::Rect KeyboardBoundsToRect(const keyboard::Bounds& bounds) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
using extensions::api::virtual_keyboard_private::ClipboardItem;
using extensions::api::virtual_keyboard_private::DisplayFormat;

// Appends a new item based on `history_item` to the list that `item_ptr` points
// to. If the conversion requires a bitmap to be encoded, some of the work will
// happen asynchronously; regardless, `barrier_callback` will be signaled when
// the conversion finishes.
void ConvertClipboardHistoryItemToClipboardItem(
    base::OnceClosure barrier_callback,
    const ui::ColorProvider& color_provider,
    const ash::ClipboardHistoryItem& history_item,
    std::vector<ClipboardItem>* items_ptr) {
  // Populate all `ClipboardItem` fields except `image_data`.
  ClipboardItem item;
  item.id = history_item.id().ToString();
  item.time_copied =
      history_item.time_copied().InMillisecondsFSinceUnixEpochIgnoringNull();

  switch (history_item.display_format()) {
    case crosapi::mojom::ClipboardHistoryDisplayFormat::kUnknown:
      NOTREACHED();
    case crosapi::mojom::ClipboardHistoryDisplayFormat::kText:
      item.text_data = base::UTF16ToUTF8(history_item.display_text());
      item.display_format = DisplayFormat::kText;
      break;
    case crosapi::mojom::ClipboardHistoryDisplayFormat::kPng:
      item.display_format = DisplayFormat::kPng;
      break;
    case crosapi::mojom::ClipboardHistoryDisplayFormat::kHtml:
      item.display_format = DisplayFormat::kHtml;
      break;
    case crosapi::mojom::ClipboardHistoryDisplayFormat::kFile:
      DCHECK(!item.image_data.has_value());

      const auto& icon = history_item.icon();
      DCHECK(icon.has_value());

      item.image_data =
          webui::GetBitmapDataUrl(*icon->Rasterize(&color_provider).bitmap());
      item.text_data = base::UTF16ToUTF8(history_item.display_text());
      item.display_format = DisplayFormat::kFile;
      break;
  }

  items_ptr->push_back(std::move(item));

  // Getting a data URL for a bitmap can be time-intensive. Populate
  // `image_data` asynchronously if `history_item` has image data.
  if (const auto& maybe_image = history_item.display_image()) {
    const auto* const bitmap =
        maybe_image->IsVectorIcon()
            ? maybe_image->Rasterize(&color_provider).bitmap()
            : maybe_image->GetImage().ToSkBitmap();
    base::ThreadPool::PostTask(
        FROM_HERE,
        base::BindOnce(
            [](base::OnceClosure barrier_callback, ClipboardItem& item,
               const SkBitmap& bitmap) {
              item.image_data = webui::GetBitmapDataUrl(bitmap);
              std::move(barrier_callback).Run();
            },
            std::move(barrier_callback), std::ref(items_ptr->back()), *bitmap));
  } else {
    // Signal that the (non-existent) asynchronous conversion work is done.
    std::move(barrier_callback).Run();
  }
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace

bool VirtualKeyboardPrivateFunction::PreRunValidation(std::string* error) {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateInsertTextFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSendKeyEventFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateHideKeyboardFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetHotrodKeyboardFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateLockKeyboardFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateKeyboardLoadedFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateGetKeyboardConfigFunction::Run() {}

void VirtualKeyboardPrivateGetKeyboardConfigFunction::OnKeyboardConfig(
    std::optional<base::Value::Dict> results) {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateOpenSettingsFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateOpenSuggestionSettingsFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetContainerBehaviorFunction::Run() {}

void VirtualKeyboardPrivateSetContainerBehaviorFunction::OnSetContainerBehavior(
    bool success) {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetDraggableAreaFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetKeyboardStateFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetOccludedBoundsFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetHitTestBoundsFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetAreaToRemainOnScreenFunction::Run() {}

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateSetWindowBoundsInScreenFunction::Run() {}

VirtualKeyboardPrivateSetWindowBoundsInScreenFunction ::
    ~VirtualKeyboardPrivateSetWindowBoundsInScreenFunction() = default;

#if BUILDFLAG(IS_CHROMEOS_ASH)
ExtensionFunction::ResponseAction
VirtualKeyboardPrivateGetClipboardHistoryFunction::Run() {
  std::optional<keyboard::GetClipboardHistory::Params> params =
      keyboard::GetClipboardHistory::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);

  delegate()->GetClipboardHistory(base::BindOnce(
      &VirtualKeyboardPrivateGetClipboardHistoryFunction::OnGetClipboardHistory,
      this));
  return did_respond() ? AlreadyResponded() : RespondLater();
}

void VirtualKeyboardPrivateGetClipboardHistoryFunction::OnGetClipboardHistory(
    std::vector<ash::ClipboardHistoryItem> history_items) {
  const auto* web_contents = GetSenderWebContents();
  if (!web_contents) {
    Respond(Error(kGetClipboardHistoryFailed));
    return;
  }

  // Create a container for converted clipboard items.
  // NOTE: Reserving space for all items is necessary to ensure that each item
  // stays at its original memory address while `items` is being populated.
  auto items = std::make_unique<ClipboardItems>();
  items->reserve(history_items.size());
  auto* items_ptr = items.get();

  // Post back to this sequence once all items have been fully converted.
  base::RepeatingClosure barrier = base::BarrierClosure(
      history_items.size(),
      base::BindPostTaskToCurrentDefault(
          base::BindOnce(&VirtualKeyboardPrivateGetClipboardHistoryFunction::
                             OnClipboardHistoryItemsConverted,
                         this, std::move(items))));

  // Convert each `ClipboardHistoryItem` into a `ClipboardItem`. A response with
  // serialized items will be sent in `OnClipboardHistoryItemsConverted()`.
  for (const auto& history_item : history_items) {
    ConvertClipboardHistoryItemToClipboardItem(
        barrier, web_contents->GetColorProvider(), history_item, items_ptr);
  }
}

void VirtualKeyboardPrivateGetClipboardHistoryFunction::
    OnClipboardHistoryItemsConverted(std::unique_ptr<ClipboardItems> items) {
  base::Value::List results;
  for (const auto& item : *items) {
    results.Append(item.ToValue());
  }
  Respond(WithArguments(std::move(results)));
}

VirtualKeyboardPrivateGetClipboardHistoryFunction ::
    ~VirtualKeyboardPrivateGetClipboardHistoryFunction() = default;

ExtensionFunction::ResponseAction
VirtualKeyboardPrivatePasteClipboardItemFunction::Run() {
  std::optional<keyboard::PasteClipboardItem::Params> params =
      keyboard::PasteClipboardItem::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);

  if (!delegate()->PasteClipboardItem(params->item_id))
    return RespondNow(Error(kPasteClipboardItemFailed));
  return RespondNow(NoArguments());
}

VirtualKeyboardPrivatePasteClipboardItemFunction ::
    ~VirtualKeyboardPrivatePasteClipboardItemFunction() = default;

ExtensionFunction::ResponseAction
VirtualKeyboardPrivateDeleteClipboardItemFunction::Run() {
  std::optional<keyboard::DeleteClipboardItem::Params> params =
      keyboard::DeleteClipboardItem::Params::Create(args());
  EXTENSION_FUNCTION_VALIDATE(params);

  if (!delegate()->DeleteClipboardItem(params->item_id))
    return RespondNow(Error(kDeleteClipboardItemFailed));
  return RespondNow(NoArguments());
}

VirtualKeyboardPrivateDeleteClipboardItemFunction ::
    ~VirtualKeyboardPrivateDeleteClipboardItemFunction() = default;
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

VirtualKeyboardAPI::VirtualKeyboardAPI(content::BrowserContext* context) {}

VirtualKeyboardAPI::~VirtualKeyboardAPI() = default;

static base::LazyInstance<BrowserContextKeyedAPIFactory<VirtualKeyboardAPI>>::
    DestructorAtExit g_factory =;

// static
BrowserContextKeyedAPIFactory<VirtualKeyboardAPI>*
VirtualKeyboardAPI::GetFactoryInstance() {}

}  // namespace extensions