~abreu-alexandre/oxide/clipboard

« back to all changes in this revision

Viewing changes to qt/core/browser/oxide_qt_clipboard.cc

  • Committer: Alexandre Abreu
  • Date: 2015-05-21 21:01:36 UTC
  • mfrom: (1069.1.3 clipboard)
  • mto: This revision was merged to the branch mainline in revision 1089.
  • Revision ID: alexandre.abreu@canonical.com-20150521210136-2tjpchpee9aeis92
Clipboard implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "oxide_qt_clipboard.h"
 
6
 
 
7
#include <list>
 
8
#include <set>
 
9
 
 
10
#include "base/basictypes.h"
 
11
#include "base/files/file_path.h"
 
12
#include "base/logging.h"
 
13
#include "base/memory/ref_counted_memory.h"
 
14
#include "base/memory/scoped_ptr.h"
 
15
#include "base/memory/singleton.h"
 
16
#include "base/metrics/histogram.h"
 
17
#include "base/stl_util.h"
 
18
#include "base/strings/utf_string_conversions.h"
 
19
#include "third_party/skia/include/core/SkBitmap.h"
 
20
#include "third_party/skia/include/core/SkImageInfo.h"
 
21
#include "ui/base/clipboard/custom_data_helper.h"
 
22
#include "ui/events/platform/platform_event_dispatcher.h"
 
23
#include "ui/events/platform/platform_event_observer.h"
 
24
#include "ui/events/platform/platform_event_source.h"
 
25
#include "ui/gfx/codec/png_codec.h"
 
26
#include "ui/gfx/geometry/size.h"
 
27
 
 
28
#include <QDebug>
 
29
#include <QClipboard>
 
30
#include <QGuiApplication>
 
31
#include <QImage>
 
32
#include <QMimeData>
 
33
#include <QObject>
 
34
#include <QString>
 
35
 
 
36
 
 
37
#define GET_CLIPBOARD_DATA(c) \
 
38
  c->mimeData( \
 
39
       type == ui::CLIPBOARD_TYPE_COPY_PASTE ? \
 
40
       QClipboard::Clipboard \
 
41
       : QClipboard::Selection)
 
42
 
 
43
class ClipboardChangedListener : public QObject {
 
44
  Q_OBJECT
 
45
  
 
46
 public:
 
47
  ClipboardChangedListener();
 
48
  uint64 clipboard_sequence_number() const {
 
49
    return clipboard_sequence_number_;
 
50
  }
 
51
  uint64 selection_sequence_number() const {
 
52
    return selection_sequence_number_;
 
53
  }
 
54
private Q_SLOTS:
 
55
  void OnClipboardDataChanged(QClipboard::Mode mode);
 
56
private:
 
57
  uint64 clipboard_sequence_number_;
 
58
  uint64 selection_sequence_number_;
 
59
 
 
60
  DISALLOW_COPY_AND_ASSIGN(ClipboardChangedListener);
 
61
};
 
62
 
 
63
ClipboardChangedListener::ClipboardChangedListener()
 
64
  : clipboard_sequence_number_(0),
 
65
    selection_sequence_number_(0) {
 
66
  QObject::connect(
 
67
      QGuiApplication::clipboard(),
 
68
      SIGNAL(changed(QClipboard::Mode)),
 
69
      this,
 
70
      SLOT(OnClipboardDataChanged(QClipboard::Mode)));
 
71
}
 
72
 
 
73
void ClipboardChangedListener::OnClipboardDataChanged(
 
74
      QClipboard::Mode mode) {
 
75
  switch (mode) {
 
76
  case QClipboard::Clipboard:
 
77
    ++clipboard_sequence_number_;
 
78
    break;
 
79
  case QClipboard::Selection:
 
80
    ++selection_sequence_number_;
 
81
    break;
 
82
  default:
 
83
    break;
 
84
  }
 
85
}
 
