Merge lp:~abreu-alexandre/oxide/clipboard into lp:~oxide-developers/oxide/oxide.trunk

Proposed by Alexandre Abreu
Status: Merged
Merged at revision: 1093
Proposed branch: lp:~abreu-alexandre/oxide/clipboard
Merge into: lp:~oxide-developers/oxide/oxide.trunk
Diff against target: 1236 lines (+1072/-1)
15 files modified
patches/add-clipboard-create-override-mechanism.patch (+15/-0)
patches/series (+1/-0)
qt/core/browser/oxide_qt_browser_platform_integration.cc (+5/-0)
qt/core/browser/oxide_qt_browser_platform_integration.h (+1/-0)
qt/core/browser/oxide_qt_clipboard.cc (+408/-0)
qt/core/browser/oxide_qt_clipboard.h (+94/-0)
qt/core/core.gyp (+7/-0)
qt/tests/qmltests/core/tst_Clipboard.html (+33/-0)
qt/tests/qmltests/core/tst_Clipboard.qml (+129/-0)
qt/tests/qmltests/oxide_qml_testing_plugin.cc (+25/-1)
shared/browser/oxide_browser_main_parts.cc (+4/-0)
shared/browser/oxide_browser_platform_integration.cc (+5/-0)
shared/browser/oxide_browser_platform_integration.h (+5/-0)
shared/port/ui_base/clipboard_oxide.cc (+260/-0)
shared/port/ui_base/clipboard_oxide.h (+80/-0)
To merge this branch: bzr merge lp:~abreu-alexandre/oxide/clipboard
Reviewer Review Type Date Requested Status
Chris Coulson Approve
Olivier Tilloy (community) Approve
Review via email: mp+257206@code.launchpad.net

Commit message

Clipboard implementation

Description of the change

Clipboard implementation

To post a comment you must log in.
lp:~abreu-alexandre/oxide/clipboard updated
1056. By Chris Coulson

Fix a memory corruption when the visibilty of a webview is changed

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

I haven't given this a proper review yet - I've just left a couple of pointers for implementation changes (quite minor).

Olivier, would you mind taking a look at this if you've got some time?

Revision history for this message
Chris Coulson (chrisccoulson) :
review: Needs Fixing
lp:~abreu-alexandre/oxide/clipboard updated
1057. By Chris Coulson

Don't crash when the frame tree is torn down during a process swap

1058. By Olivier Tilloy

Fix a crash when a popup menu is dismissed twice (by calling accept() and then cancel() on it).

1059. By Olivier Tilloy

Fix a crash when a JS dialog is dismissed twice (by calling accept() and then reject() on it).

1060. By Chris Coulson

Process all descendents in WebView::FrameDeleted, rather than just the immediate children

1061. By Chris Coulson

Don't disable share-group usage if virtualized GL contexts are enabled on desktop. This sucks, as we can't really know why virtualized contexts are enabled - if it's due to performance issues, then using share-groups is ok (and better than the alternative - software compositing). If it's because of driver bugs / crashes, then we're screwed. We need to do this now because Chromium cananry enables virtualized contexts globally on desktop Linux

1062. By Chris Coulson

Don't run unload handlers on webviews that are script closed. Also, beef up the tests to catch this and work a bit more reliably

1063. By Chris Coulson

Bump Chromium rev to 44.0.2391.0

1064. By Olivier Tilloy

Add a WebView::webProcessStatus property to notify embedders when the renderer process crashed or was killed.

1065. By Chris Coulson

Add WebView.mediaAccessPermissionRequested API

1066. By Chris Coulson

Make comments more accurate

1067. By Chris Coulson

FrameTreeNode::frame_tree_node_id is an int rather than int64_t

Revision history for this message
Olivier Tilloy (osomon) wrote :

There’s a couple of conflicts in qt/tests/qmltests/oxide_qml_testing_plugin.cc when merging this branch into the latest trunk.

lp:~abreu-alexandre/oxide/clipboard updated
1068. By Chris Coulson

Remove a workaround for the old browser headerbar, used when scrolling the focused editable node in to view

1069. By Alexandre Abreu

Prevent a shutdown deadlock if the render process is killed whilst waiting for the close ACK

1070. By Chris Coulson

When deleting a WebContext, ensure that the service worker context is shut down to release references on the RenderProcessHost

1071. By Chris Coulson

Don't leak BrowserContext

1072. By Chris Coulson

Fix test failure in tst_OxideGlobal - it seems that the displayName doesn't have extra characters on some machines

1073. By Chris Coulson

Ensure we correctly shut down the OTR BrowserContext

Revision history for this message
Olivier Tilloy (osomon) wrote :
Download full text (3.6 KiB)

Thanks for working on this, this is probably the most-awaited feature ever :)
Here are a few comments/remarks from a first round of review:

== unit tests ==

We’re missing unit tests for (at least) HTML markup.

Indentation in qt/tests/qmltests/core/tst_Clipboard.* is inconsistent in places.

Why does clearClipboard() accept an (unused) 'data' parameter?

Is getClipboardImageData() really necessary? Can’t the test data be defined in tst_Clipboard.qml directly (and add a 'data' parameter to copyImageToClipboard())?
In fact, can’t we get rid entirely of copyImageToClipboard(), and make copyToClipboard() more generic by checking the mimeType to decide whether the data is base64-encoded or not?

In test_paste_data(), the 'isimage' parameter seems redundant, you could just verify whether the mimeType starts with "image/".

copyFromClipboard() would be better named getFromClipboard() or getClipboardContent()

> The image we get from QImage and the one we pasted are slightly
> different but overall is the same image. QImage does some "processing"
> on the raw image content that slightly alters it and make it hard to
> have an exact match.
How is that even possible? We’re talking about an uncompressed, lossless PNG, right?
And I don’t see where QImage is involved in test_paste(), only raw data is passed around as QByteArrays.
By the way, can’t we make the test image data smaller? A 1×1 PNG would suffice for testing purposes.

test_copy() seems to be text-specific, so I don’t really see the point of having it being data-driven.

== implementation ==

There is a leftover DLOG in shared/port/ui_base/clipboard_oxide.cc.

Includes are not properly sorted alphabetically in shared/port/ui_base/clipboard_oxide.cc.

In qt/core/browser/oxide_qt_clipboard.cc, Qt includes are not sorted alphabetically. Also QDebug is included but doesn’t appear to be used. Shouldn’t it be used instead of LOG() macros?

In ClipboardQt’s method implementations, isn’t the DCHECK(clipboard) redundant, given that the case where clipboard is null is explictly handled?

Same for a DCHECK(data) in ClipboardQt::IsFormatAvailable(…).

In ClipboardQt::ReadAvailableTypes():
  - instead of a if() followed by a NOTREACHED, wouldn’t a DCHECK be more appropriate? We don’t expect the caller to pass in null parameters anyway, do we?
  - why not push types directly to the passed vector, instead of using an temporary vector and swapping its contents afterwards?
  - shouldn’t contains_filenames be set accordingly if one of the formats is "chromium/filename" ?

The indentation of the definition of ClipboardQt::ReadAsciiText() is incorrect.

It looks like the following block is repeated many times, maybe it could be factored out as a macro?
  const QMimeData *data =
    clipboard->mimeData(
       type == ui::CLIPBOARD_TYPE_COPY_PASTE ?
       QClipboard::Clipboard
       : QClipboard::Selection);

In ClipboardQt::ReadHTML():
  - please use curly brackets to surround the contents of an if() block, even if it’s a one-liner.
  - do we really need to clear markup and src_url prior to setting their content?

In ClipboardQt::ReadImage():
  - I don’t understand the comment about ReadImage. Can you clarif...

Read more...

review: Needs Fixing
lp:~abreu-alexandre/oxide/clipboard updated
1074. By Chris Coulson

Move gesture detection to RWHV, keep MotionEvent tracking on WebView (so that we keep it in sync with incoming touch events), and reset the gesture pipeline when navigating to a new page

1075. By Chris Coulson

Refactor ownership model of BrowserContext, and discard the OTR BrowserContext as soon as all incognito webviews using it have been deleted

1076. By Chris Coulson

Actually fix tst_OxideGlobal.qml

