1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/flash_clipboard_resource.h"
6
7#include "ipc/ipc_message.h"
8#include "ppapi/c/pp_errors.h"
9#include "ppapi/proxy/ppapi_messages.h"
10#include "ppapi/shared_impl/ppapi_globals.h"
11#include "ppapi/shared_impl/var.h"
12#include "ppapi/shared_impl/var_tracker.h"
13
14namespace ppapi {
15namespace proxy {
16
17namespace {
18
19// Returns whether the given clipboard type is valid.
20bool IsValidClipboardType(PP_Flash_Clipboard_Type type) {
21  return type == PP_FLASH_CLIPBOARD_TYPE_STANDARD ||
22         type == PP_FLASH_CLIPBOARD_TYPE_SELECTION;
23}
24
25// Convert a PP_Var to/from a string which is transmitted to the pepper host.
26// These functions assume the format is valid.
27bool PPVarToClipboardString(int32_t format,
28                            const PP_Var& var,
29                            std::string* string_out) {
30  if (format == PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT ||
31      format == PP_FLASH_CLIPBOARD_FORMAT_HTML) {
32    StringVar* string_var = StringVar::FromPPVar(var);
33    if (!string_var)
34      return false;
35    *string_out = string_var->value();
36    return true;
37  } else {
38    // All other formats are expected to be array buffers.
39    ArrayBufferVar* array_buffer_var = ArrayBufferVar::FromPPVar(var);
40    if (!array_buffer_var)
41      return false;
42    *string_out = std::string(static_cast<const char*>(array_buffer_var->Map()),
43                              array_buffer_var->ByteLength());
44    return true;
45  }
46}
47
48PP_Var ClipboardStringToPPVar(int32_t format,
49                              const std::string& string) {
50  if (format == PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT ||
51      format == PP_FLASH_CLIPBOARD_FORMAT_HTML) {
52    return StringVar::StringToPPVar(string);
53  } else {
54    // All other formats are expected to be array buffers.
55    return PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
56        string.size(), string.data());
57  }
58}
59}  // namespace
60
61FlashClipboardResource::FlashClipboardResource(
62    Connection connection, PP_Instance instance)
63    : PluginResource(connection, instance) {
64  SendCreate(BROWSER, PpapiHostMsg_FlashClipboard_Create());
65}
66
67FlashClipboardResource::~FlashClipboardResource() {
68}
69
70thunk::PPB_Flash_Clipboard_API*
71FlashClipboardResource::AsPPB_Flash_Clipboard_API() {
72  return this;
73}
74
75uint32_t FlashClipboardResource::RegisterCustomFormat(
76    PP_Instance instance,
77    const char* format_name) {
78  // Check to see if the format has already been registered.
79  uint32_t format = clipboard_formats_.GetFormatID(format_name);
80  if (format != PP_FLASH_CLIPBOARD_FORMAT_INVALID)
81    return format;
82  int32_t result =
83      SyncCall<PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply>(
84          BROWSER,
85          PpapiHostMsg_FlashClipboard_RegisterCustomFormat(format_name),
86          &format);
87  if (result != PP_OK || format == PP_FLASH_CLIPBOARD_FORMAT_INVALID)
88    return PP_FLASH_CLIPBOARD_FORMAT_INVALID;
89  clipboard_formats_.SetRegisteredFormat(format_name, format);
90  return format;
91}
92
93PP_Bool FlashClipboardResource::IsFormatAvailable(
94    PP_Instance instance,
95    PP_Flash_Clipboard_Type clipboard_type,
96    uint32_t format) {
97  if (IsValidClipboardType(clipboard_type) &&
98      (FlashClipboardFormatRegistry::IsValidPredefinedFormat(format) ||
99       clipboard_formats_.IsFormatRegistered(format))) {
100    int32_t result = SyncCall<IPC::Message>(BROWSER,
101        PpapiHostMsg_FlashClipboard_IsFormatAvailable(clipboard_type, format));
102    return result == PP_OK ? PP_TRUE : PP_FALSE;
103  }
104  return PP_FALSE;
105}
106
107PP_Var FlashClipboardResource::ReadData(
108    PP_Instance instance,
109    PP_Flash_Clipboard_Type clipboard_type,
110    uint32_t format) {
111  std::string value;
112  int32_t result =
113      SyncCall<PpapiPluginMsg_FlashClipboard_ReadDataReply>(
114          BROWSER,
115          PpapiHostMsg_FlashClipboard_ReadData(clipboard_type, format),
116          &value);
117  if (result != PP_OK)
118    return PP_MakeUndefined();
119
120  return ClipboardStringToPPVar(format, value);
121}
122
123int32_t FlashClipboardResource::WriteData(
124    PP_Instance instance,
125    PP_Flash_Clipboard_Type clipboard_type,
126    uint32_t data_item_count,
127    const uint32_t formats[],
128    const PP_Var data_items[]) {
129  if (!IsValidClipboardType(clipboard_type))
130      return PP_ERROR_BADARGUMENT;
131  std::vector<uint32_t> formats_vector;
132  std::vector<std::string> data_items_vector;
133  for (size_t i = 0; i < data_item_count; ++i) {
134    if (!clipboard_formats_.IsFormatRegistered(formats[i]) &&
135        !FlashClipboardFormatRegistry::IsValidPredefinedFormat(formats[i])) {
136      return PP_ERROR_BADARGUMENT;
137    }
138    formats_vector.push_back(formats[i]);
139    std::string string;
140    if (!PPVarToClipboardString(formats[i], data_items[i], &string))
141      return PP_ERROR_BADARGUMENT;
142    data_items_vector.push_back(string);
143  }
144
145  Post(BROWSER,
146       PpapiHostMsg_FlashClipboard_WriteData(
147           static_cast<uint32_t>(clipboard_type),
148           formats_vector,
149           data_items_vector));
150
151  // Assume success, since it allows us to avoid a sync IPC.
152  return PP_OK;
153}
154
155PP_Bool FlashClipboardResource::GetSequenceNumber(
156    PP_Instance instance,
157    PP_Flash_Clipboard_Type clipboard_type,
158    uint64_t* sequence_number) {
159  int32_t result =
160      SyncCall<PpapiPluginMsg_FlashClipboard_GetSequenceNumberReply>(
161          BROWSER,
162          PpapiHostMsg_FlashClipboard_GetSequenceNumber(clipboard_type),
163          sequence_number);
164  return PP_FromBool(result == PP_OK);
165}
166
167}  // namespace proxy
168}  // namespace ppapi
169