Merge lp:~abreu-alexandre/oxide/clipboard into lp:~oxide-developers/oxide/oxide.trunk
- clipboard
- Merge into oxide.trunk
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 | ||||
Related bugs: |
|
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
- 1056. By Chris Coulson
-
Fix a memory corruption when the visibilty of a webview is changed
Chris Coulson (chrisccoulson) wrote : | # |
Chris Coulson (chrisccoulson) : | # |
- 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:
:webProcessStat us property to notify embedders when the renderer process crashed or was killed. - 1065. By Chris Coulson
-
Add WebView.
mediaAccessPerm issionRequested 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
Olivier Tilloy (osomon) wrote : | # |
There’s a couple of conflicts in qt/tests/
- 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
Olivier Tilloy (osomon) wrote : | # |
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/
Why does clearClipboard() accept an (unused) 'data' parameter?
Is getClipboardIma
In fact, can’t we get rid entirely of copyImageToClip
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 getClipboardCon
> 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/
Includes are not properly sorted alphabetically in shared/
In qt/core/
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:
In ClipboardQt:
- 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:
It looks like the following block is repeated many times, maybe it could be factored out as a macro?
const QMimeData *data =
clipboard-
type == ui::CLIPBOARD_
: QClipboard:
In ClipboardQt:
- 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:
- I don’t understand the comment about ReadImage. Can you clarif...
- 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_UnloadHandl
ers.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
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:
> of relative links?
this is something that is actually win32 specific,
- 1088. By Ugo Riboni
-
Add WebView.
findController API
Olivier Tilloy (osomon) wrote : | # |
Is the license and copyright header in qt/core/
In qt/core/
- shouldn’t the override of GetClipboardOxi
In qt/core/
- is "friend class Clipboard;" needed?
- does the 'override' keywoard makes sense for a destructor?
In qt/core/
- ClipboardChange
- In ClipboardChange
- In ClipboardChange
- shouldn’t ClipboardQt:
- it seems the checks on the nullness of QGuiApplication
In qt/tests/
- div with id "blabla" is unused, can it be removed?
In qt/tests/
- 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/
- 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:
> - 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:
> - do we really need to clear markup and src_url prior to setting
> their content?
- 1089. By Alexandre Abreu
-
Add clipboard support
- 1090. By Alexandre Abreu
-
Nits
- 1091. By Alexandre Abreu
-
update test
Alexandre Abreu (abreu-alexandre) wrote : | # |
> Is the license and copyright header in
> qt/core/
>
> In qt/core/
> - shouldn’t the override of GetClipboardOxi
> 'override' instead of 'final' ?
>
> In qt/core/
> - is "friend class Clipboard;" needed?
> - does the 'override' keywoard makes sense for a destructor?
yes,
> In qt/core/
> - ClipboardChange
> use Q_DISABLE_COPY instead of DISALLOW_
> - In ClipboardChange
> visibility keywords is inconsistent
> - In ClipboardChange
> indentation level for 'case' statements and their contents?
> - shouldn’t ClipboardQt:
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
> necessary, we can safely assume it will never be null (other code throughout
> Qt makes this assumption already)
>
> In qt/tests/
> - div with id "blabla" is unused, can it be removed?
>
> In qt/tests/
> - 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/
> - 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:
> > - 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:
> > - do we really need to clear markup and src_url prior to setting
> > the...
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)?
- 1092. By Alexandre Abreu
-
updates
- 1093. By Alexandre Abreu
-
update cmment
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
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.
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 BrowserPlatform
- I'm not sure I fully understand what ui::ClipboardOxide is for. Given that BrowserMainParts always calls ui::SetClipboar
Other than that, this should be ok to merge
Chris Coulson (chrisccoulson) wrote : | # |
Actually, forget my 3rd point there. Of course, in the current implementation, ui::SetClipboar
- 1094. By Alexandre Abreu
-
removed CONTENT_EXPORT
Alexandre Abreu (abreu-alexandre) wrote : | # |
Updated to remove the CONTENT_EXPORT ... I'll address the other points later this week,
Preview Diff
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(©, 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_ |
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?