86
 
 
87
namespace oxide {
 
88
 
 
89
namespace qt {
 
90
 
 
91
namespace {
 
92
 
 
93
const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
 
94
 
 
95
}
 
96
 
 
97
///////////////////////////////////////////////////////////////////////////////
 
98
// ClipboardAuraX11
 
99
 
 
100
ClipboardQt::ClipboardQt()
 
101
  : clipboard_changed_listener_(new ClipboardChangedListener()),
 
102
    write_mime_data_acc_(new QMimeData()) {
 
103
  DCHECK(CalledOnValidThread());
 
104
}
 
105
 
 
106
ui::Clipboard* ClipboardQt::DoCreate() {
 
107
  return new ClipboardQt();
 
108
}
 
109
 
 
110
ClipboardQt::~ClipboardQt() {
 
111
  DCHECK(CalledOnValidThread());
 
112
}
 
113
 
 
114
uint64 ClipboardQt::GetSequenceNumber(ui::ClipboardType type) const {
 
115
  DCHECK(CalledOnValidThread());
 
116
  return type == ui::CLIPBOARD_TYPE_COPY_PASTE
 
117
    ? clipboard_changed_listener_->clipboard_sequence_number()
 
118
    : clipboard_changed_listener_->selection_sequence_number();
 
119
}
 
120
 
 
121
bool ClipboardQt::IsFormatAvailable(const FormatType& format,
 
122
                                    ui::ClipboardType type) const {
 
123
  DCHECK(CalledOnValidThread());
 
124
  DCHECK(IsSupportedClipboardType(type));
 
125
 
 
126
  QClipboard* clipboard = QGuiApplication::clipboard();
 
127
  if ( ! clipboard) {
 
128
    qCritical() << "Could not access clipboard";
 
129
    return false;
 
130
  }
 
131
 
 
132
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
133
  if ( ! data) {
 
134
    return false;
 
135
  }
 
136
 
 
137
  return data->hasFormat(format.ToString().c_str());
 
138
}
 
139
 
 
140
void ClipboardQt::Clear(ui::ClipboardType type) {
 
141
  DCHECK(CalledOnValidThread());
 
142
  DCHECK(IsSupportedClipboardType(type));
 
143
 
 
144
  QClipboard* clipboard = QGuiApplication::clipboard();
 
145
  if ( ! clipboard) {
 
146
    qCritical() << "Could not access clipboard";
 
147
    return;
 
148
  }
 
149
 
 
150
  clipboard->clear();
 
151
}
 
152
 
 
153
void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type,
 
154
                                     std::vector<base::string16>* types,
 
155
                                     bool* contains_filenames) const {
 
156
  DCHECK(IsSupportedClipboardType(type));
 
157
  DCHECK(CalledOnValidThread());
 
158
  DCHECK(types != nullptr);
 
159
  DCHECK(contains_filenames != nullptr);
 
160
 
 
161
  QClipboard* clipboard = QGuiApplication::clipboard();
 
162
  if ( ! clipboard) {
 
163
    qCritical() << "Could not access clipboard";
 
164
    return;
 
165
  }
 
166
 
 
167
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
168
  if ( ! data) {
 
169
    return;
 
170
  }
 
171
 
 
172
  std::vector<base::string16> out_types;
 
173
  Q_FOREACH (const QString& format, data->formats()) {
 
174
    out_types.push_back(base::UTF8ToUTF16(format.toUtf8().data()));
 
175
  }
 
176
  std::swap(*types, out_types);
 
177
 
 
178
  *contains_filenames = false;
 
179
}
 
180
 
 
181
void ClipboardQt::ReadText(ui::ClipboardType type,
 
182
                           base::string16* result) const {
 
183
  DCHECK(IsSupportedClipboardType(type));
 
184
  DCHECK(CalledOnValidThread());
 
185
 
 
186
  QClipboard* clipboard = QGuiApplication::clipboard();
 
187
  if ( ! clipboard) {
 
188
    qCritical() << "Could not access clipboard";
 
189
    return;
 
190
  }
 
191
 
 
192
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
193
  if ( ! data || ! data->hasText()) {
 
194
    return;
 
195
  }
 
196
 
 
197
  *result = base::UTF8ToUTF16(data->text().toUtf8().data());
 
198
}
 
199
 
 
200
void ClipboardQt::ReadAsciiText(ui::ClipboardType type,
 
201
                                std::string* result) const {
 
202
  DCHECK(IsSupportedClipboardType(type));
 
203
  DCHECK(CalledOnValidThread());
 
204
 
 
205
  QClipboard* clipboard = QGuiApplication::clipboard();
 
206
  if ( ! clipboard) {
 
207
    qCritical() << "Could not access clipboard";
 
208
    return;
 
209
  }
 
210
 
 
211
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
212
  if ( ! data || ! data->hasText()) {
 
213
    return;
 
214
  }
 
215
 
 
216
  *result = data->text().toStdString().c_str();
 
217
}
 
218
 
 
219
void ClipboardQt::ReadHTML(ui::ClipboardType type,
 
220
                           base::string16* markup,
 
221
                           std::string* src_url,
 
222
                           uint32* fragment_start,
 
223
                           uint32* fragment_end) const {
 
224
  DCHECK(IsSupportedClipboardType(type));
 
225
  DCHECK(CalledOnValidThread());
 
226
 
 
227
  QClipboard* clipboard = QGuiApplication::clipboard();
 
228
  if ( ! clipboard) {
 
229
    qCritical() << "Could not access clipboard";
 
230
    return;
 
231
  }
 
232
 
 
233
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
234
  if ( ! data || ! data->hasHtml()) {
 
235
    return;
 
236
  }
 
237
 
 
238
  markup->clear();
 
239
  if (src_url) {
 
240
    src_url->clear();
 
241
  }
 
242
 
 
243
  *markup = base::UTF8ToUTF16(data->html().toStdString());
 
244
  *fragment_start = 0;
 
245
  DCHECK(markup->length() <= kuint32max);
 
246
  *fragment_end = static_cast<uint32>(markup->length());
 
247
}
 
248
 
 
249
void ClipboardQt::ReadRTF(ui::ClipboardType type, std::string* result) const {
 
250
  DCHECK(IsSupportedClipboardType(type));
 
251
  DCHECK(CalledOnValidThread());
 
252
 
 
253
  QClipboard* clipboard = QGuiApplication::clipboard();
 
254
  if ( ! clipboard) {
 
255
    qCritical() << "Could not access clipboard";
 
256
    return;
 
257
  }
 
258
 
 
259
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
260
  if ( ! data || ! data->hasFormat(QString::fromLatin1(kMimeTypeRTF))) {
 
261
    return;
 
262
  }
 
263
 
 
264
  *result = data->data(QString::fromLatin1(kMimeTypeRTF)).data();
 
265
}
 
266
 
 
267
SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const {
 
268
  DCHECK(IsSupportedClipboardType(type));
 
269
  DCHECK(CalledOnValidThread());
 
270
 
 
271
  QClipboard* clipboard = QGuiApplication::clipboard();
 
272
  if ( ! clipboard) {
 
273
    qCritical() << "Could not access clipboard";
 
274
    return SkBitmap();
 
275
  }
 
276
 
 
277
  const QMimeData *md = GET_CLIPBOARD_DATA(clipboard);
 
278
  if ( ! md) {
 
279
    return SkBitmap();
 
280
  }
 
281
 
 
282
  QImage image;
 
283
  if (md->hasImage()) {
 
284
    image = qvariant_cast<QImage>(md->imageData());
 
285
    /**
 
286
     * ReadImage() is called from Blink when 'clipboardData.getAsFile'
 
287
     * is called with a forced explicit mime type of 'image/png'.
 
288
     * 
 
289
     * See third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
 
290
     */
 
291
  } else if (md->hasFormat(Clipboard::kMimeTypePNG)) {
 
292
    image.loadFromData(md->data(Clipboard::kMimeTypePNG), "PNG");
 
293
  } else {
 
294
    return SkBitmap();
 
295
  }
 
296
 
 
297
  if (image.format() != QImage::Format_RGBA8888) {
 
298
    image.convertToFormat(QImage::Format_RGBA8888);
 
299
  }
 
300
 
 
301
  SkBitmap bitmap;
 
302
  bitmap.setInfo(
 
303
      SkImageInfo::MakeN32(
 
304
          image.width(),
 
305
          image.height(),
 
306
          kOpaque_SkAlphaType));
 
307
  
 
308
  bitmap.setPixels(const_cast<uchar*>(image.constBits()));
 
309
 
 
310
  // Force a deep copy of the image data
 
311
  SkBitmap copy;
 
312
  bitmap.copyTo(&copy, kN32_SkColorType);
 
313
  return copy;
 
314
}
 
315
 
 
316
void ClipboardQt::ReadCustomData(ui::ClipboardType type,
 
317
                                 const base::string16& data_type,
 
318
                                 base::string16* result) const {
 
319
  DCHECK(CalledOnValidThread());
 
320
  DCHECK(IsSupportedClipboardType(type));
 
321
  
 
322
  QClipboard* clipboard = QGuiApplication::clipboard();
 
323
  if ( ! clipboard) {
 
324
    qCritical() << "Could not access clipboard";
 
325
    return;
 
326
  }
 
327
 
 
328
  const QMimeData *data = GET_CLIPBOARD_DATA(clipboard);
 
329
  QString mime_type = QString::fromStdString(base::UTF16ToUTF8(data_type));
 
330
  if ( ! data || ! data->hasFormat(mime_type)) {
 
331
    return;
 
332
  }
 
333
 
 
334
  ui::ReadCustomDataForType(
 
335
      data->data(mime_type).constData(),
 
336
      data->data(mime_type).size(),
 
337
      data_type,
 
338
      result);
 
339
}
 
340
 
 
341
void ClipboardQt::ReadBookmark(base::string16* title,
 
342
                               std::string* url) const {
 
343
  NOTIMPLEMENTED();
 
344
}
 
345
 
 
346
void ClipboardQt::ReadData(const FormatType& format,
 
347
                           std::string* result) const {
 
348
  DCHECK(CalledOnValidThread());
 
349
 
 
350
  QClipboard* clipboard = QGuiApplication::clipboard();
 
351
  if ( ! clipboard) {
 
352
    qCritical() << "Could not access clipboard";
 
353
    return;
 
354
  }
 
355
 
 
356
  const QMimeData *data = clipboard->mimeData(QClipboard::Clipboard);
 
357
  if ( ! data) {
 
358
    return;
 
359
  }
 
360
 
 
361
  *result = data->data(format.ToString().c_str()).data();
 
362
}
 
363
 
 
364
void ClipboardQt::WriteObjects(ui::ClipboardType type,
 
365
                               const ObjectMap& objects) {
 
366
  DCHECK(CalledOnValidThread());
 
367
  DCHECK(IsSupportedClipboardType(type));
 
368
 
 
369
  if (! write_mime_data_acc_) {
 
370
    write_mime_data_acc_.reset(new QMimeData());
 
371
  }
 
372
 
 
373
  // dispatch all objects and gather the resulting mime data
 
374
  for (ObjectMap::const_iterator iter = objects.begin();
 
375
       iter != objects.end();
 
376
       ++iter) {
 
377
    DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
 
378
  }
 
379
 
 
380
  QClipboard* clipboard = QGuiApplication::clipboard();
 
381
  if ( ! clipboard) {
 
382
    qCritical() << "Could not access clipboard";
 
383
    return;
 
384
  }
 
385
 
 
386
  clipboard->setMimeData(
 
387
      write_mime_data_acc_.release(),
 
388
      type == ui::CLIPBOARD_TYPE_COPY_PASTE
 
389
      ? QClipboard::Clipboard
 
390
      : QClipboard::Selection);
 
391
}
 
392
 
 
393
void ClipboardQt::WriteText(const char* text_data, size_t text_len) {
 
394
  write_mime_data_acc_->setText(QString::fromUtf8(text_data, text_len));
 
395
}
 
396
 
 
397
void ClipboardQt::WriteHTML(const char* markup_data,
 
398
                            size_t markup_len,
 
399
                            const char* url_data,
 
400
                            size_t url_len) {
 
401
  write_mime_data_acc_->setHtml(
 
402
      QString::fromUtf8(markup_data, markup_len));
 
403
}
 
404
 
 
405
void ClipboardQt::WriteRTF(const char* rtf_data, size_t data_len) {
 
406
  write_mime_data_acc_->setData(QString::fromLatin1(kMimeTypeRTF), QByteArray(rtf_data, data_len));
 
407
}
 
408
 
 
409
void ClipboardQt::WriteBookmark(const char* title_data,
 
410
                                     size_t title_len,
 
411
                                     const char* url_data,
 
412
                                     size_t url_len) {
 
413
  NOTIMPLEMENTED();
 
414
}
 
415
 
 
416
void ClipboardQt::WriteWebSmartPaste() {
 
417
  write_mime_data_acc_->setData(
 
418
      QString::fromLatin1(kMimeTypeWebkitSmartPaste),
 
419
      QByteArray());
 
420
}
 
421
 
 
422
void ClipboardQt::WriteBitmap(const SkBitmap& bitmap) {
 
423
  QImage image;
 
424
  if (bitmap.info().colorType() != kN32_SkColorType) {
 
425
    SkImageInfo info =
 
426
      SkImageInfo::MakeN32(
 
427
        bitmap.width(),
 
428
        bitmap.height(),
 
429
        bitmap.alphaType());
 
430
 
 
431
    SkBitmap convertedBitmap;
 
432
    if (!convertedBitmap.tryAllocPixels(info)) {
 
433
      return;
 
434
    }
 
435
 
 
436
    bitmap.readPixels(
 
437
        info,
 
438
        convertedBitmap.getPixels(),
 
439
        0, 0, 0);
 
440
 
 
441
    image = QImage(reinterpret_cast<const uchar *>(convertedBitmap.getPixels()),
 
442
        bitmap.width(),
 
443
        bitmap.height(),
 
444
        QImage::Format_RGBA8888);
 
445
  } else {
 
446
    image = QImage(reinterpret_cast<const uchar *>(bitmap.getPixels()),
 
447
        bitmap.width(),
 
448
        bitmap.height(),
 
449
        QImage::Format_RGBA8888);
 
450
  }
 
451
 
 
452
  write_mime_data_acc_->setImageData(image.copy());
 
453
}
 
454
 
 
455
void ClipboardQt::WriteData(const FormatType& format,
 
456
                                 const char* data_data,
 
457
                                 size_t data_len) {
 
458
  write_mime_data_acc_->setData(
 
459
      QString::fromStdString(format.ToString()),
 
460
      QByteArray(data_data, data_len));
 
461
}
 
462
 
 
463
} // namespace qt
 
464
} // namespace oxide
 
465
 
 
466
#include "oxide_qt_clipboard.moc"