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.
5 #include "content/renderer/pepper/pepper_flash_clipboard_host.h"
7 #include "base/pickle.h"
8 #include "base/utf_string_conversions.h"
9 #include "content/public/renderer/renderer_ppapi_host.h"
10 #include "content/renderer/renderer_clipboard_client.h"
11 #include "ipc/ipc_message_macros.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/private/ppb_flash_clipboard.h"
14 #include "ppapi/host/dispatch_host_message.h"
15 #include "ppapi/host/ppapi_host.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/proxy/resource_message_params.h"
18 #include "webkit/glue/clipboard_client.h"
19 #include "webkit/glue/scoped_clipboard_writer_glue.h"
25 const size_t kMaxClipboardWriteSize
= 1000000;
27 ui::Clipboard::Buffer
ConvertClipboardType(uint32_t type
) {
29 case PP_FLASH_CLIPBOARD_TYPE_STANDARD
:
30 return ui::Clipboard::BUFFER_STANDARD
;
31 case PP_FLASH_CLIPBOARD_TYPE_SELECTION
:
32 return ui::Clipboard::BUFFER_SELECTION
;
35 return ui::Clipboard::BUFFER_STANDARD
;
38 // Functions to pack/unpack custom data from a pickle. See the header file for
39 // more detail on custom formats in Pepper.
40 // TODO(raymes): Currently pepper custom formats are stored in their own
41 // native format type. However we should be able to store them in the same way
42 // as "Web Custom" formats are. This would allow clipboard data to be shared
43 // between pepper applications and web applications. However currently web apps
44 // assume all data that is placed on the clipboard is UTF16 and pepper allows
45 // arbitrary data so this change would require some reworking of the chrome
46 // clipboard interface for custom data.
47 bool JumpToFormatInPickle(const string16
& format
, PickleIterator
* iter
) {
49 if (!iter
->ReadUInt64(&size
))
51 for (uint64 i
= 0; i
< size
; ++i
) {
52 string16 stored_format
;
53 if (!iter
->ReadString16(&stored_format
))
55 if (stored_format
== format
)
58 if (!iter
->ReadLength(&skip_length
))
60 if (!iter
->SkipBytes(skip_length
))
66 bool IsFormatAvailableInPickle(const string16
& format
, const Pickle
& pickle
) {
67 PickleIterator
iter(pickle
);
68 return JumpToFormatInPickle(format
, &iter
);
71 std::string
ReadDataFromPickle(const string16
& format
, const Pickle
& pickle
) {
73 PickleIterator
iter(pickle
);
74 if (!JumpToFormatInPickle(format
, &iter
) || !iter
.ReadString(&result
))
79 bool WriteDataToPickle(const std::map
<string16
, std::string
>& data
,
81 pickle
->WriteUInt64(data
.size());
82 for (std::map
<string16
, std::string
>::const_iterator it
= data
.begin();
83 it
!= data
.end(); ++it
) {
84 if (!pickle
->WriteString16(it
->first
))
86 if (!pickle
->WriteString(it
->second
))
94 PepperFlashClipboardHost::PepperFlashClipboardHost(
95 RendererPpapiHost
* host
,
98 : ResourceHost(host
->GetPpapiHost(), instance
, resource
),
99 clipboard_client_(new RendererClipboardClient
) {
102 PepperFlashClipboardHost::~PepperFlashClipboardHost() {
105 int32_t PepperFlashClipboardHost::OnResourceMessageReceived(
106 const IPC::Message
& msg
,
107 ppapi::host::HostMessageContext
* context
) {
108 IPC_BEGIN_MESSAGE_MAP(PepperFlashClipboardHost
, msg
)
109 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
110 PpapiHostMsg_FlashClipboard_RegisterCustomFormat
,
111 OnMsgRegisterCustomFormat
);
112 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
113 PpapiHostMsg_FlashClipboard_IsFormatAvailable
,
114 OnMsgIsFormatAvailable
);
115 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
116 PpapiHostMsg_FlashClipboard_ReadData
,
118 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
119 PpapiHostMsg_FlashClipboard_WriteData
,
121 IPC_END_MESSAGE_MAP()
122 return PP_ERROR_FAILED
;
125 int32_t PepperFlashClipboardHost::OnMsgRegisterCustomFormat(
126 ppapi::host::HostMessageContext
* host_context
,
127 const std::string
& format_name
) {
128 uint32_t format
= custom_formats_
.RegisterFormat(format_name
);
129 if (format
== PP_FLASH_CLIPBOARD_FORMAT_INVALID
)
130 return PP_ERROR_FAILED
;
131 host_context
->reply_msg
=
132 PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply(format
);
136 int32_t PepperFlashClipboardHost::OnMsgIsFormatAvailable(
137 ppapi::host::HostMessageContext
* host_context
,
138 uint32_t clipboard_type
,
140 if (clipboard_type
!= PP_FLASH_CLIPBOARD_TYPE_STANDARD
) {
142 return PP_ERROR_FAILED
;
145 ui::Clipboard::Buffer buffer_type
= ConvertClipboardType(clipboard_type
);
146 bool available
= false;
148 case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT
: {
149 bool plain
= clipboard_client_
->IsFormatAvailable(
150 ui::Clipboard::GetPlainTextFormatType(), buffer_type
);
151 bool plainw
= clipboard_client_
->IsFormatAvailable(
152 ui::Clipboard::GetPlainTextWFormatType(), buffer_type
);
153 available
= plain
|| plainw
;
156 case PP_FLASH_CLIPBOARD_FORMAT_HTML
:
157 available
= clipboard_client_
->IsFormatAvailable(
158 ui::Clipboard::GetHtmlFormatType(), buffer_type
);
160 case PP_FLASH_CLIPBOARD_FORMAT_RTF
:
161 available
= clipboard_client_
->IsFormatAvailable(
162 ui::Clipboard::GetRtfFormatType(), buffer_type
);
164 case PP_FLASH_CLIPBOARD_FORMAT_INVALID
:
167 if (custom_formats_
.IsFormatRegistered(format
)) {
168 std::string format_name
= custom_formats_
.GetFormatName(format
);
169 std::string clipboard_data
;
170 clipboard_client_
->ReadData(
171 ui::Clipboard::GetPepperCustomDataFormatType(), &clipboard_data
);
172 Pickle
pickle(clipboard_data
.data(), clipboard_data
.size());
173 available
= IsFormatAvailableInPickle(UTF8ToUTF16(format_name
), pickle
);
178 return available
? PP_OK
: PP_ERROR_FAILED
;
181 int32_t PepperFlashClipboardHost::OnMsgReadData(
182 ppapi::host::HostMessageContext
* host_context
,
183 uint32_t clipboard_type
,
185 if (clipboard_type
!= PP_FLASH_CLIPBOARD_TYPE_STANDARD
) {
187 return PP_ERROR_FAILED
;
190 ui::Clipboard::Buffer buffer_type
= ConvertClipboardType(clipboard_type
);
191 std::string clipboard_string
;
192 int32_t result
= PP_ERROR_FAILED
;
194 case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT
: {
195 if (clipboard_client_
->IsFormatAvailable(
196 ui::Clipboard::GetPlainTextWFormatType(), buffer_type
)) {
198 clipboard_client_
->ReadText(buffer_type
, &text
);
201 clipboard_string
= UTF16ToUTF8(text
);
205 // If the PlainTextW format isn't available or is empty, take the
206 // ASCII text format.
207 if (clipboard_client_
->IsFormatAvailable(
208 ui::Clipboard::GetPlainTextFormatType(), buffer_type
)) {
210 clipboard_client_
->ReadAsciiText(buffer_type
, &clipboard_string
);
214 case PP_FLASH_CLIPBOARD_FORMAT_HTML
: {
215 if (!clipboard_client_
->IsFormatAvailable(
216 ui::Clipboard::GetHtmlFormatType(), buffer_type
)) {
222 uint32 fragment_start
;
224 clipboard_client_
->ReadHTML(buffer_type
, &html
, &gurl
, &fragment_start
,
227 clipboard_string
= UTF16ToUTF8(
228 html
.substr(fragment_start
, fragment_end
- fragment_start
));
231 case PP_FLASH_CLIPBOARD_FORMAT_RTF
: {
232 if (!clipboard_client_
->IsFormatAvailable(
233 ui::Clipboard::GetRtfFormatType(), buffer_type
)) {
237 clipboard_client_
->ReadRTF(buffer_type
, &clipboard_string
);
240 case PP_FLASH_CLIPBOARD_FORMAT_INVALID
:
243 if (custom_formats_
.IsFormatRegistered(format
)) {
244 string16 format_name
= UTF8ToUTF16(
245 custom_formats_
.GetFormatName(format
));
246 std::string clipboard_data
;
247 clipboard_client_
->ReadData(
248 ui::Clipboard::GetPepperCustomDataFormatType(), &clipboard_data
);
249 Pickle
pickle(clipboard_data
.data(), clipboard_data
.size());
250 if (IsFormatAvailableInPickle(format_name
, pickle
)) {
252 clipboard_string
= ReadDataFromPickle(format_name
, pickle
);
259 if (result
== PP_OK
) {
260 host_context
->reply_msg
=
261 PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string
);
266 int32_t PepperFlashClipboardHost::OnMsgWriteData(
267 ppapi::host::HostMessageContext
* host_context
,
268 uint32_t clipboard_type
,
269 const std::vector
<uint32_t>& formats
,
270 const std::vector
<std::string
>& data
) {
271 if (clipboard_type
!= PP_FLASH_CLIPBOARD_TYPE_STANDARD
) {
273 return PP_ERROR_FAILED
;
276 DCHECK(formats
.size() == data
.size());
277 // If no formats are passed in clear the clipboard.
278 if (formats
.size() == 0) {
279 clipboard_client_
->Clear(ConvertClipboardType(clipboard_type
));
283 webkit_glue::ScopedClipboardWriterGlue
scw(clipboard_client_
.get());
284 std::map
<string16
, std::string
> custom_data_map
;
286 for (uint32_t i
= 0; i
< formats
.size(); ++i
) {
287 if (data
[i
].length() > kMaxClipboardWriteSize
) {
288 res
= PP_ERROR_NOSPACE
;
292 switch (formats
[i
]) {
293 case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT
:
294 scw
.WriteText(UTF8ToUTF16(data
[i
]));
296 case PP_FLASH_CLIPBOARD_FORMAT_HTML
:
297 scw
.WriteHTML(UTF8ToUTF16(data
[i
]), "");
299 case PP_FLASH_CLIPBOARD_FORMAT_RTF
:
300 scw
.WriteRTF(data
[i
]);
302 case PP_FLASH_CLIPBOARD_FORMAT_INVALID
:
303 res
= PP_ERROR_BADARGUMENT
;
306 if (custom_formats_
.IsFormatRegistered(formats
[i
])) {
307 std::string format_name
= custom_formats_
.GetFormatName(formats
[i
]);
308 custom_data_map
[UTF8ToUTF16(format_name
)] = data
[i
];
311 res
= PP_ERROR_BADARGUMENT
;
320 if (custom_data_map
.size() > 0) {
322 if (WriteDataToPickle(custom_data_map
, &pickle
)) {
323 scw
.WritePickledData(pickle
,
324 ui::Clipboard::GetPepperCustomDataFormatType());
326 res
= PP_ERROR_BADARGUMENT
;
331 // Need to clear the objects so nothing is written.
338 } // namespace content