1077. By Chris Coulson

Don't create multiple WebContexts pointing at the same path in tst_UnloadHandlers.qml

1078. By Riccardo Padovani

Add LoadEvent.httpStatusCode property

1079. By Chris Coulson

Bump Chromium rev to 44.0.2398.0

1080. By Chris Coulson

Revert a couple of changes that shouldn't have landed

1081. By Chris Coulson

Initialize handle_ for all Proxy objects

1082. By Chris Coulson

Flush profile data when the application goes in to the background

1083. By Chris Coulson

Generate a synthetic Suspended state on the phone

1084. By Chris Coulson

Remove spurious printf

1085. By Chris Coulson

Bump Chromium rev to 44.0.2403.0

1086. By Chris Coulson

Bump Chromium rev to 44.0.2403.4

1087. By Chris Coulson

Add a client interface for WebView, and implement that in qt/. This is the start of an attempt to split functionality out of WebView in to smaller classes

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

The comments have been addressed,

>
> > The image we get from QImage and the one we pasted are slightly
> > different but overall is the same image. QImage does some "processing"
> > on the raw image content that slightly alters it and make it hard to
> > have an exact match.
> How is that even possible? We’re talking about an uncompressed, lossless PNG,
> right?
> And I don’t see where QImage is involved in test_paste(), only raw data is
> passed around as QByteArrays.
> By the way, can’t we make the test image data smaller? A 1×1 PNG would suffice
> for testing purposes.

There are conversion to account for the alpha channel RGBA -> ARGB updates,

> In ClipboardQt::WriteHTML(), what prevents us from implementing the resolution
> of relative links?

this is something that is actually win32 specific,

lp:~abreu-alexandre/oxide/clipboard updated
1088. By Ugo Riboni

Add WebView.findController API

Revision history for this message
Olivier Tilloy (osomon) wrote :

Is the license and copyright header in qt/core/browser/oxide_qt_clipboard.[h|cc] correct?

In qt/core/browser/oxide_qt_browser_platform_integration.h:
 - shouldn’t the override of GetClipboardOxideFactory() be annotated with 'override' instead of 'final' ?

In qt/core/browser/oxide_qt_clipboard.h:
 - is "friend class Clipboard;" needed?
 - does the 'override' keywoard makes sense for a destructor?

In qt/core/browser/oxide_qt_clipboard.cc:
 - ClipboardChangedListener being a QObject, it would be more consistent to use Q_DISABLE_COPY instead of DISALLOW_COPY_AND_ASSIGN
 - In ClipboardChangedListener’s class declaration, the alignment of the visibility keywords is inconsistent
 - In ClipboardChangedListener::OnClipboardDataChanged, can you add an indentation level for 'case' statements and their contents?
 - shouldn’t ClipboardQt::WriteWebSmartPaste() be marked NOTIMPLEMENTED ?
 - it seems the checks on the nullness of QGuiApplication::clipboard() are not necessary, we can safely assume it will never be null (other code throughout Qt makes this assumption already)

In qt/tests/qmltests/core/tst_Clipboard.html:
 - div with id "blabla" is unused, can it be removed?

In qt/tests/qmltests/core/tst_Clipboard.qml:
 - in expect_has_file(), [result = result == 'true'] is incomplete: if 'expected' is false and 'result' is anything but "false" (including the empty string), the function should return false
 - indentation should use 2 spaces, not 4
 - test_copy() takes an unused 'data' parameter, can it be removed?

In qt/tests/qmltests/oxide_qml_testing_plugin.cc:
 - Qt includes are not ordered alphabetically
 - the newline in the middle of the first call to setData in copyToClipboard() is not necessary

There are a few of my previous comments that haven’t been addressed/answered, copying them here for reference:

> We’re missing unit tests for (at least) HTML markup.

>> The image we get from QImage and the one we pasted are slightly
>> different but overall is the same image. QImage does some "processing"
>> on the raw image content that slightly alters it and make it hard to
>> have an exact match.
> How is that even possible? We’re talking about an uncompressed,
> lossless PNG, right?
> And I don’t see where QImage is involved in test_paste(), only raw data
> is passed around as QByteArrays.

> In ClipboardQt::ReadAvailableTypes():
> - why not push types directly to the passed vector, instead of using
> an temporary vector and swapping its contents afterwards?
> - shouldn’t contains_filenames be set accordingly if one of the
> formats is "chromium/filename" ?

> In ClipboardQt::ReadHTML():
> - do we really need to clear markup and src_url prior to setting
> their content?

review: Needs Fixing
lp:~abreu-alexandre/oxide/clipboard updated
1089. By Alexandre Abreu

Add clipboard support

1090. By Alexandre Abreu

Nits

1091. By Alexandre Abreu

update test

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :
Download full text (3.1 KiB)

> Is the license and copyright header in
> qt/core/browser/oxide_qt_clipboard.[h|cc] correct?
>
> In qt/core/browser/oxide_qt_browser_platform_integration.h:
> - shouldn’t the override of GetClipboardOxideFactory() be annotated with
> 'override' instead of 'final' ?
>
> In qt/core/browser/oxide_qt_clipboard.h:
> - is "friend class Clipboard;" needed?
> - does the 'override' keywoard makes sense for a destructor?

yes,

> In qt/core/browser/oxide_qt_clipboard.cc:
> - ClipboardChangedListener being a QObject, it would be more consistent to
> use Q_DISABLE_COPY instead of DISALLOW_COPY_AND_ASSIGN
> - In ClipboardChangedListener’s class declaration, the alignment of the
> visibility keywords is inconsistent
> - In ClipboardChangedListener::OnClipboardDataChanged, can you add an
> indentation level for 'case' statements and their contents?
> - shouldn’t ClipboardQt::WriteWebSmartPaste() be marked NOTIMPLEMENTED ?

it not actually, this is a special tag (mostly like a shell 'touch') that touches
the clipboard w/ null data

> - it seems the checks on the nullness of QGuiApplication::clipboard() are not
> necessary, we can safely assume it will never be null (other code throughout
> Qt makes this assumption already)
>
> In qt/tests/qmltests/core/tst_Clipboard.html:
> - div with id "blabla" is unused, can it be removed?
>
> In qt/tests/qmltests/core/tst_Clipboard.qml:
> - in expect_has_file(), [result = result == 'true'] is incomplete: if
> 'expected' is false and 'result' is anything but "false" (including the empty
> string), the function should return false
> - indentation should use 2 spaces, not 4
> - test_copy() takes an unused 'data' parameter, can it be removed?
>
> In qt/tests/qmltests/oxide_qml_testing_plugin.cc:
> - Qt includes are not ordered alphabetically
> - the newline in the middle of the first call to setData in copyToClipboard()
> is not necessary

addressed all the above (unless otherwise noted)

> There are a few of my previous comments that haven’t been addressed/answered,
> copying them here for reference:
>
> > We’re missing unit tests for (at least) HTML markup.
>
> >> The image we get from QImage and the one we pasted are slightly
> >> different but overall is the same image. QImage does some "processing"
> >> on the raw image content that slightly alters it and make it hard to
> >> have an exact match.
> > How is that even possible? We’re talking about an uncompressed,
> > lossless PNG, right?
> > And I don’t see where QImage is involved in test_paste(), only raw data
> > is passed around as QByteArrays.

as I said in my previous comment, there is a conversion happening, from ARGB -> RGBA

> > In ClipboardQt::ReadAvailableTypes():
> > - why not push types directly to the passed vector, instead of using
> > an temporary vector and swapping its contents afterwards?

it is mostly an exception safety reflex, not being destructive of args, etc. but
it obviously does not apply here

> > - shouldn’t contains_filenames be set accordingly if one of the
> > formats is "chromium/filename" ?
> > In ClipboardQt::ReadHTML():
> > - do we really need to clear markup and src_url prior to setting
> > the...

Read more...

Revision history for this message
Olivier Tilloy (osomon) wrote :

>>> The image we get from QImage and the one we pasted are slightly
>>> different but overall is the same image. QImage does some "processing"
>>> on the raw image content that slightly alters it and make it hard to
>>> have an exact match.
>> How is that even possible? We’re talking about an uncompressed,
>> lossless PNG, right?
>> And I don’t see where QImage is involved in test_paste(), only raw data
>> is passed around as QByteArrays.
> as I said in my previous comment, there is a conversion happening,
> from ARGB -> RGBA

Could you please update the comment to make it explicit what the issue is, then?
 « some "processing" on the raw image content that slightly alters it » is rather vague, ARGB -> RGBA conversion is much more precise.

Where does the 34 magic number come from (in the call to expect_content)?

lp:~abreu-alexandre/oxide/clipboard updated
1092. By Alexandre Abreu

updates

1093. By Alexandre Abreu

update cmment

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> >>> The image we get from QImage and the one we pasted are slightly
> >>> different but overall is the same image. QImage does some "processing"
> >>> on the raw image content that slightly alters it and make it hard to
> >>> have an exact match.
> >> How is that even possible? We’re talking about an uncompressed,
> >> lossless PNG, right?
> >> And I don’t see where QImage is involved in test_paste(), only raw data
> >> is passed around as QByteArrays.
> > as I said in my previous comment, there is a conversion happening,
> > from ARGB -> RGBA
>
> Could you please update the comment to make it explicit what the issue is,
> then?
> « some "processing" on the raw image content that slightly alters it » is
> rather vague, ARGB -> RGBA conversion is much more precise.

> Where does the 34 magic number come from (in the call to expect_content)?

I updated the comment

Revision history for this message
Olivier Tilloy (osomon) wrote :

I don’t really like that magic number, we could probably write a cleaner test by setting the contents of the clipboard on an Image object, and comparing its dimensions and pixel content to the expected values.

Aside from that, this now looks good to me. I wouldn’t mind a quick sanity review from Chris to validate the architecture though.

review: Approve
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

I haven't done a thorough review, but there is one comment inline I'd like to see fixed before merging (the use of CONTENT_EXPORT in a code compiled in to ui_base isn't correct).

A couple of other minor points, although these can be fixed up afterwards:

- I'd prefer ClipboardQt to just be Clipboard, given that it's inside of the oxide::qt namespace
- It would be better if BrowserPlatformIntegration returned the actual Clipboard implementation instead of the factory function. The factory implementation can be private to oxide_browser_main_parts.cc (eg, see CreateUIMessagePump).
- I'm not sure I fully understand what ui::ClipboardOxide is for. Given that BrowserMainParts always calls ui::SetClipboardOxideFactory, then ui::Clipboard::Create() will always return the result from the implementation of BrowserPlatformIntegration. If it's meant to be a fallback where no clipboard implementation is provided by the embedding layer, then it doesn't really work because ui::Clipboard::Create() null checks the wrong thing. And a more appropriate name in this case would probably be something like "NullClipboard".

Other than that, this should be ok to merge

review: Approve
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Actually, forget my 3rd point there. Of course, in the current implementation, ui::SetClipboardOxideFactory can set a null factory if one isn't provided

lp:~abreu-alexandre/oxide/clipboard updated
1094. By Alexandre Abreu

removed CONTENT_EXPORT

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

Updated to remove the CONTENT_EXPORT ... I'll address the other points later this week,

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'patches/add-clipboard-create-override-mechanism.patch'
2--- patches/add-clipboard-create-override-mechanism.patch 1970-01-01 00:00:00 +0000
3+++ patches/add-clipboard-create-override-mechanism.patch 2015-05-26 19:17:26 +0000
4@@ -0,0 +1,15 @@
5+diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp
6+index 29fac97..43427a7 100644
7+--- a/ui/base/ui_base.gyp
8++++ b/ui/base/ui_base.gyp
9+@@ -58,8 +58,8 @@
10+ 'clipboard/clipboard.h',
11+ 'clipboard/clipboard_android.cc',
12+ 'clipboard/clipboard_android.h',
13+- 'clipboard/clipboard_aura.cc',
14+- 'clipboard/clipboard_aura.h',
15++ '<(DEPTH)/../../../shared/port/ui_base/clipboard_oxide.cc',
16++ '<(DEPTH)/../../../shared/port/ui_base/clipboard_oxide.h',
17+ 'clipboard/clipboard_aurax11.cc',
18+ 'clipboard/clipboard_aurax11.h',
19+ 'clipboard/clipboard_constants.cc',
20
21=== modified file 'patches/series'
22--- patches/series 2015-04-21 18:34:44 +0000
23+++ patches/series 2015-05-26 19:17:26 +0000
24@@ -30,3 +30,4 @@
25 allow-render-widget-compositor-settings-override.patch
26 pulse-audio-role.patch
27 enable-accelerated-canvas-on-arale.patch
28+add-clipboard-create-override-mechanism.patch
29\ No newline at end of file
30
31=== modified file 'qt/core/browser/oxide_qt_browser_platform_integration.cc'
32--- qt/core/browser/oxide_qt_browser_platform_integration.cc 2015-05-19 18:02:42 +0000
33+++ qt/core/browser/oxide_qt_browser_platform_integration.cc 2015-05-26 19:17:26 +0000
34@@ -40,6 +40,7 @@
35 #include "oxide_qt_browser_thread_q_event_dispatcher.h"
36 #include "oxide_qt_location_provider.h"
37 #include "oxide_qt_message_pump.h"
38+#include "oxide_qt_clipboard.h"
39
40 namespace oxide {
41 namespace qt {
42@@ -189,6 +190,10 @@
43 QGuiApplication::instance()->removeEventFilter(this);
44 }
45
46+ui::ClipboardOxideFactory BrowserPlatformIntegration::GetClipboardOxideFactory() {
47+ return ClipboardQt::DoCreate;
48+}
49+
50 QThread* GetIOQThread() {
51 return g_io_thread.Get();
52 }
53
54=== modified file 'qt/core/browser/oxide_qt_browser_platform_integration.h'
55--- qt/core/browser/oxide_qt_browser_platform_integration.h 2015-05-19 18:02:42 +0000
56+++ qt/core/browser/oxide_qt_browser_platform_integration.h 2015-05-26 19:17:26 +0000
57@@ -58,6 +58,7 @@
58 content::LocationProvider* CreateLocationProvider() override;
59 ApplicationState GetApplicationState() override;
60 std::string GetApplicationLocale() override;
61+ ui::ClipboardOxideFactory GetClipboardOxideFactory() override;
62
63 // QObject implementation
64 bool eventFilter(QObject* watched, QEvent* event) override;
65
66=== added file 'qt/core/browser/oxide_qt_clipboard.cc'
67--- qt/core/browser/oxide_qt_clipboard.cc 1970-01-01 00:00:00 +0000
68+++ qt/core/browser/oxide_qt_clipboard.cc 2015-05-26 19:17:26 +0000
69@@ -0,0 +1,408 @@
70+// vim:expandtab:shiftwidth=2:tabstop=2:
71+// Copyright (C) 2015 Canonical Ltd.
72+
73+// This library is free software; you can redistribute it and/or
74+// modify it under the terms of the GNU Lesser General Public
75+// License as published by the Free Software Foundation; either
76+// version 2.1 of the License, or (at your option) any later version.
77+
78+// This library is distributed in the hope that it will be useful,
79+// but WITHOUT ANY WARRANTY; without even the implied warranty of
80+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
81+// Lesser General Public License for more details.
82+
83+// You should have received a copy of the GNU Lesser General Public
84+// License along with this library; if not, write to the Free Software
85+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
86+
87+#include "oxide_qt_clipboard.h"
88+
89+#include <list>
90+#include <set>
91+
92+#include "base/basictypes.h"
93+#include "base/files/file_path.h"
94+#include "base/logging.h"
95+#include "base/memory/ref_counted_memory.h"
96+#include "base/memory/scoped_ptr.h"
97+#include "base/memory/singleton.h"
98+#include "base/metrics/histogram.h"
99+#include "base/stl_util.h"
100+#include "base/strings/utf_string_conversions.h"
101+#include "third_party/skia/include/core/SkBitmap.h"
102+#include "third_party/skia/include/core/SkImageInfo.h"
103+#include "ui/base/clipboard/custom_data_helper.h"
104+#include "ui/events/platform/platform_event_dispatcher.h"
105+#include "ui/events/platform/platform_event_observer.h"
106+#include "ui/events/platform/platform_event_source.h"
107+#include "ui/gfx/codec/png_codec.h"
108+#include "ui/gfx/geometry/size.h"
109+
110+#include <QDebug>
111+#include <QClipboard>
112+#include <QGuiApplication>
113+#include <QImage>
114+#include <QMimeData>
115+#include <QObject>
116+#include <QString>
117+
118+
119+#define GET_CLIPBOARD_DATA(c) \
120+ c->mimeData( \
121+ type == ui::CLIPBOARD_TYPE_COPY_PASTE ? \
122+ QClipboard::Clipboard \
123+ : QClipboard::Selection)
124+
125+class ClipboardChangedListener : public QObject {
126+ Q_OBJECT
127+
128+ public:
129+ ClipboardChangedListener();
130+ uint64 clipboard_sequence_number() const {
131+ return clipboard_sequence_number_;
132+ }
133+ uint64 selection_sequence_number() const {
134+ return selection_sequence_number_;
135+ }
136+ private Q_SLOTS:
137+ void OnClipboardDataChanged(QClipboard::Mode mode);
138+ private:
139+ uint64 clipboard_sequence_number_;
140+ uint64 selection_sequence_number_;
141+
142+ Q_DISABLE_COPY(ClipboardChangedListener);
143+};
144+
145+ClipboardChangedListener::ClipboardChangedListener()
146+ : clipboard_sequence_number_(0),
147+ selection_sequence_number_(0) {
148+ QObject::connect(
149+ QGuiApplication::clipboard(),
150+ SIGNAL(changed(QClipboard::Mode)),
151+ this,
152+ SLOT(OnClipboardDataChanged(QClipboard::Mode)));
153+}
154+
155+void ClipboardChangedListener::OnClipboardDataChanged(
156+ QClipboard::Mode mode) {
157+ switch (mode) {
158+ case QClipboard::Clipboard:
159+ ++clipboard_sequence_number_;
160+ break;
161+ case QClipboard::Selection:
162+ ++selection_sequence_number_;
163+ break;
164+ default:
165+ break;
166+ }
167+}
168+
169+namespace oxide {
170+
171+namespace qt {
172+
173+namespace {
174+
175+const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
176+
177+}
178+
179+///////////////////////////////////////////////////////////////////////////////
180+// ClipboardAuraX11
181+
182+ClipboardQt::ClipboardQt()
183+ : clipboard_changed_listener_(new ClipboardChangedListener()),
184+ write_mime_data_acc_(new QMimeData()) {
185+ DCHECK(CalledOnValidThread());
186+}
187+
188+ui::Clipboard* ClipboardQt::DoCreate() {
189+ return new ClipboardQt();
190+}
191+
192+ClipboardQt::~ClipboardQt() {
193+ DCHECK(CalledOnValidThread());
194+}
195+
196+uint64 ClipboardQt::GetSequenceNumber(ui::ClipboardType type) const {
197+ DCHECK(CalledOnValidThread());
198+ return type == ui::CLIPBOARD_TYPE_COPY_PASTE
199+ ? clipboard_changed_listener_->clipboard_sequence_number()
200+ : clipboard_changed_listener_->selection_sequence_number();
201+}
202+
203+bool ClipboardQt::IsFormatAvailable(const FormatType& format,
204+ ui::ClipboardType type) const {
205+ DCHECK(CalledOnValidThread());
206+ DCHECK(IsSupportedClipboardType(type));
207+
208+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
209+ if ( ! data) {
210+ return false;
211+ }
212+
213+ return data->hasFormat(format.ToString().c_str());
214+}
215+
216+void ClipboardQt::Clear(ui::ClipboardType type) {
217+ DCHECK(CalledOnValidThread());
218+ DCHECK(IsSupportedClipboardType(type));
219+ QGuiApplication::clipboard()->clear();
220+}
221+
222+void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type,
223+ std::vector<base::string16>* types,
224+ bool* contains_filenames) const {
225+ DCHECK(IsSupportedClipboardType(type));
226+ DCHECK(CalledOnValidThread());
227+ DCHECK(types != nullptr);
228+ DCHECK(contains_filenames != nullptr);
229+
230+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
231+ if ( ! data) {
232+ return;
233+ }
234+
235+ *contains_filenames = false;
236+ Q_FOREACH (const QString& format, data->formats()) {
237+ types->push_back(base::UTF8ToUTF16(format.toUtf8().data()));
238+
239+ if (format == GetFilenameFormatType().ToString().c_str()) {
240+ *contains_filenames = true;
241+ }
242+ }
243+}
244+
245+void ClipboardQt::ReadText(ui::ClipboardType type,
246+ base::string16* result) const {
247+ DCHECK(IsSupportedClipboardType(type));
248+ DCHECK(CalledOnValidThread());
249+
250+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
251+ if ( ! data || ! data->hasText()) {
252+ return;
253+ }
254+
255+ *result = base::UTF8ToUTF16(data->text().toUtf8().data());
256+}
257+
258+void ClipboardQt::ReadAsciiText(ui::ClipboardType type,
259+ std::string* result) const {
260+ DCHECK(IsSupportedClipboardType(type));
261+ DCHECK(CalledOnValidThread());
262+
263+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
264+ if ( ! data || ! data->hasText()) {
265+ return;
266+ }
267+
268+ *result = data->text().toStdString().c_str();
269+}
270+
271+void ClipboardQt::ReadHTML(ui::ClipboardType type,
272+ base::string16* markup,
273+ std::string* src_url,
274+ uint32* fragment_start,
275+ uint32* fragment_end) const {
276+ DCHECK(IsSupportedClipboardType(type));
277+ DCHECK(CalledOnValidThread());
278+
279+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
280+ if ( ! data || ! data->hasHtml()) {
281+ return;
282+ }
283+
284+ *markup = base::UTF8ToUTF16(data->html().toStdString());
285+ *fragment_start = 0;
286+ DCHECK(markup->length() <= kuint32max);
287+ *fragment_end = static_cast<uint32>(markup->length());
288+}
289+
290+void ClipboardQt::ReadRTF(ui::ClipboardType type, std::string* result) const {
291+ DCHECK(IsSupportedClipboardType(type));
292+ DCHECK(CalledOnValidThread());
293+
294+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
295+ if ( ! data || ! data->hasFormat(QString::fromLatin1(kMimeTypeRTF))) {
296+ return;
297+ }
298+
299+ *result = data->data(QString::fromLatin1(kMimeTypeRTF)).data();
300+}
301+
302+SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const {
303+ DCHECK(IsSupportedClipboardType(type));
304+ DCHECK(CalledOnValidThread());
305+
306+ const QMimeData *md = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
307+ if ( ! md) {
308+ return SkBitmap();
309+ }
310+
311+ QImage image;
312+ if (md->hasImage()) {
313+ image = qvariant_cast<QImage>(md->imageData());
314+ /**
315+ * ReadImage() is called from Blink when 'clipboardData.getAsFile'
316+ * is called with a forced explicit mime type of 'image/png'.
317+ *
318+ * See third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
319+ */
320+ } else if (md->hasFormat(Clipboard::kMimeTypePNG)) {
321+ image.loadFromData(md->data(Clipboard::kMimeTypePNG), "PNG");
322+ } else {
323+ return SkBitmap();
324+ }
325+
326+ if (image.format() != QImage::Format_RGBA8888) {
327+ image.convertToFormat(QImage::Format_RGBA8888);
328+ }
329+
330+ SkBitmap bitmap;
331+ bitmap.setInfo(
332+ SkImageInfo::MakeN32(
333+ image.width(),
334+ image.height(),
335+ kOpaque_SkAlphaType));
336+
337+ bitmap.setPixels(const_cast<uchar*>(image.constBits()));
338+
339+ // Force a deep copy of the image data
340+ SkBitmap copy;
341+ bitmap.copyTo(&copy, kN32_SkColorType);
342+ return copy;
343+}
344+
345+void ClipboardQt::ReadCustomData(ui::ClipboardType type,
346+ const base::string16& data_type,
347+ base::string16* result) const {
348+ DCHECK(CalledOnValidThread());
349+ DCHECK(IsSupportedClipboardType(type));
350+
351+ const QMimeData *data = GET_CLIPBOARD_DATA(QGuiApplication::clipboard());
352+ QString mime_type = QString::fromStdString(base::UTF16ToUTF8(data_type));
353+ if ( ! data || ! data->hasFormat(mime_type)) {
354+ return;
355+ }
356+
357+ ui::ReadCustomDataForType(
358+ data->data(mime_type).constData(),
359+ data->data(mime_type).size(),
360+ data_type,
361+ result);
362+}
363+
364+void ClipboardQt::ReadBookmark(base::string16* title,
365+ std::string* url) const {
366+ NOTIMPLEMENTED();
367+}
368+
369+void ClipboardQt::ReadData(const FormatType& format,
370+ std::string* result) const {
371+ DCHECK(CalledOnValidThread());
372+
373+ const QMimeData *data = QGuiApplication::clipboard()->mimeData(QClipboard::Clipboard);
374+ if ( ! data) {
375+ return;
376+ }
377+
378+ *result = data->data(format.ToString().c_str()).data();
379+}
380+
381+void ClipboardQt::WriteObjects(ui::ClipboardType type,
382+ const ObjectMap& objects) {
383+ DCHECK(CalledOnValidThread());
384+ DCHECK(IsSupportedClipboardType(type));
385+
386+ if (! write_mime_data_acc_) {
387+ write_mime_data_acc_.reset(new QMimeData());
388+ }
389+
390+ // dispatch all objects and gather the resulting mime data
391+ for (ObjectMap::const_iterator iter = objects.begin();
392+ iter != objects.end();
393+ ++iter) {
394+ DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
395+ }
396+
397+ QGuiApplication::clipboard()->setMimeData(
398+ write_mime_data_acc_.release(),
399+ type == ui::CLIPBOARD_TYPE_COPY_PASTE
400+ ? QClipboard::Clipboard
401+ : QClipboard::Selection);
402+}
403+
404+void ClipboardQt::WriteText(const char* text_data, size_t text_len) {
405+ write_mime_data_acc_->setText(QString::fromUtf8(text_data, text_len));
406+}
407+
408+void ClipboardQt::WriteHTML(const char* markup_data,
409+ size_t markup_len,
410+ const char* url_data,
411+ size_t url_len) {
412+ write_mime_data_acc_->setHtml(
413+ QString::fromUtf8(markup_data, markup_len));
414+}
415+
416+void ClipboardQt::WriteRTF(const char* rtf_data, size_t data_len) {
417+ write_mime_data_acc_->setData(QString::fromLatin1(kMimeTypeRTF), QByteArray(rtf_data, data_len));
418+}
419+
420+void ClipboardQt::WriteBookmark(const char* title_data,
421+ size_t title_len,
422+ const char* url_data,
423+ size_t url_len) {
424+ NOTIMPLEMENTED();
425+}
426+
427+void ClipboardQt::WriteWebSmartPaste() {
428+ write_mime_data_acc_->setData(
429+ QString::fromLatin1(kMimeTypeWebkitSmartPaste),
430+ QByteArray());
431+}
432+
433+void ClipboardQt::WriteBitmap(const SkBitmap& bitmap) {
434+ QImage image;
435+ if (bitmap.info().colorType() != kN32_SkColorType) {
436+ SkImageInfo info =
437+ SkImageInfo::MakeN32(
438+ bitmap.width(),
439+ bitmap.height(),
440+ bitmap.alphaType());
441+
442+ SkBitmap convertedBitmap;
443+ if (!convertedBitmap.tryAllocPixels(info)) {
444+ return;
445+ }
446+
447+ bitmap.readPixels(
448+ info,
449+ convertedBitmap.getPixels(),
450+ 0, 0, 0);
451+
452+ image = QImage(reinterpret_cast<const uchar *>(convertedBitmap.getPixels()),
453+ bitmap.width(),
454+ bitmap.height(),
455+ QImage::Format_RGBA8888);
456+ } else {
457+ image = QImage(reinterpret_cast<const uchar *>(bitmap.getPixels()),
458+ bitmap.width(),
459+ bitmap.height(),
460+ QImage::Format_RGBA8888);
461+ }
462+
463+ write_mime_data_acc_->setImageData(image.copy());
464+}
465+
466+void ClipboardQt::WriteData(const FormatType& format,
467+ const char* data_data,
468+ size_t data_len) {
469+ write_mime_data_acc_->setData(
470+ QString::fromStdString(format.ToString()),
471+ QByteArray(data_data, data_len));
472+}
473+
474+} // namespace qt
475+} // namespace oxide
476+
477+#include "oxide_qt_clipboard.moc"
478
479=== added file 'qt/core/browser/oxide_qt_clipboard.h'
480--- qt/core/browser/oxide_qt_clipboard.h 1970-01-01 00:00:00 +0000
481+++ qt/core/browser/oxide_qt_clipboard.h 2015-05-26 19:17:26 +0000
482@@ -0,0 +1,94 @@
483+// vim:expandtab:shiftwidth=2:tabstop=2:
484+// Copyright (C) 2015 Canonical Ltd.
485+
486+// This library is free software; you can redistribute it and/or
487+// modify it under the terms of the GNU Lesser General Public
488+// License as published by the Free Software Foundation; either
489+// version 2.1 of the License, or (at your option) any later version.
490+
491+// This library is distributed in the hope that it will be useful,
492+// but WITHOUT ANY WARRANTY; without even the implied warranty of
493+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
494+// Lesser General Public License for more details.
495+
496+// You should have received a copy of the GNU Lesser General Public
497+// License along with this library; if not, write to the Free Software
498+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
499+
500+#ifndef _OXIDE_QT_CORE_BROWSER_CLIPBOARD_QT_H_
501+#define _OXIDE_QT_CORE_BROWSER_CLIPBOARD_QT_H_
502+
503+#include "ui/base/clipboard/clipboard.h"
504+
505+#include "base/memory/scoped_ptr.h"
506+
507+class QMimeData;
508+class ClipboardChangedListener;
509+
510+namespace oxide {
511+namespace qt {
512+
513+class ClipboardQt : public ui::Clipboard {
514+ public:
515+
516+ static Clipboard* DoCreate();
517+
518+ private:
519+
520+ ClipboardQt();
521+ ~ClipboardQt() override;
522+
523+ // Clipboard overrides
524+
525+ uint64 GetSequenceNumber(ui::ClipboardType type) const override;
526+ bool IsFormatAvailable(const FormatType& format,
527+ ui::ClipboardType type) const override;
528+ void Clear(ui::ClipboardType type) override;
529+ void ReadAvailableTypes(ui::ClipboardType type,
530+ std::vector<base::string16>* types,
531+ bool* contains_filenames) const override;
532+ void ReadText(ui::ClipboardType type, base::string16* result) const override;
533+ void ReadAsciiText(ui::ClipboardType type, std::string* result) const override;
534+ void ReadHTML(ui::ClipboardType type,
535+ base::string16* markup,
536+ std::string* src_url,
537+ uint32* fragment_start,
538+ uint32* fragment_end) const override;
539+ void ReadRTF(ui::ClipboardType type, std::string* result) const override;
540+ SkBitmap ReadImage(ui::ClipboardType type) const override;
541+ void ReadCustomData(ui::ClipboardType clipboard_type,
542+ const base::string16& type,
543+ base::string16* result) const override;
544+ void ReadBookmark(base::string16* title, std::string* url) const override;
545+ void ReadData(const FormatType& format, std::string* result) const override;
546+ void WriteObjects(ui::ClipboardType type, const ui::Clipboard::ObjectMap& objects) override;
547+ void WriteText(const char* text_data, size_t text_len) override;
548+ void WriteHTML(const char* markup_data,
549+ size_t markup_len,
550+ const char* url_data,
551+ size_t url_len) override;
552+ void WriteRTF(const char* rtf_data, size_t data_len) override;
553+ void WriteBookmark(const char* title_data,
554+ size_t title_len,
555+ const char* url_data,
556+ size_t url_len) override;
557+ void WriteWebSmartPaste() override;
558+ void WriteBitmap(const SkBitmap& bitmap) override;
559+ void WriteData(const FormatType& format,
560+ const char* data_data,
561+ size_t data_len) override;
562+
563+ private:
564+
565+ scoped_ptr<ClipboardChangedListener> clipboard_changed_listener_;
566+
567+ // Used for accumulated mimedata
568+ scoped_ptr<QMimeData> write_mime_data_acc_;
569+
570+ DISALLOW_COPY_AND_ASSIGN(ClipboardQt);
571+};
572+
573+} // namespace qt
574+} // namespace oxide
575+
576+#endif // _OXIDE_QT_CORE_BROWSER_CLIPBOARD_QT_H_
577
578=== modified file 'qt/core/core.gyp'
579--- qt/core/core.gyp 2015-05-19 10:08:59 +0000
580+++ qt/core/core.gyp 2015-05-26 19:17:26 +0000
581@@ -68,6 +68,8 @@
582 'browser/oxide_qt_browser_startup.h',
583 'browser/oxide_qt_browser_thread_q_event_dispatcher.cc',
584 'browser/oxide_qt_browser_thread_q_event_dispatcher.h',
585+ 'browser/oxide_qt_clipboard.cc',
586+ 'browser/oxide_qt_clipboard.h',
587 'browser/oxide_qt_file_picker.cc',
588 'browser/oxide_qt_file_picker.h',
589 'browser/oxide_qt_javascript_dialog.cc',
590@@ -134,6 +136,11 @@
591 ],
592 'actions': [
593 {
594+ 'action_name': 'oxide_qt_clipboard.moc',
595+ 'moc_input': 'browser/oxide_qt_clipboard.cc',
596+ 'includes': [ 'moc.gypi' ]
597+ },
598+ {
599 'action_name': 'oxide_qt_location_provider.moc',
600 'moc_input': 'browser/oxide_qt_location_provider.cc',
601 'includes': [ 'moc.gypi' ]
602
603=== added file 'qt/tests/qmltests/core/tst_Clipboard.html'
604--- qt/tests/qmltests/core/tst_Clipboard.html 1970-01-01 00:00:00 +0000
605+++ qt/tests/qmltests/core/tst_Clipboard.html 2015-05-26 19:17:26 +0000
606@@ -0,0 +1,33 @@
607+<html>
608+<body>
609+ <h1>Clipboard</h1>
610+
611+ <textarea id="content"></textarea>
612+
613+ <span id="mime_type"></span>
614+ <span id="has_file"></span>
615+
616+ <script>
617+
618+ window.onload = function() {
619+
620+ document.addEventListener("paste", function(e) {
621+ for (var i = 0; i < e.clipboardData.items.length; ++i) {
622+ document.getElementById("mime_type").innerHTML = e.clipboardData.items[i].type;
623+ var blob = e.clipboardData.items[i].getAsFile();
624+ document.getElementById("has_file").innerHTML = (blob != null) ? "true" : "false";
625+ if (blob) {
626+ var reader = new FileReader();
627+ reader.addEventListener("loadend", function(e) {
628+ document.getElementById("content").value = reader.result.substr(String("data:image/png;base64,").length)
629+ });
630+ reader.readAsDataURL(blob);
631+ }
632+ }
633+ }, true);
634+
635+ }
636+ </script>
637+
638+</body>
639+</html>
640
641=== added file 'qt/tests/qmltests/core/tst_Clipboard.qml'
642--- qt/tests/qmltests/core/tst_Clipboard.qml 1970-01-01 00:00:00 +0000
643+++ qt/tests/qmltests/core/tst_Clipboard.qml 2015-05-26 19:17:26 +0000
644@@ -0,0 +1,129 @@
645+import QtQuick 2.0
646+import QtTest 1.0
647+import com.canonical.Oxide 1.0
648+import com.canonical.Oxide.Testing 1.0
649+
650+TestWebView {
651+ id: webView
652+
653+ focus: true
654+
655+ width: 200
656+ height: 200
657+
658+ function expect_content(expected, rangemax) {
659+ var result = webView.getTestApi().evaluateCode(
660+ "return document.querySelector('#content').value", true);
661+ if (!rangemax) {
662+ rangemax = -1
663+ }
664+ return String(result).substr(0, rangemax) === expected.substr(0, rangemax);
665+ }
666+
667+ function expect_has_file(expected) {
668+ var result = webView.getTestApi().evaluateCode(
669+ "return document.querySelector('#has_file').innerHTML", true);
670+ if (result == 'true') {
671+ result = true
672+ } else if (result == 'false') {
673+ result = false
674+ } else {
675+ return false
676+ }
677+ return (result === expected);
678+ }
679+
680+ function expect_mime_type(expected) {
681+ var result = webView.getTestApi().evaluateCode(
682+ "return document.querySelector('#mime_type').innerHTML", true);
683+ return (result === expected);
684+ }
685+
686+ function select_textarea_content() {
687+ webView.getTestApi().evaluateCode(
688+ "document.querySelector('#content').select()", true);
689+ }
690+
691+ function set_content(content) {
692+ webView.getTestApi().evaluateCode(
693+ "document.querySelector('#content').value = '" + content + "'", true);
694+ }
695+
696+ function get_image_data() {
697+ return "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGUlEQVQIHQEOAPH/AAAAAAAAAAAAAAAAAAAADgABd6ch7AAAAABJRU5ErkJggg=="
698+ }
699+
700+ TestCase {
701+ id: testcase
702+ name: "clipboard"
703+
704+ when: windowShown
705+
706+ function setup() {
707+ OxideTestingUtils.clearClipboard();
708+ }
709+
710+ function test_paste_data() {
711+ return [
712+ { content: "content", mimeType: "text/plain" },
713+ { content: get_image_data(), mimeType: "image/png"},
714+ { content: "<div><a href=\"#\">Test</a></div>", mimeType: "text/html"},
715+ ];
716+ }
717+
718+ function test_paste(data) {
719+ var isImage = (data.mimeType.indexOf("image/") === 0)
720+
721+ OxideTestingUtils.copyToClipboard(data.mimeType, data.content);
722+
723+ webView.url = "http://testsuite/tst_Clipboard.html";
724+
725+ verify(webView.waitForLoadSucceeded(), "Timed out waiting for successful load");
726+
727+ if ( ! isImage) {
728+ select_textarea_content();
729+ }
730+ keyPress("v", Qt.ControlModifier)
731+
732+ verify(webView.waitFor(function() { return expect_mime_type(data.mimeType); }));
733+ verify(webView.waitFor(function() { return expect_has_file(isImage); }));
734+
735+ if (isImage) {
736+ /**
737+ The image we get from QImage and the one we pasted are slightly different
738+ but overall is the same image. QImage does ARGB -> RGBA conversion
739+ on the raw image content
740+ that slightly alters it and make it hard to have an exact match.
741+
742+ The '34' magic number in this case has been empirically determined as the
743+ maximum amount of content that stays the same after the conversion in this
744+ context.
745+ */
746+ verify(webView.waitFor(function() { return expect_content(data.content, 34); }));
747+ } else {
748+ verify(webView.waitFor(function() { return expect_content(data.content); }));
749+ }
750+ }
751+
752+ function test_copy() {
753+ webView.url = "http://testsuite/tst_Clipboard.html";
754+
755+ verify(webView.waitForLoadSucceeded(), "Timed out waiting for successful load");
756+
757+ var data_content = "content"
758+ set_content(data_content)
759+
760+ webView.waitFor(function() { return expect_content(data_content); });
761+
762+ select_textarea_content();
763+
764+ keyPress("c", Qt.ControlModifier)
765+
766+ verify(webView.waitFor(function() {
767+ var current_content = OxideTestingUtils.getFromClipboard(
768+ "text/plain");
769+ return current_content === data_content
770+ }));
771+ }
772+ }
773+}
774
775=== modified file 'qt/tests/qmltests/oxide_qml_testing_plugin.cc'
776--- qt/tests/qmltests/oxide_qml_testing_plugin.cc 2015-05-06 17:53:22 +0000
777+++ qt/tests/qmltests/oxide_qml_testing_plugin.cc 2015-05-26 19:17:26 +0000
778@@ -19,8 +19,10 @@
779 #include <sys/types.h>
780 #include <unistd.h>
781
782+#include <QClipboard>
783 #include <QCoreApplication>
784 #include <QDesktopServices>
785+#include <QGuiApplication>
786 #include <QLatin1String>
787 #include <QList>
788 #include <QQmlContext>
789@@ -163,7 +165,7 @@
790 }
791
792 Q_INVOKABLE QVariant getAppProperty(const QString& property) {
793- QCoreApplication::instance()->property(property.toStdString().c_str());
794+ return QCoreApplication::instance()->property(property.toStdString().c_str());
795 }
796
797 Q_INVOKABLE void setAppProperty(const QString& property, const QVariant& value) {
798@@ -189,6 +191,28 @@
799 }
800 }
801 }
802+
803+ Q_INVOKABLE void copyToClipboard(const QString& mimeType, const QString& data) {
804+ QMimeData * mime_data = new QMimeData();
805+ if (mimeType.startsWith("image/")) {
806+ mime_data->setData(mimeType, QByteArray::fromBase64(data.toUtf8()));
807+ } else {
808+ mime_data->setData(mimeType, data.toUtf8());
809+ }
810+ QGuiApplication::clipboard()->setMimeData(mime_data);
811+ }
812+
813+ Q_INVOKABLE QString getFromClipboard(const QString& mimeType) {
814+ const QMimeData * mime_data = QGuiApplication::clipboard()->mimeData();
815+ if (mime_data->hasFormat(mimeType)) {
816+ return QString(mime_data->data(mimeType));
817+ }
818+ return QString();
819+ }
820+
821+ Q_INVOKABLE void clearClipboard() {
822+ QGuiApplication::clipboard()->clear();
823+ }
824 };
825
826 QObject* UtilsFactory(QQmlEngine* engine, QJSEngine* script_engine) {
827
828=== modified file 'shared/browser/oxide_browser_main_parts.cc'
829--- shared/browser/oxide_browser_main_parts.cc 2015-05-26 13:25:16 +0000
830+++ shared/browser/oxide_browser_main_parts.cc 2015-05-26 19:17:26 +0000
831@@ -43,6 +43,7 @@
832 #include "shared/port/content/common/gpu_service_shim_oxide.h"
833 #include "shared/port/gfx/gfx_utils_oxide.h"
834 #include "shared/port/gpu_config/gpu_info_collector_oxide_linux.h"
835+#include "shared/port/ui_base/clipboard_oxide.h"
836
837 #include "oxide_browser_context.h"
838 #include "oxide_browser_platform_integration.h"
839@@ -193,6 +194,9 @@
840 content::SetWebContentsViewOxideFactory(WebContentsView::Create);
841 content::SetPowerSaveBlockerOxideDelegateFactory(CreatePowerSaveBlocker);
842
843+ ui::SetClipboardOxideFactory(
844+ BrowserPlatformIntegration::GetInstance()->GetClipboardOxideFactory());
845+
846 gfx::InitializeOxideNativeDisplay(
847 BrowserPlatformIntegration::GetInstance()->GetNativeDisplay());
848
849
850=== modified file 'shared/browser/oxide_browser_platform_integration.cc'
851--- shared/browser/oxide_browser_platform_integration.cc 2015-03-24 17:06:40 +0000
852+++ shared/browser/oxide_browser_platform_integration.cc 2015-05-26 19:17:26 +0000
853@@ -90,4 +90,9 @@
854 ApplicationStateChanged());
855 }
856
857+ui::ClipboardOxideFactory
858+BrowserPlatformIntegration::GetClipboardOxideFactory() {
859+ return nullptr;
860+}
861+
862 } // namespace oxide
863
864=== modified file 'shared/browser/oxide_browser_platform_integration.h'
865--- shared/browser/oxide_browser_platform_integration.h 2015-05-19 18:02:42 +0000
866+++ shared/browser/oxide_browser_platform_integration.h 2015-05-26 19:17:26 +0000
867@@ -24,6 +24,9 @@
868 #include "content/public/browser/browser_thread.h"
869 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
870
871+#include "shared/port/ui_base/clipboard_oxide.h"
872+
873+
874 class GURL;
875
876 namespace content {
877@@ -80,6 +83,8 @@
878 // the applications UI event loop
879 virtual scoped_ptr<MessagePump> CreateUIMessagePump() = 0;
880
881+ virtual ui::ClipboardOxideFactory GetClipboardOxideFactory();
882+
883 // Called on the specified browser thread
884 virtual void BrowserThreadInit(content::BrowserThread::ID id);
885 virtual void BrowserThreadCleanUp(content::BrowserThread::ID id);
886
887=== added directory 'shared/port/ui_base'
888=== added file 'shared/port/ui_base/clipboard_oxide.cc'
889--- shared/port/ui_base/clipboard_oxide.cc 1970-01-01 00:00:00 +0000
890+++ shared/port/ui_base/clipboard_oxide.cc 2015-05-26 19:17:26 +0000
891@@ -0,0 +1,260 @@
892+// vim:expandtab:shiftwidth=2:tabstop=2:
893+// Copyright (C) 2015 Canonical Ltd.
894+
895+// This library is free software; you can redistribute it and/or
896+// modify it under the terms of the GNU Lesser General Public
897+// License as published by the Free Software Foundation; either
898+// version 2.1 of the License, or (at your option) any later version.
899+
900+// This library is distributed in the hope that it will be useful,
901+// but WITHOUT ANY WARRANTY; without even the implied warranty of
902+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
903+// Lesser General Public License for more details.
904+
905+// You should have received a copy of the GNU Lesser General Public
906+// License along with this library; if not, write to the Free Software
907+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
908+
909+#include "clipboard_oxide.h"
910+
911+#include "base/basictypes.h"
912+#include "ui/base/clipboard/custom_data_helper.h"
913+#include "third_party/skia/include/core/SkBitmap.h"
914+
915+namespace ui {
916+
917+namespace {
918+
919+const char kMimeTypeFilename[] = "chromium/filename";
920+const char kMimeTypeBitmap[] = "image/bmp";
921+const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
922+const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
923+
924+ClipboardOxideFactory g_clipboard_factory;
925+
926+} // namespace
927+
928+
929+void SetClipboardOxideFactory(ClipboardOxideFactory factory) {
930+ g_clipboard_factory = factory;
931+}
932+
933+// Clipboard factory method.
934+Clipboard* Clipboard::Create() {
935+ if (g_clipboard_factory) {
936+ return g_clipboard_factory();
937+ }
938+ return new ClipboardOxide;
939+}
940+
941+
942+// Clipboard::FormatType implementation.
943+Clipboard::FormatType::FormatType() {
944+}
945+
946+Clipboard::FormatType::FormatType(const std::string& native_format)
947+ : data_(native_format) {
948+}
949+
950+Clipboard::FormatType::~FormatType() {
951+}
952+
953+std::string Clipboard::FormatType::Serialize() const {
954+ return data_;
955+}
956+
957+// static
958+Clipboard::FormatType Clipboard::FormatType::Deserialize(
959+ const std::string& serialization) {
960+ return FormatType(serialization);
961+}
962+
963+bool Clipboard::FormatType::operator<(const FormatType& other) const {
964+ return data_ < other.data_;
965+}
966+
967+bool Clipboard::FormatType::Equals(const FormatType& other) const {
968+ return data_ == other.data_;
969+}
970+
971+// Various predefined FormatTypes.
972+// static
973+Clipboard::FormatType Clipboard::GetFormatType(
974+ const std::string& format_string) {
975+ return FormatType::Deserialize(format_string);
976+}
977+
978+// static
979+const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
980+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
981+ return type;
982+}
983+
984+// static
985+const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
986+ return GetUrlFormatType();
987+}
988+
989+// static
990+const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
991+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
992+ return type;
993+}
994+
995+// static
996+const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
997+ return GetPlainTextFormatType();
998+}
999+
1000+// static
1001+const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
1002+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
1003+ return type;
1004+}
1005+
1006+// static
1007+const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
1008+ return Clipboard::GetFilenameFormatType();
1009+}
1010+
1011+// static
1012+const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
1013+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
1014+ return type;
1015+}
1016+
1017+// static
1018+const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
1019+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
1020+ return type;
1021+}
1022+
1023+// static
1024+const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
1025+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
1026+ return type;
1027+}
1028+
1029+// static
1030+const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
1031+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
1032+ return type;
1033+}
1034+
1035+// static
1036+const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
1037+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
1038+ return type;
1039+}
1040+
1041+// static
1042+const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
1043+ CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
1044+ return type;
1045+}
1046+
1047+ClipboardOxide::ClipboardOxide() {
1048+ DCHECK(CalledOnValidThread());
1049+}
1050+
1051+ClipboardOxide::~ClipboardOxide() {
1052+ DCHECK(CalledOnValidThread());
1053+}
1054+
1055+uint64 ClipboardOxide::GetSequenceNumber(ClipboardType type) const {
1056+ DCHECK(CalledOnValidThread());
1057+ return uint64();
1058+}
1059+
1060+bool ClipboardOxide::IsFormatAvailable(const FormatType& format,
1061+ ClipboardType type) const {
1062+ DCHECK(CalledOnValidThread());
1063+ return false;
1064+}
1065+
1066+void ClipboardOxide::Clear(ClipboardType type) {
1067+ DCHECK(CalledOnValidThread());
1068+}
1069+
1070+void ClipboardOxide::ReadAvailableTypes(ClipboardType type,
1071+ std::vector<base::string16>* types,
1072+ bool* contains_filenames) const {
1073+ DCHECK(CalledOnValidThread());
1074+}
1075+
1076+void ClipboardOxide::ReadText(ClipboardType type, base::string16* result) const {
1077+ DCHECK(CalledOnValidThread());
1078+}
1079+
1080+void ClipboardOxide::ReadAsciiText(ClipboardType type,
1081+ std::string* result) const {
1082+ DCHECK(CalledOnValidThread());
1083+}
1084+
1085+void ClipboardOxide::ReadHTML(ClipboardType type,
1086+ base::string16* markup,
1087+ std::string* src_url,
1088+ uint32* fragment_start,
1089+ uint32* fragment_end) const {
1090+ DCHECK(CalledOnValidThread());
1091+}
1092+
1093+void ClipboardOxide::ReadRTF(ClipboardType type, std::string* result) const {
1094+ DCHECK(CalledOnValidThread());
1095+}
1096+
1097+SkBitmap ClipboardOxide::ReadImage(ClipboardType type) const {
1098+ DCHECK(CalledOnValidThread());
1099+ return SkBitmap();
1100+}
1101+
1102+void ClipboardOxide::ReadCustomData(ClipboardType clipboard_type,
1103+ const base::string16& type,
1104+ base::string16* result) const {
1105+ DCHECK(CalledOnValidThread());
1106+}
1107+
1108+void ClipboardOxide::ReadBookmark(base::string16* title,
1109+ std::string* url) const {
1110+ DCHECK(CalledOnValidThread());
1111+}
1112+
1113+void ClipboardOxide::ReadData(const FormatType& format,
1114+ std::string* result) const {
1115+ DCHECK(CalledOnValidThread());
1116+}
1117+
1118+void ClipboardOxide::WriteObjects(ClipboardType type, const ObjectMap& objects) {
1119+ DCHECK(CalledOnValidThread());
1120+}
1121+
1122+void ClipboardOxide::WriteText(const char* text_data, size_t text_len) {
1123+}
1124+
1125+void ClipboardOxide::WriteHTML(const char* markup_data,
1126+ size_t markup_len,
1127+ const char* url_data,
1128+ size_t url_len) {
1129+}
1130+
1131+void ClipboardOxide::WriteRTF(const char* rtf_data, size_t data_len) {
1132+}
1133+
1134+void ClipboardOxide::WriteBookmark(const char* title_data,
1135+ size_t title_len,
1136+ const char* url_data,
1137+ size_t url_len) {
1138+}
1139+
1140+void ClipboardOxide::WriteWebSmartPaste() {
1141+}
1142+
1143+void ClipboardOxide::WriteBitmap(const SkBitmap& bitmap) {
1144+}
1145+
1146+void ClipboardOxide::WriteData(const FormatType& format,
1147+ const char* data_data,
1148+ size_t data_len) {
1149+}
1150+
1151+} // namespace ui
1152
1153=== added file 'shared/port/ui_base/clipboard_oxide.h'
1154--- shared/port/ui_base/clipboard_oxide.h 1970-01-01 00:00:00 +0000
1155+++ shared/port/ui_base/clipboard_oxide.h 2015-05-26 19:17:26 +0000
1156@@ -0,0 +1,80 @@
1157+// vim:expandtab:shiftwidth=2:tabstop=2:
1158+// Copyright (C) 2015 Canonical Ltd.
1159+
1160+// This library is free software; you can redistribute it and/or
1161+// modify it under the terms of the GNU Lesser General Public
1162+// License as published by the Free Software Foundation; either
1163+// version 2.1 of the License, or (at your option) any later version.
1164+
1165+// This library is distributed in the hope that it will be useful,
1166+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1167+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1168+// Lesser General Public License for more details.
1169+
1170+// You should have received a copy of the GNU Lesser General Public
1171+// License along with this library; if not, write to the Free Software
1172+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1173+
1174+#ifndef OXIDE_SHARED_PORT_UI_CLIPBOARD_OXIDE_H_
1175+#define OXIDE_SHARED_PORT_UI_CLIPBOARD_OXIDE_H_
1176+
1177+#include "ui/base/ui_base_export.h"
1178+#include "ui/base/clipboard/clipboard.h"
1179+
1180+namespace ui {
1181+
1182+class ClipboardOxide : public Clipboard {
1183+ public:
1184+ ClipboardOxide();
1185+ virtual ~ClipboardOxide();
1186+
1187+ // Clipboard overrides:
1188+ uint64 GetSequenceNumber(ClipboardType type) const override;
1189+ bool IsFormatAvailable(const FormatType& format,
1190+ ClipboardType type) const override;
1191+ void Clear(ClipboardType type) override;
1192+ void ReadAvailableTypes(ClipboardType type,
1193+ std::vector<base::string16>* types,
1194+ bool* contains_filenames) const override;
1195+ void ReadText(ClipboardType type, base::string16* result) const override;
1196+ void ReadAsciiText(ClipboardType type, std::string* result) const override;
1197+ void ReadHTML(ClipboardType type,
1198+ base::string16* markup,
1199+ std::string* src_url,
1200+ uint32* fragment_start,
1201+ uint32* fragment_end) const override;
1202+ void ReadRTF(ClipboardType type, std::string* result) const override;
1203+ SkBitmap ReadImage(ClipboardType type) const override;
1204+ void ReadCustomData(ClipboardType clipboard_type,
1205+ const base::string16& type,
1206+ base::string16* result) const override;
1207+ void ReadBookmark(base::string16* title, std::string* url) const override;
1208+ void ReadData(const FormatType& format, std::string* result) const override;
1209+ void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
1210+ void WriteText(const char* text_data, size_t text_len) override;
1211+ void WriteHTML(const char* markup_data,
1212+ size_t markup_len,
1213+ const char* url_data,
1214+ size_t url_len) override;
1215+ void WriteRTF(const char* rtf_data, size_t data_len) override;
1216+ void WriteBookmark(const char* title_data,
1217+ size_t title_len,
1218+ const char* url_data,
1219+ size_t url_len) override;
1220+ void WriteWebSmartPaste() override;
1221+ void WriteBitmap(const SkBitmap& bitmap) override;
1222+ void WriteData(const FormatType& format,
1223+ const char* data_data,
1224+ size_t data_len) override;
1225+
1226+ DISALLOW_COPY_AND_ASSIGN(ClipboardOxide);
1227+};
1228+
1229+typedef Clipboard* (*ClipboardOxideFactory) ();
1230+
1231+UI_BASE_EXPORT void SetClipboardOxideFactory(
1232+ ClipboardOxideFactory factory);
1233+
1234+}
1235+
1236+#endif // OXIDE_SHARED_PORT_UI_CLIPBOARD_OXIDE_H_

Subscribers

People subscribed via source and target branches