Merge lp:~osomon/oxide/touch-selection-api into lp:~oxide-developers/oxide/oxide.trunk

Proposed by Olivier Tilloy
Status: Merged
Merged at revision: 1309
Proposed branch: lp:~osomon/oxide/touch-selection-api
Merge into: lp:~oxide-developers/oxide/oxide.trunk
Diff against target: 2496 lines (+1435/-54)
37 files modified
qt/core/browser/oxide_qt_browser_platform_integration.cc (+8/-3)
qt/core/browser/oxide_qt_browser_platform_integration.h (+1/-0)
qt/core/browser/oxide_qt_touch_handle_drawable.cc (+105/-0)
qt/core/browser/oxide_qt_touch_handle_drawable.h (+56/-0)
qt/core/browser/oxide_qt_web_context_menu.cc (+1/-0)
qt/core/browser/oxide_qt_web_view.cc (+58/-4)
qt/core/browser/oxide_qt_web_view.h (+13/-7)
qt/core/core.gyp (+4/-1)
qt/core/glue/oxide_qt_touch_handle_drawable_proxy.h (+56/-0)
qt/core/glue/oxide_qt_web_context_menu_proxy_client.h (+0/-11)
qt/core/glue/oxide_qt_web_view_proxy.h (+18/-4)
qt/core/glue/oxide_qt_web_view_proxy_client.h (+8/-1)
qt/qmlplugin/oxide.qmltypes (+28/-0)
qt/qmlplugin/oxide_qml_plugin.cc (+3/-0)
qt/quick/CMakeLists.txt (+3/-1)
qt/quick/api/oxideqquicktouchselectioncontroller.cc (+92/-0)
qt/quick/api/oxideqquicktouchselectioncontroller_p.h (+74/-0)
qt/quick/api/oxideqquickwebview.cc (+45/-1)
qt/quick/api/oxideqquickwebview_p.h (+10/-0)
qt/quick/api/oxideqquickwebview_p_p.h (+7/-1)
qt/quick/oxide_qquick_touch_handle_drawable.cc (+286/-0)
qt/quick/oxide_qquick_touch_handle_drawable.h (+70/-0)
qt/quick/oxide_qquick_web_context_menu.cc (+1/-0)
qt/tests/qmltests/api/tst_WebView_editingCapabilities.html (+6/-0)
qt/tests/qmltests/api/tst_WebView_editingCapabilities.qml (+132/-0)
shared/browser/oxide_browser_platform_integration.cc (+6/-0)
shared/browser/oxide_browser_platform_integration.h (+2/-0)
shared/browser/oxide_browser_platform_integration_observer.h (+3/-1)
shared/browser/oxide_render_widget_host_view.cc (+153/-2)
shared/browser/oxide_render_widget_host_view.h (+27/-1)
shared/browser/oxide_render_widget_host_view_container.h (+12/-1)
shared/browser/oxide_web_view.cc (+100/-4)
shared/browser/oxide_web_view.h (+18/-5)
shared/browser/oxide_web_view_client.cc (+10/-1)
shared/browser/oxide_web_view_client.h (+16/-1)
shared/renderer/oxide_content_renderer_client.cc (+1/-3)
shared/shared.gyp (+2/-1)
To merge this branch: bzr merge lp:~osomon/oxide/touch-selection-api
Reviewer Review Type Date Requested Status
Chris Coulson Approve
Olivier Tilloy (community) Abstain
Review via email: mp+277193@code.launchpad.net

Commit message

Add a touch selection API, to allow embedders to display handles for resizing the current selection, and contextual actions for it.

Description of the change

Initial proposal for a touch selection API.
Feedback on the proposed API and architecture welcome.

I shared a small example here for tests, along with screenshots of how this looks like on an MX4: http://people.canonical.com/~osomon/oxide-touch-selection/.

To post a comment you must log in.
lp:~osomon/oxide/touch-selection-api updated
1274. By Olivier Tilloy

Report the actual selected text.

1275. By Olivier Tilloy

Rename selectionText to selectedText for consistency with chromium’s API.

1276. By Olivier Tilloy

Re-create the touch selection handles if the embedder modifies the component on the fly.

1277. By Olivier Tilloy

Add a 'bounds' property to the touch selection controller.

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

This should now be ready for review.

Regarding this comment:

    // XXX: if editable, can we determine whether undo/redo is available?

It doesn’t look like the content API exposes a way to get at the currently focused editor, nor a canUndo() method of some sort.

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

I tested further and I’m seeing one issue with the positioning of the handles and of the bounds when the locationBarController is used: the positions are offset by the height of the location bar.

review: Needs Fixing
lp:~osomon/oxide/touch-selection-api updated
1278. By Olivier Tilloy

Take into account the location bar offset.

1279. By Olivier Tilloy

Update the bounding rect and positions of the handles if the location bar offset changes while a touch selection is active.

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

The issue I was pointing out above should be fixed now.

review: Abstain
lp:~osomon/oxide/touch-selection-api updated
1280. By Olivier Tilloy

Enable adaptive handle orientation, and expose the mirrorVertical and mirrorHorizontal properties.

1281. By Olivier Tilloy

Disable adaptive handle orientation for now, to match what chrome on android does.

1282. By Olivier Tilloy

Version 1.12 of the QML plugin corresponds to revision 7 of the WebView’s API.

1283. By Olivier Tilloy

Expose the horizontalPaddingRatio property on the handle component.

1284. By Olivier Tilloy

Merge the latest changes from trunk, and resolve a few conflicts.

1285. By Olivier Tilloy

Copy ConvertSelectionBound()’s implementation from content/browser/renderer_host/input/ui_touch_selection_helper.cc because that helper is not part of content’s public API.

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

Sorry for taking ages on this. Whilst I continue to review the implementation, I do have some high-level comments on the API:

- OxideQQuickTouchSelectionController::editFlags would be better off as a property on WebView (as editingCapabilities or something), given that it has executeEditingCommand() there. This isn't unique to touch selection, and it's something that WebView needs anyway.
- The read only properties on OxideQQuickTouchSelection have setters in what will eventually be a public header. There shouldn't be public setters for these if they're only updated from Oxide.
- It's not clear what OxideQQuickTouchSelectionController::selectedText will be used for.
- OxideQQuickTouchSelectionController::Orientation should probably be OxideQQuickTouchSelectionController::HandleOrientation.
- Will horizontalPaddingRatio be used for our touch handles? It's always zero in Chrome/Aura and 0.25f in Chrome/Android. If we don't have a use for this in the design of our touch handles, I'd prefer this not to be exposed.

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

> - Will horizontalPaddingRatio be used for our touch handles? It's
> always zero in Chrome/Aura and 0.25f in Chrome/Android. If we don't
> have a use for this in the design of our touch handles, I'd prefer
> this not to be exposed.

Yes. This is necessary if the arrow/pointer of the assets is not aligned to the right (for the left handle) / to the left (for the right handle). It seems the selection handles in the Ubuntu UITK are being redesigned at the moment, so there are no definite visuals yet, but I’ve seen some mockups where the arrow is horizontally centered, for which horizontalPaddingRatio needs to be 0.5f.

lp:~osomon/oxide/touch-selection-api updated
1286. By Olivier Tilloy

Remove the selectedText read-only property from OxideQQuickTouchSelectionController,
it’s not really useful since the webview has cut/copy/paste commands which interact directly with the clipboard.

1287. By Olivier Tilloy

Rename OxideQQuickTouchSelectionController::Orientation to OxideQQuickTouchSelectionController::HandleOrientation.

1288. By Olivier Tilloy

Move OxideQQuickTouchSelectionController::editFlags to OxideQQuickWebView::editingCapabilities.

1289. By Olivier Tilloy

Remove setters for the 'active' and 'bounds' properties on OxideQQuickTouchSelectionController.

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

All your high-level comments on the API should now be addressed/answered.

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

I’m currently adding unit tests for WebView.editingCapabilities, and facing an issue: the current implementation emits editingCapabilitiesChanged whenever the selection bounds change, which seems to cover most use cases, but one: when the user issues the Copy command, the contents of the clipboard change, and the editing caps potentially change with it (if the clipboard was empty, the PasteCapability becomes true). Emitting editingCapabilitiesChanged in WebView::executeEditingCommand() just after calling contents::WebContents::Copy() doesn’t do the trick, as copying content to the clipboard is async (and thus by the time the signal is emitted the content might not have been copied to the clipboard yet).

In fact the problem is more general than that: if content is copied to the clipboard outside of the application, there’s no way to get notified of it and update the editing caps. There’s a comment in chrome/browser/ui/views/frame/browser_view.cc (above BrowserView::CutCopyPaste()) that suggests that this is currently not possible anyway.

Is WebView.editingCapabilities a good idea after all?

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

> I’m currently adding unit tests for WebView.editingCapabilities, and facing an
> issue: the current implementation emits editingCapabilitiesChanged whenever
> the selection bounds change, which seems to cover most use cases, but one:
> when the user issues the Copy command, the contents of the clipboard change,
> and the editing caps potentially change with it (if the clipboard was empty,
> the PasteCapability becomes true). Emitting editingCapabilitiesChanged in
> WebView::executeEditingCommand() just after calling
> contents::WebContents::Copy() doesn’t do the trick, as copying content to the
> clipboard is async (and thus by the time the signal is emitted the content
> might not have been copied to the clipboard yet).
>
> In fact the problem is more general than that: if content is copied to the
> clipboard outside of the application, there’s no way to get notified of it and
> update the editing caps. There’s a comment in
> chrome/browser/ui/views/frame/browser_view.cc (above
> BrowserView::CutCopyPaste()) that suggests that this is currently not possible
> anyway.
>
> Is WebView.editingCapabilities a good idea after all?

We need some way of exposing this from WebView in order to support editing commands in an application menu. If possible, I'd like to not have this information duplicated in 3 different places (it's already exposed specifically for context menus).

Is the lack of notifications Chromium specific, or is that something we can get from Qt? (I'm not sure what QClipboard::dataChanged does)

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

> Is the lack of notifications Chromium specific, or is that something
> we can get from Qt? (I'm not sure what QClipboard::dataChanged does)

It seems we can get the information from Qt. I just did a quick test with QClipboard (which is conveniently exposed in Qml by Ubuntu.Components, see https://developer.ubuntu.com/api/apps/qml/sdk-15.04/Ubuntu.Components.Clipboard/), and indeed the dataChanged signal is emitted whenever new data is being copied to the clipboard. Presumably, we can listen to this signal to emit editingCapabilitiesChanged. This also works when the application doesn’t have active focus.

lp:~osomon/oxide/touch-selection-api updated
1290. By Olivier Tilloy

Emit editingCapabilitiesChanged() when the contents of the clipboard change.

1291. By Olivier Tilloy

Merge the latest changes from trunk and resolve a couple of minor conflicts.

1292. By Olivier Tilloy

Cache the edit flags to avoid emitting a signal when they haven’t actually changed.

1293. By Olivier Tilloy

Add unit tests for the WebView.editingCapabilities API.

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

I added unit tests for the WebView.editingCapabilities API. Some of them are partially commented out as they would fail because of bug #1524288.

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

Sorry for taking ages on this - I've added some comments inline. I'm still going through it though, so there might be a few more later.

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

I've left another couple of comments

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

Ok, I think I'm done for now (there's another couple of comments)

lp:~osomon/oxide/touch-selection-api updated
1294. By Olivier Tilloy

Merge the latest changes from trunk.

1295. By Olivier Tilloy

Disconnect all signal handlers in oxide::qt::BrowserPlatformIntegration’s destructor.

1296. By Olivier Tilloy

Use RenderWidgetHostViewContainer instead of having RWHV call into WebView directly.

1297. By Olivier Tilloy

Do not explicitly call reset() on scoped pointers in a destructor, this is happening at destruction anyway.

1298. By Olivier Tilloy

Ensure the edit flags are updated when the RWHV changes.

1299. By Olivier Tilloy

Pass the bounds by const reference instead of by value.

1300. By Olivier Tilloy

Clear the edit flags if there’s no RWHV.

1301. By Olivier Tilloy

Factor out code in a helper function.

1302. By Olivier Tilloy

Remove the base oxide::TouchHandleDrawable implementation, and oxide::TouchHandleDrawableDelegate.
This was one layer too many for no good reason.

1303. By Olivier Tilloy

Merge the latest changes from trunk.

1304. By Olivier Tilloy

Fix a regression with vertical positioning of handles that crept in a previous commit.

1305. By Olivier Tilloy

Update copyright years in headers of changed files.

1306. By Olivier Tilloy

Remove explicit disconnections in destructor, which are handled automatically by QObject.

1307. By Olivier Tilloy

onTouchSelectionChanged doesn’t need to be a slot.

1308. By Olivier Tilloy

Move the pointer to the touch selection handle to OxideQQuickTouchSelectionControllerPrivate.

1309. By Olivier Tilloy

Make RWHV an implementation of ui::TouchSelectionControllreClient, instead of proxying calls to a separate object.

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

Thanks for the thorough review. I think I addressed all your comments.

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

This looks fine to merge now - I'll probably report a few follow up bugs with other cleanups / suggestions, but those don't need to block the initial landing

review: Approve
lp:~osomon/oxide/touch-selection-api updated
1310. By Olivier Tilloy

Merge the latest changes from trunk and resolve a minor conflict.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qt/core/browser/oxide_qt_browser_platform_integration.cc'
2--- qt/core/browser/oxide_qt_browser_platform_integration.cc 2015-11-27 21:35:14 +0000
3+++ qt/core/browser/oxide_qt_browser_platform_integration.cc 2016-01-08 22:47:28 +0000
4@@ -1,5 +1,5 @@
5 // vim:expandtab:shiftwidth=2:tabstop=2:
6-// Copyright (C) 2014-2015 Canonical Ltd.
7+// Copyright (C) 2014-2016 Canonical Ltd.
8
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11@@ -17,6 +17,7 @@
12
13 #include "oxide_qt_browser_platform_integration.h"
14
15+#include <QClipboard>
16 #include <QDesktopServices>
17 #include <QEvent>
18 #include <QGuiApplication>
19@@ -80,6 +81,10 @@
20 UpdateApplicationState();
21 }
22
23+void BrowserPlatformIntegration::OnClipboardDataChanged() {
24+ NotifyClipboardDataChanged();
25+}
26+
27 void BrowserPlatformIntegration::OnScreenGeometryChanged(
28 const QRect& geometry) {
29 UpdateDefaultScreenInfo();
30@@ -226,14 +231,14 @@
31
32 connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
33 SLOT(OnApplicationStateChanged()));
34+ connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
35+ SLOT(OnClipboardDataChanged()));
36 if (QGuiApplication::platformName().startsWith("ubuntu")) {
37 qApp->installEventFilter(this);
38 }
39-
40 }
41
42 BrowserPlatformIntegration::~BrowserPlatformIntegration() {
43- qApp->disconnect(this);
44 qApp->removeEventFilter(this);
45 }
46
47
48=== modified file 'qt/core/browser/oxide_qt_browser_platform_integration.h'
49--- qt/core/browser/oxide_qt_browser_platform_integration.h 2015-11-27 21:35:14 +0000
50+++ qt/core/browser/oxide_qt_browser_platform_integration.h 2016-01-08 22:47:28 +0000
51@@ -44,6 +44,7 @@
52
53 private Q_SLOTS:
54 void OnApplicationStateChanged();
55+ void OnClipboardDataChanged();
56 void OnScreenGeometryChanged(const QRect& geometry);
57 void OnScreenOrientationChanged(Qt::ScreenOrientation orientation);
58
59
60=== added file 'qt/core/browser/oxide_qt_touch_handle_drawable.cc'
61--- qt/core/browser/oxide_qt_touch_handle_drawable.cc 1970-01-01 00:00:00 +0000
62+++ qt/core/browser/oxide_qt_touch_handle_drawable.cc 2016-01-08 22:47:28 +0000
63@@ -0,0 +1,105 @@
64+// vim:expandtab:shiftwidth=2:tabstop=2:
65+// Copyright (C) 2015-2016 Canonical Ltd.
66+
67+// This library is free software; you can redistribute it and/or
68+// modify it under the terms of the GNU Lesser General Public
69+// License as published by the Free Software Foundation; either
70+// version 2.1 of the License, or (at your option) any later version.
71+
72+// This library is distributed in the hope that it will be useful,
73+// but WITHOUT ANY WARRANTY; without even the implied warranty of
74+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
75+// Lesser General Public License for more details.
76+
77+// You should have received a copy of the GNU Lesser General Public
78+// License along with this library; if not, write to the Free Software
79+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
80+
81+#include "oxide_qt_touch_handle_drawable.h"
82+
83+#include "qt/core/glue/oxide_qt_touch_handle_drawable_proxy.h"
84+
85+#include "oxide_qt_web_view.h"
86+
87+#include <QPointF>
88+
89+namespace oxide {
90+namespace qt {
91+
92+TouchHandleDrawable::TouchHandleDrawable(const WebView* view)
93+ : view_(view) {}
94+
95+TouchHandleDrawable::~TouchHandleDrawable() {}
96+
97+void TouchHandleDrawable::SetProxy(TouchHandleDrawableProxy* proxy) {
98+ proxy_.reset(proxy);
99+}
100+
101+void TouchHandleDrawable::SetEnabled(bool enabled) {
102+ if (proxy_) {
103+ proxy_->SetEnabled(enabled);
104+ }
105+}
106+
107+void TouchHandleDrawable::SetOrientation(
108+ ui::TouchHandleOrientation orientation,
109+ bool mirror_vertical,
110+ bool mirror_horizontal) {
111+ if (proxy_) {
112+ TouchHandleDrawableProxy::Orientation o;
113+ switch (orientation) {
114+ case ui::TouchHandleOrientation::LEFT:
115+ o = TouchHandleDrawableProxy::Left;
116+ break;
117+ case ui::TouchHandleOrientation::CENTER:
118+ o = TouchHandleDrawableProxy::Center;
119+ break;
120+ case ui::TouchHandleOrientation::RIGHT:
121+ o = TouchHandleDrawableProxy::Right;
122+ break;
123+ case ui::TouchHandleOrientation::UNDEFINED:
124+ o = TouchHandleDrawableProxy::Undefined;
125+ break;
126+ default:
127+ Q_UNREACHABLE();
128+ }
129+ proxy_->SetOrientation(o, mirror_vertical, mirror_horizontal);
130+ }
131+}
132+
133+void TouchHandleDrawable::SetOrigin(const gfx::PointF& origin) {
134+ if (proxy_) {
135+ const float dpr = view_->GetDeviceScaleFactor();
136+ const int y_offset = view_->GetLocationBarContentOffsetPix();
137+ proxy_->SetOrigin(QPointF(origin.x() * dpr, origin.y() * dpr + y_offset));
138+ }
139+}
140+
141+void TouchHandleDrawable::SetAlpha(float alpha) {
142+ if (proxy_) {
143+ proxy_->SetAlpha(alpha);
144+ }
145+}
146+
147+gfx::RectF TouchHandleDrawable::GetVisibleBounds() const {
148+ if (!proxy_) {
149+ return gfx::RectF();
150+ }
151+
152+ const float dpr = view_->GetDeviceScaleFactor();
153+ const int y_offset = view_->GetLocationBarContentOffsetPix();
154+ QRectF bounds = proxy_->GetVisibleBounds();
155+ return gfx::RectF(bounds.x() / dpr, (bounds.y() - y_offset) / dpr,
156+ bounds.width() / dpr, bounds.height() / dpr);
157+}
158+
159+float TouchHandleDrawable::GetDrawableHorizontalPaddingRatio() const {
160+ if (!proxy_) {
161+ return 0.0f;
162+ }
163+
164+ return proxy_->GetDrawableHorizontalPaddingRatio();
165+}
166+
167+} // namespace qt
168+} // namespace oxide
169
170=== added file 'qt/core/browser/oxide_qt_touch_handle_drawable.h'
171--- qt/core/browser/oxide_qt_touch_handle_drawable.h 1970-01-01 00:00:00 +0000
172+++ qt/core/browser/oxide_qt_touch_handle_drawable.h 2016-01-08 22:47:28 +0000
173@@ -0,0 +1,56 @@
174+// vim:expandtab:shiftwidth=2:tabstop=2:
175+// Copyright (C) 2015-2016 Canonical Ltd.
176+
177+// This library is free software; you can redistribute it and/or
178+// modify it under the terms of the GNU Lesser General Public
179+// License as published by the Free Software Foundation; either
180+// version 2.1 of the License, or (at your option) any later version.
181+
182+// This library is distributed in the hope that it will be useful,
183+// but WITHOUT ANY WARRANTY; without even the implied warranty of
184+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
185+// Lesser General Public License for more details.
186+
187+// You should have received a copy of the GNU Lesser General Public
188+// License along with this library; if not, write to the Free Software
189+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
190+
191+#ifndef _OXIDE_QT_CORE_BROWSER_TOUCH_HANDLE_DRAWABLE_H_
192+#define _OXIDE_QT_CORE_BROWSER_TOUCH_HANDLE_DRAWABLE_H_
193+
194+#include "base/memory/scoped_ptr.h"
195+#include "ui/touch_selection/touch_handle.h"
196+
197+namespace oxide {
198+namespace qt {
199+
200+class TouchHandleDrawableProxy;
201+class WebView;
202+
203+class TouchHandleDrawable : public ui::TouchHandleDrawable {
204+ public:
205+ TouchHandleDrawable(const WebView* view);
206+
207+ void SetProxy(TouchHandleDrawableProxy* proxy);
208+
209+ private:
210+ ~TouchHandleDrawable() override;
211+
212+ // ui::TouchHandleDrawable implementation
213+ void SetEnabled(bool enabled) override;
214+ void SetOrientation(ui::TouchHandleOrientation orientation,
215+ bool mirror_vertical,
216+ bool mirror_horizontal) override;
217+ void SetOrigin(const gfx::PointF& origin) override;
218+ void SetAlpha(float alpha) override;
219+ gfx::RectF GetVisibleBounds() const override;
220+ float GetDrawableHorizontalPaddingRatio() const override;
221+
222+ scoped_ptr<TouchHandleDrawableProxy> proxy_;
223+ const WebView* view_;
224+};
225+
226+} // namespace qt
227+} // namespace oxide
228+
229+#endif // _OXIDE_QT_CORE_BROWSER_TOUCH_HANDLE_DRAWABLE_H_
230
231=== modified file 'qt/core/browser/oxide_qt_web_context_menu.cc'
232--- qt/core/browser/oxide_qt_web_context_menu.cc 2015-08-31 10:57:08 +0000
233+++ qt/core/browser/oxide_qt_web_context_menu.cc 2016-01-08 22:47:28 +0000
234@@ -24,6 +24,7 @@
235 #include "base/strings/utf_string_conversions.h"
236
237 #include "qt/core/glue/oxide_qt_web_context_menu_proxy.h"
238+#include "qt/core/glue/oxide_qt_web_view_proxy.h"
239 #include "shared/browser/oxide_web_view.h"
240
241 namespace oxide {
242
243=== modified file 'qt/core/browser/oxide_qt_web_view.cc'
244--- qt/core/browser/oxide_qt_web_view.cc 2016-01-04 13:40:25 +0000
245+++ qt/core/browser/oxide_qt_web_view.cc 2016-01-08 22:47:28 +0000
246@@ -1,5 +1,5 @@
247 // vim:expandtab:shiftwidth=2:tabstop=2:
248-// Copyright (C) 2013-2015 Canonical Ltd.
249+// Copyright (C) 2013-2016 Canonical Ltd.
250
251 // This library is free software; you can redistribute it and/or
252 // modify it under the terms of the GNU Lesser General Public
253@@ -50,7 +50,9 @@
254 #include "ui/events/event.h"
255 #include "ui/gfx/geometry/point.h"
256 #include "ui/gfx/geometry/rect.h"
257+#include "ui/gfx/geometry/rect_f.h"
258 #include "ui/gfx/geometry/size.h"
259+#include "ui/touch_selection/touch_selection_controller.h"
260 #include "url/gurl.h"
261
262 #include "qt/core/api/oxideqdownloadrequest.h"
263@@ -92,6 +94,7 @@
264 #include "oxide_qt_screen_utils.h"
265 #include "oxide_qt_script_message_handler.h"
266 #include "oxide_qt_skutils.h"
267+#include "oxide_qt_touch_handle_drawable.h"
268 #include "oxide_qt_web_context.h"
269 #include "oxide_qt_web_context_menu.h"
270 #include "oxide_qt_web_frame.h"
271@@ -411,6 +414,10 @@
272 return GetDeviceScaleFactorFromQScreen(screen);
273 }
274
275+int WebView::GetLocationBarContentOffsetPix() const {
276+ return locationBarContentOffsetPix();
277+}
278+
279 void WebView::CommonInit(OxideQFindController* find_controller) {
280 content::WebContents* contents = view_->GetWebContents();
281
282@@ -819,6 +826,22 @@
283 return picker;
284 }
285
286+ui::TouchHandleDrawable* WebView::CreateTouchHandleDrawable() const {
287+ TouchHandleDrawable* drawable = new TouchHandleDrawable(this);
288+ drawable->SetProxy(client_->CreateTouchHandleDrawable());
289+ return drawable;
290+}
291+
292+OXIDE_MAKE_ENUM_BITWISE_OPERATORS(EditCapabilityFlags)
293+
294+void WebView::TouchSelectionChanged(bool active,
295+ const gfx::RectF& bounds) const {
296+ const float dpr = GetDeviceScaleFactor();
297+ QRectF rect(bounds.x() * dpr, bounds.y() * dpr,
298+ bounds.width() * dpr, bounds.height() * dpr);
299+ client_->TouchSelectionChanged(active, rect);
300+}
301+
302 void WebView::SwapCompositorFrame() {
303 compositor_frame_.reset();
304 client_->ScheduleUpdate();
305@@ -878,6 +901,10 @@
306 client_->TargetURLChanged();
307 }
308
309+void WebView::OnEditingCapabilitiesChanged() {
310+ client_->OnEditingCapabilitiesChanged();
311+}
312+
313 size_t WebView::GetScriptMessageHandlerCount() const {
314 return message_handlers_.size();
315 }
316@@ -1277,7 +1304,7 @@
317 view_->PrepareToClose();
318 }
319
320-int WebView::locationBarHeight() {
321+int WebView::locationBarHeight() const {
322 return view_->GetLocationBarHeightPix();
323 }
324
325@@ -1285,11 +1312,11 @@
326 view_->SetLocationBarHeightPix(height);
327 }
328
329-int WebView::locationBarOffsetPix() {
330+int WebView::locationBarOffsetPix() const {
331 return view_->GetLocationBarOffsetPix();
332 }
333
334-int WebView::locationBarContentOffsetPix() {
335+int WebView::locationBarContentOffsetPix() const {
336 return view_->GetLocationBarContentOffsetPix();
337 }
338
339@@ -1368,6 +1395,33 @@
340 return QUrl(QString::fromStdString(view_->target_url().spec()));
341 }
342
343+EditCapabilityFlags WebView::editFlags() const {
344+ EditCapabilityFlags capabilities = NO_CAPABILITY;
345+ int flags = view_->GetEditFlags();
346+ if (flags & blink::WebContextMenuData::CanUndo) {
347+ capabilities |= UNDO_CAPABILITY;
348+ }
349+ if (flags & blink::WebContextMenuData::CanRedo) {
350+ capabilities |= REDO_CAPABILITY;
351+ }
352+ if (flags & blink::WebContextMenuData::CanCut) {
353+ capabilities |= CUT_CAPABILITY;
354+ }
355+ if (flags & blink::WebContextMenuData::CanCopy) {
356+ capabilities |= COPY_CAPABILITY;
357+ }
358+ if (flags & blink::WebContextMenuData::CanPaste) {
359+ capabilities |= PASTE_CAPABILITY;
360+ }
361+ if (flags & blink::WebContextMenuData::CanDelete) {
362+ capabilities |= ERASE_CAPABILITY;
363+ }
364+ if (flags & blink::WebContextMenuData::CanSelectAll) {
365+ capabilities |= SELECT_ALL_CAPABILITY;
366+ }
367+ return capabilities;
368+}
369+
370 void WebView::teardownFrameTree() {
371 DCHECK(!frame_tree_torn_down_);
372
373
374=== modified file 'qt/core/browser/oxide_qt_web_view.h'
375--- qt/core/browser/oxide_qt_web_view.h 2015-11-23 17:58:35 +0000
376+++ qt/core/browser/oxide_qt_web_view.h 2016-01-08 22:47:28 +0000
377@@ -1,5 +1,5 @@
378 // vim:expandtab:shiftwidth=2:tabstop=2:
379-// Copyright (C) 2013-2015 Canonical Ltd.
380+// Copyright (C) 2013-2016 Canonical Ltd.
381
382 // This library is free software; you can redistribute it and/or
383 // modify it under the terms of the GNU Lesser General Public
384@@ -86,12 +86,13 @@
385
386 const oxide::SecurityStatus& GetSecurityStatus() const;
387
388+ float GetDeviceScaleFactor() const;
389+ int GetLocationBarContentOffsetPix() const;
390+
391 private:
392 WebView(WebViewProxyClient* client,
393 OxideQSecurityStatus* security_status);
394
395- float GetDeviceScaleFactor() const;
396-
397 void CommonInit(OxideQFindController* find_controller);
398
399 void EnsurePreferences();
400@@ -150,7 +151,6 @@
401 const std::string& user_agent) override;
402 void HttpAuthenticationRequested(
403 ResourceDispatcherHostLoginDelegate* login_delegate) override;
404-
405 bool ShouldHandleNavigation(const GURL& url,
406 WindowOpenDisposition disposition,
407 bool user_gesture) override;
408@@ -163,6 +163,9 @@
409 WindowOpenDisposition disposition,
410 scoped_ptr<content::WebContents> contents) override;
411 oxide::FilePicker* CreateFilePicker(content::RenderViewHost* rvh) override;
412+ ui::TouchHandleDrawable* CreateTouchHandleDrawable() const override;
413+ void TouchSelectionChanged(bool active,
414+ const gfx::RectF& bounds) const override;
415 void SwapCompositorFrame() override;
416 void EvictCurrentFrame() override;
417 oxide::InputMethodContext* GetInputMethodContext() const override;
418@@ -172,6 +175,7 @@
419 void PrepareToCloseResponseReceived(bool proceed) override;
420 void CloseRequested() override;
421 void TargetURLChanged() override;
422+ void OnEditingCapabilitiesChanged() override;
423
424 // oxide::ScriptMessageTarget implementation
425 size_t GetScriptMessageHandlerCount() const override;
426@@ -271,10 +275,10 @@
427
428 void prepareToClose() override;
429
430- int locationBarHeight() override;
431+ int locationBarHeight() const override;
432 void setLocationBarHeight(int height) override;
433- int locationBarOffsetPix() override;
434- int locationBarContentOffsetPix() override;
435+ int locationBarOffsetPix() const override;
436+ int locationBarContentOffsetPix() const override;
437 LocationBarMode locationBarMode() const override;
438 void setLocationBarMode(LocationBarMode mode) override;
439 bool locationBarAnimated() const override;
440@@ -288,6 +292,8 @@
441
442 QUrl targetUrl() const override;
443
444+ EditCapabilityFlags editFlags() const override;
445+
446 void teardownFrameTree() override;
447
448 // This must outlive |view_|
449
450=== modified file 'qt/core/core.gyp'
451--- qt/core/core.gyp 2015-12-22 20:59:56 +0000
452+++ qt/core/core.gyp 2016-01-08 22:47:28 +0000
453@@ -1,4 +1,4 @@
454-# Copyright (C) 2013 Canonical Ltd.
455+# Copyright (C) 2013-2016 Canonical Ltd.
456
457 # This library is free software; you can redistribute it and/or
458 # modify it under the terms of the GNU Lesser General Public
459@@ -148,6 +148,8 @@
460 'browser/oxide_qt_script_message_request.h',
461 'browser/oxide_qt_skutils.cc',
462 'browser/oxide_qt_skutils.h',
463+ 'browser/oxide_qt_touch_handle_drawable.cc',
464+ 'browser/oxide_qt_touch_handle_drawable.h',
465 'browser/oxide_qt_url_request_delegated_job.cc',
466 'browser/oxide_qt_url_request_delegated_job.h',
467 'browser/oxide_qt_user_script.cc',
468@@ -180,6 +182,7 @@
469 'glue/oxide_qt_script_message_request_proxy.cc',
470 'glue/oxide_qt_script_message_request_proxy.h',
471 'glue/oxide_qt_script_message_request_proxy_client.h',
472+ 'glue/oxide_qt_touch_handle_drawable_proxy.h',
473 'glue/oxide_qt_user_script_proxy.cc',
474 'glue/oxide_qt_user_script_proxy.h',
475 'glue/oxide_qt_user_script_proxy_client.h',
476
477=== added file 'qt/core/glue/oxide_qt_touch_handle_drawable_proxy.h'
478--- qt/core/glue/oxide_qt_touch_handle_drawable_proxy.h 1970-01-01 00:00:00 +0000
479+++ qt/core/glue/oxide_qt_touch_handle_drawable_proxy.h 2016-01-08 22:47:28 +0000
480@@ -0,0 +1,56 @@
481+// vim:expandtab:shiftwidth=2:tabstop=2:
482+// Copyright (C) 2015-2016 Canonical Ltd.
483+
484+// This library is free software; you can redistribute it and/or
485+// modify it under the terms of the GNU Lesser General Public
486+// License as published by the Free Software Foundation; either
487+// version 2.1 of the License, or (at your option) any later version.
488+
489+// This library is distributed in the hope that it will be useful,
490+// but WITHOUT ANY WARRANTY; without even the implied warranty of
491+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
492+// Lesser General Public License for more details.
493+
494+// You should have received a copy of the GNU Lesser General Public
495+// License along with this library; if not, write to the Free Software
496+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
497+
498+#ifndef _OXIDE_QT_CORE_GLUE_TOUCH_HANDLE_DRAWABLE_PROXY_H_
499+#define _OXIDE_QT_CORE_GLUE_TOUCH_HANDLE_DRAWABLE_PROXY_H_
500+
501+#include <QRectF>
502+#include <QtGlobal>
503+
504+QT_BEGIN_NAMESPACE
505+class QPointF;
506+QT_END_NAMESPACE
507+
508+namespace oxide {
509+namespace qt {
510+
511+class TouchHandleDrawableProxy {
512+ public:
513+ // Matches chromium’s ui::TouchHandleOrientation
514+ enum Orientation {
515+ Left,
516+ Center,
517+ Right,
518+ Undefined,
519+ };
520+
521+ virtual ~TouchHandleDrawableProxy() {}
522+
523+ virtual void SetEnabled(bool enabled) = 0;
524+ virtual void SetOrientation(Orientation orientation,
525+ bool mirror_vertical,
526+ bool mirror_horizontal) = 0;
527+ virtual void SetOrigin(const QPointF& origin) = 0;
528+ virtual void SetAlpha(float alpha) = 0;
529+ virtual QRectF GetVisibleBounds() const = 0;
530+ virtual float GetDrawableHorizontalPaddingRatio() const = 0;
531+};
532+
533+} // namespace qt
534+} // namespace oxide
535+
536+#endif // _OXIDE_QT_CORE_GLUE_TOUCH_HANDLE_DRAWABLE_PROXY_H_
537
538=== modified file 'qt/core/glue/oxide_qt_web_context_menu_proxy_client.h'
539--- qt/core/glue/oxide_qt_web_context_menu_proxy_client.h 2015-05-28 23:51:39 +0000
540+++ qt/core/glue/oxide_qt_web_context_menu_proxy_client.h 2016-01-08 22:47:28 +0000
541@@ -26,17 +26,6 @@
542 namespace oxide {
543 namespace qt {
544
545-enum EditCapabilityFlags {
546- NO_CAPABILITY = 0,
547- UNDO_CAPABILITY = 1 << 0,
548- REDO_CAPABILITY = 1 << 1,
549- CUT_CAPABILITY = 1 << 2,
550- COPY_CAPABILITY = 1 << 3,
551- PASTE_CAPABILITY = 1 << 4,
552- ERASE_CAPABILITY = 1 << 5,
553- SELECT_ALL_CAPABILITY = 1 << 6
554-};
555-
556 enum MediaType {
557 MEDIA_TYPE_NONE,
558 MEDIA_TYPE_IMAGE,
559
560=== modified file 'qt/core/glue/oxide_qt_web_view_proxy.h'
561--- qt/core/glue/oxide_qt_web_view_proxy.h 2015-11-23 17:58:35 +0000
562+++ qt/core/glue/oxide_qt_web_view_proxy.h 2016-01-08 22:47:28 +0000
563@@ -1,5 +1,5 @@
564 // vim:expandtab:shiftwidth=2:tabstop=2:
565-// Copyright (C) 2013-2015 Canonical Ltd.
566+// Copyright (C) 2013-2016 Canonical Ltd.
567
568 // This library is free software; you can redistribute it and/or
569 // modify it under the terms of the GNU Lesser General Public
570@@ -49,6 +49,7 @@
571 class OxideQFindController;
572 class OxideQNewViewRequest;
573 class OxideQSecurityStatus;
574+class OxideQTouchSelectionController;
575 class OxideQWebPreferences;
576
577 namespace oxide {
578@@ -84,6 +85,17 @@
579 WEB_PROCESS_CRASHED
580 };
581
582+enum EditCapabilityFlags {
583+ NO_CAPABILITY = 0,
584+ UNDO_CAPABILITY = 1 << 0,
585+ REDO_CAPABILITY = 1 << 1,
586+ CUT_CAPABILITY = 1 << 2,
587+ COPY_CAPABILITY = 1 << 3,
588+ PASTE_CAPABILITY = 1 << 4,
589+ ERASE_CAPABILITY = 1 << 5,
590+ SELECT_ALL_CAPABILITY = 1 << 6
591+};
592+
593 enum EditingCommands {
594 EDITING_COMMAND_UNDO,
595 EDITING_COMMAND_REDO,
596@@ -222,10 +234,10 @@
597
598 virtual void prepareToClose() = 0;
599
600- virtual int locationBarHeight() = 0;
601+ virtual int locationBarHeight() const = 0;
602 virtual void setLocationBarHeight(int height) = 0;
603- virtual int locationBarOffsetPix() = 0;
604- virtual int locationBarContentOffsetPix() = 0;
605+ virtual int locationBarOffsetPix() const = 0;
606+ virtual int locationBarContentOffsetPix() const = 0;
607 virtual LocationBarMode locationBarMode() const = 0;
608 virtual void setLocationBarMode(LocationBarMode mode) = 0;
609 virtual bool locationBarAnimated() const = 0;
610@@ -239,6 +251,8 @@
611
612 virtual QUrl targetUrl() const = 0;
613
614+ virtual EditCapabilityFlags editFlags() const = 0;
615+
616 virtual void teardownFrameTree() = 0;
617 };
618
619
620=== modified file 'qt/core/glue/oxide_qt_web_view_proxy_client.h'
621--- qt/core/glue/oxide_qt_web_view_proxy_client.h 2015-11-23 17:58:35 +0000
622+++ qt/core/glue/oxide_qt_web_view_proxy_client.h 2016-01-08 22:47:28 +0000
623@@ -1,5 +1,5 @@
624 // vim:expandtab:shiftwidth=2:tabstop=2:
625-// Copyright (C) 2013-2015 Canonical Ltd.
626+// Copyright (C) 2013-2016 Canonical Ltd.
627
628 // This library is free software; you can redistribute it and/or
629 // modify it under the terms of the GNU Lesser General Public
630@@ -19,6 +19,7 @@
631 #define _OXIDE_QT_CORE_GLUE_WEB_VIEW_PROXY_CLIENT_H_
632
633 #include <QRect>
634+#include <QRectF>
635 #include <QtGlobal>
636
637 #include "qt/core/glue/oxide_qt_javascript_dialog_proxy_client.h"
638@@ -48,6 +49,7 @@
639 class FilePickerProxy;
640 class FilePickerProxyClient;
641 class JavaScriptDialogProxy;
642+class TouchHandleDrawableProxy;
643 class WebContextMenuProxy;
644 class WebContextMenuProxyClient;
645 class WebFrameProxy;
646@@ -82,6 +84,7 @@
647 virtual JavaScriptDialogProxy* CreateBeforeUnloadDialog(
648 JavaScriptDialogProxyClient* client) = 0;
649 virtual FilePickerProxy* CreateFilePicker(FilePickerProxyClient* client) = 0;
650+ virtual TouchHandleDrawableProxy* CreateTouchHandleDrawable() = 0;
651
652 virtual void WebProcessStatusChanged() = 0;
653
654@@ -97,6 +100,8 @@
655 virtual void NavigationListPruned(bool from_front, int count) = 0;
656 virtual void NavigationEntryChanged(int index) = 0;
657
658+ virtual void TouchSelectionChanged(bool active, QRectF bounds) = 0;
659+
660 virtual void CreateWebFrame(WebFrameProxy* proxy) = 0;
661
662 virtual QScreen* GetScreen() const = 0;
663@@ -151,6 +156,8 @@
664 virtual void CloseRequested() = 0;
665
666 virtual void TargetURLChanged() = 0;
667+
668+ virtual void OnEditingCapabilitiesChanged() = 0;
669 };
670
671 } // namespace qt
672
673=== modified file 'qt/qmlplugin/oxide.qmltypes'
674--- qt/qmlplugin/oxide.qmltypes 2015-11-16 14:29:31 +0000
675+++ qt/qmlplugin/oxide.qmltypes 2016-01-08 22:47:28 +0000
676@@ -290,6 +290,25 @@
677 Signal { name: "errorCallbackChanged" }
678 }
679 Component {
680+ name: "OxideQQuickTouchSelectionController"
681+ prototype: "QObject"
682+ exports: ["TouchSelectionController 1.12"]
683+ isCreatable: false
684+ exportMetaObjectRevisions: [0]
685+ Enum {
686+ name: "HandleOrientation"
687+ values: {
688+ "HandleOrientationLeft": 0,
689+ "HandleOrientationCenter": 1,
690+ "HandleOrientationRight": 2,
691+ "HandleOrientationUndefined": 3
692+ }
693+ }
694+ Property { name: "active"; type: "bool"; isReadonly: true }
695+ Property { name: "handle"; type: "QQmlComponent"; isPointer: true }
696+ Property { name: "bounds"; type: "QRectF"; isReadonly: true }
697+ }
698+ Component {
699 name: "OxideQQuickUserScript"
700 prototype: "QObject"
701 exports: ["UserScript 1.0"]
702@@ -620,6 +639,14 @@
703 }
704 Property { name: "webProcessStatus"; revision: 4; type: "WebProcessStatus"; isReadonly: true }
705 Property { name: "hoveredUrl"; type: "QUrl"; isReadonly: true }
706+ Property {
707+ name: "touchSelectionController"
708+ revision: 7
709+ type: "OxideQQuickTouchSelectionController"
710+ isReadonly: true
711+ isPointer: true
712+ }
713+ Property { name: "editingCapabilities"; revision: 7; type: "EditCapabilities"; isReadonly: true }
714 Signal { name: "loadingStateChanged"; revision: 1 }
715 Signal {
716 name: "loadEvent"
717@@ -689,6 +716,7 @@
718 Parameter { name: "request"; type: "QJSValue" }
719 }
720 Signal { name: "hoveredUrlChanged"; revision: 7 }
721+ Signal { name: "editingCapabilitiesChanged"; revision: 7 }
722 Signal {
723 name: "loadingChanged"
724 Parameter { name: "loadEvent"; type: "OxideQLoadEvent" }
725
726=== modified file 'qt/qmlplugin/oxide_qml_plugin.cc'
727--- qt/qmlplugin/oxide_qml_plugin.cc 2015-11-16 12:15:21 +0000
728+++ qt/qmlplugin/oxide_qml_plugin.cc 2016-01-08 22:47:28 +0000
729@@ -40,6 +40,7 @@
730 #include "qt/quick/api/oxideqquickscriptmessage_p.h"
731 #include "qt/quick/api/oxideqquickscriptmessagehandler_p.h"
732 #include "qt/quick/api/oxideqquickscriptmessagerequest_p.h"
733+#include "qt/quick/api/oxideqquicktouchselectioncontroller_p.h"
734 #include "qt/quick/api/oxideqquickuserscript_p.h"
735 #include "qt/quick/api/oxideqquickwebcontext_p.h"
736 #include "qt/quick/api/oxideqquickwebcontextdelegateworker_p.h"
737@@ -163,6 +164,8 @@
738
739 qmlRegisterType<OxideQQuickWebView, 6>(uri, 1, 11, "WebView");
740
741+ qmlRegisterUncreatableType<OxideQQuickTouchSelectionController>(uri, 1, 12, "TouchSelectionController",
742+ "TouchSelectionController is accessed via WebView.touchSelectionController");
743 qmlRegisterType<OxideQQuickWebView, 7>(uri, 1, 12, "WebView");
744 }
745 };
746
747=== modified file 'qt/quick/CMakeLists.txt'
748--- qt/quick/CMakeLists.txt 2015-07-02 18:18:25 +0000
749+++ qt/quick/CMakeLists.txt 2016-01-08 22:47:28 +0000
750@@ -1,6 +1,6 @@
751 # vim:expandtab:shiftwidth=2:tabstop=2:
752
753-# Copyright (C) 2014-2015 Canonical Ltd.
754+# Copyright (C) 2014-2016 Canonical Ltd.
755
756 # This library is free software; you can redistribute it and/or
757 # modify it under the terms of the GNU Lesser General Public
758@@ -34,6 +34,7 @@
759 api/oxideqquickscriptmessage.cc
760 api/oxideqquickscriptmessagehandler.cc
761 api/oxideqquickscriptmessagerequest.cc
762+ api/oxideqquicktouchselectioncontroller.cc
763 api/oxideqquickuserscript.cc
764 api/oxideqquickwebcontext.cc
765 api/oxideqquickwebcontextdelegateworker.cc
766@@ -50,6 +51,7 @@
767 oxide_qquick_javascript_dialog.cc
768 oxide_qquick_prompt_dialog.cc
769 oxide_qquick_software_frame_node.cc
770+ oxide_qquick_touch_handle_drawable.cc
771 oxide_qquick_web_context_menu.cc
772 oxide_qquick_web_popup_menu.cc
773 ${MOC_EXTRA})
774
775=== added file 'qt/quick/api/oxideqquicktouchselectioncontroller.cc'
776--- qt/quick/api/oxideqquicktouchselectioncontroller.cc 1970-01-01 00:00:00 +0000
777+++ qt/quick/api/oxideqquicktouchselectioncontroller.cc 2016-01-08 22:47:28 +0000
778@@ -0,0 +1,92 @@
779+// vim:expandtab:shiftwidth=2:tabstop=2:
780+// Copyright (C) 2015-2016 Canonical Ltd.
781+
782+// This library is free software; you can redistribute it and/or
783+// modify it under the terms of the GNU Lesser General Public
784+// License as published by the Free Software Foundation; either
785+// version 2.1 of the License, or (at your option) any later version.
786+
787+// This library is distributed in the hope that it will be useful,
788+// but WITHOUT ANY WARRANTY; without even the implied warranty of
789+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
790+// Lesser General Public License for more details.
791+
792+// You should have received a copy of the GNU Lesser General Public
793+// License along with this library; if not, write to the Free Software
794+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
795+
796+#include "oxideqquicktouchselectioncontroller_p.h"
797+
798+#include "oxideqquickwebview_p_p.h"
799+
800+QT_BEGIN_NAMESPACE
801+class QQmlComponent;
802+QT_END_NAMESPACE
803+
804+class OxideQQuickTouchSelectionControllerPrivate {
805+ public:
806+ OxideQQuickTouchSelectionControllerPrivate()
807+ : view(nullptr)
808+ , handle(nullptr)
809+ , active(false) {}
810+
811+ OxideQQuickWebView* view;
812+ QQmlComponent* handle;
813+ bool active;
814+ QRectF bounds;
815+};
816+
817+OxideQQuickTouchSelectionController::OxideQQuickTouchSelectionController(
818+ OxideQQuickWebView* view)
819+ : d_ptr(new OxideQQuickTouchSelectionControllerPrivate()) {
820+ Q_D(OxideQQuickTouchSelectionController);
821+
822+ d->view = view;
823+}
824+
825+OxideQQuickTouchSelectionController::~OxideQQuickTouchSelectionController() {}
826+
827+bool OxideQQuickTouchSelectionController::active() const {
828+ Q_D(const OxideQQuickTouchSelectionController);
829+
830+ return d->active;
831+}
832+
833+QQmlComponent* OxideQQuickTouchSelectionController::handle() const {
834+ Q_D(const OxideQQuickTouchSelectionController);
835+
836+ return d->handle;
837+}
838+
839+void OxideQQuickTouchSelectionController::setHandle(QQmlComponent* handle) {
840+ Q_D(OxideQQuickTouchSelectionController);
841+
842+ if (handle == d->handle) {
843+ return;
844+ }
845+
846+ d->handle = handle;
847+ Q_EMIT handleChanged();
848+}
849+
850+const QRectF& OxideQQuickTouchSelectionController::bounds() const {
851+ Q_D(const OxideQQuickTouchSelectionController);
852+
853+ return d->bounds;
854+}
855+
856+void OxideQQuickTouchSelectionController::onTouchSelectionChanged(
857+ bool active,
858+ const QRectF& bounds) {
859+ Q_D(OxideQQuickTouchSelectionController);
860+
861+ if (active != d->active) {
862+ d->active = active;
863+ Q_EMIT activeChanged();
864+ }
865+
866+ if (bounds != d->bounds) {
867+ d->bounds = bounds;
868+ Q_EMIT boundsChanged();
869+ }
870+}
871
872=== added file 'qt/quick/api/oxideqquicktouchselectioncontroller_p.h'
873--- qt/quick/api/oxideqquicktouchselectioncontroller_p.h 1970-01-01 00:00:00 +0000
874+++ qt/quick/api/oxideqquicktouchselectioncontroller_p.h 2016-01-08 22:47:28 +0000
875@@ -0,0 +1,74 @@
876+// vim:expandtab:shiftwidth=2:tabstop=2:
877+// Copyright (C) 2015-2016 Canonical Ltd.
878+
879+// This library is free software; you can redistribute it and/or
880+// modify it under the terms of the GNU Lesser General Public
881+// License as published by the Free Software Foundation; either
882+// version 2.1 of the License, or (at your option) any later version.
883+
884+// This library is distributed in the hope that it will be useful,
885+// but WITHOUT ANY WARRANTY; without even the implied warranty of
886+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
887+// Lesser General Public License for more details.
888+
889+// You should have received a copy of the GNU Lesser General Public
890+// License along with this library; if not, write to the Free Software
891+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
892+
893+#ifndef _OXIDE_QT_QUICK_API_TOUCH_SELECTION_CONTROLLER_H_
894+#define _OXIDE_QT_QUICK_API_TOUCH_SELECTION_CONTROLLER_H_
895+
896+#include <QObject>
897+#include <QRectF>
898+#include <QString>
899+#include <QtGlobal>
900+
901+#include "oxideqquickwebview_p.h"
902+
903+class QQmlComponent;
904+
905+class OxideQQuickTouchSelectionControllerPrivate;
906+
907+class Q_DECL_EXPORT OxideQQuickTouchSelectionController : public QObject {
908+ Q_OBJECT
909+
910+ Q_ENUMS(HandleOrientation);
911+
912+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
913+ Q_PROPERTY(QQmlComponent* handle READ handle WRITE setHandle NOTIFY handleChanged)
914+ Q_PROPERTY(QRectF bounds READ bounds NOTIFY boundsChanged)
915+
916+ Q_DISABLE_COPY(OxideQQuickTouchSelectionController)
917+ Q_DECLARE_PRIVATE(OxideQQuickTouchSelectionController)
918+
919+ public:
920+ Q_DECL_HIDDEN OxideQQuickTouchSelectionController(OxideQQuickWebView* view);
921+ virtual ~OxideQQuickTouchSelectionController();
922+
923+ enum HandleOrientation {
924+ HandleOrientationLeft,
925+ HandleOrientationCenter,
926+ HandleOrientationRight,
927+ HandleOrientationUndefined
928+ };
929+
930+ bool active() const;
931+
932+ QQmlComponent* handle() const;
933+ void setHandle(QQmlComponent* handle);
934+
935+ const QRectF& bounds() const;
936+
937+ Q_SIGNALS:
938+ void activeChanged();
939+ void handleChanged();
940+ void boundsChanged();
941+
942+ private:
943+ friend class OxideQQuickWebViewPrivate;
944+ void onTouchSelectionChanged(bool active, const QRectF& bounds);
945+
946+ QScopedPointer<OxideQQuickTouchSelectionControllerPrivate> d_ptr;
947+};
948+
949+#endif // _OXIDE_QT_QUICK_API_TOUCH_SELECTION_CONTROLLER_H_
950
951=== modified file 'qt/quick/api/oxideqquickwebview.cc'
952--- qt/quick/api/oxideqquickwebview.cc 2015-11-23 18:06:19 +0000
953+++ qt/quick/api/oxideqquickwebview.cc 2016-01-08 22:47:28 +0000
954@@ -1,5 +1,5 @@
955 // vim:expandtab:shiftwidth=2:tabstop=2:
956-// Copyright (C) 2013-2015 Canonical Ltd.
957+// Copyright (C) 2013-2016 Canonical Ltd.
958
959 // This library is free software; you can redistribute it and/or
960 // modify it under the terms of the GNU Lesser General Public
961@@ -57,12 +57,14 @@
962 #include "qt/quick/oxide_qquick_init.h"
963 #include "qt/quick/oxide_qquick_prompt_dialog.h"
964 #include "qt/quick/oxide_qquick_software_frame_node.h"
965+#include "qt/quick/oxide_qquick_touch_handle_drawable.h"
966 #include "qt/quick/oxide_qquick_web_context_menu.h"
967 #include "qt/quick/oxide_qquick_web_popup_menu.h"
968
969 #include "oxideqquicklocationbarcontroller_p.h"
970 #include "oxideqquickscriptmessagehandler_p.h"
971 #include "oxideqquickscriptmessagehandler_p_p.h"
972+#include "oxideqquicktouchselectioncontroller_p.h"
973 #include "oxideqquickwebcontext_p.h"
974 #include "oxideqquickwebcontext_p_p.h"
975 #include "oxideqquickwebframe_p.h"
976@@ -214,6 +216,13 @@
977 return new oxide::qquick::FilePicker(q, client);
978 }
979
980+oxide::qt::TouchHandleDrawableProxy*
981+OxideQQuickWebViewPrivate::CreateTouchHandleDrawable() {
982+ Q_Q(OxideQQuickWebView);
983+
984+ return new oxide::qquick::TouchHandleDrawable(q);
985+}
986+
987 void OxideQQuickWebViewPrivate::WebProcessStatusChanged() {
988 Q_Q(OxideQQuickWebView);
989
990@@ -284,6 +293,13 @@
991 navigation_history_.onNavigationEntryChanged(index);
992 }
993
994+void OxideQQuickWebViewPrivate::TouchSelectionChanged(bool active,
995+ QRectF bounds) {
996+ Q_Q(OxideQQuickWebView);
997+
998+ q->touchSelectionController()->onTouchSelectionChanged(active, bounds);
999+}
1000+
1001 void OxideQQuickWebViewPrivate::CreateWebFrame(
1002 oxide::qt::WebFrameProxy* proxy) {
1003 Q_Q(OxideQQuickWebView);
1004@@ -642,6 +658,12 @@
1005 emit q->hoveredUrlChanged();
1006 }
1007
1008+void OxideQQuickWebViewPrivate::OnEditingCapabilitiesChanged() {
1009+ Q_Q(OxideQQuickWebView);
1010+
1011+ emit q->editingCapabilitiesChanged();
1012+}
1013+
1014 void OxideQQuickWebViewPrivate::completeConstruction() {
1015 Q_Q(OxideQQuickWebView);
1016
1017@@ -2084,6 +2106,17 @@
1018 return d->proxy()->targetUrl();
1019 }
1020
1021+OxideQQuickWebView::EditCapabilities OxideQQuickWebView::editingCapabilities() const {
1022+ Q_D(const OxideQQuickWebView);
1023+
1024+ if (!d->proxy()) {
1025+ return NoCapability;
1026+ }
1027+
1028+ oxide::qt::EditCapabilityFlags flags = d->proxy()->editFlags();
1029+ return static_cast<EditCapabilities>(flags);
1030+}
1031+
1032 // static
1033 OxideQQuickWebViewAttached* OxideQQuickWebView::qmlAttachedProperties(
1034 QObject* object) {
1035@@ -2214,4 +2247,15 @@
1036 return d->find_controller_.data();
1037 }
1038
1039+OxideQQuickTouchSelectionController* OxideQQuickWebView::touchSelectionController() {
1040+ Q_D(OxideQQuickWebView);
1041+
1042+ if (!d->touch_selection_controller_) {
1043+ d->touch_selection_controller_.reset(
1044+ new OxideQQuickTouchSelectionController(this));
1045+ }
1046+
1047+ return d->touch_selection_controller_.data();
1048+}
1049+
1050 #include "moc_oxideqquickwebview_p.cpp"
1051
1052=== modified file 'qt/quick/api/oxideqquickwebview_p.h'
1053--- qt/quick/api/oxideqquickwebview_p.h 2016-01-08 16:02:42 +0000
1054+++ qt/quick/api/oxideqquickwebview_p.h 2016-01-08 22:47:28 +0000
1055@@ -39,6 +39,7 @@
1056 class OxideQQuickLocationBarController;
1057 class OxideQQuickNavigationHistory;
1058 class OxideQQuickScriptMessageHandler;
1059+class OxideQQuickTouchSelectionController;
1060 class OxideQQuickWebContext;
1061 class OxideQQuickWebFrame;
1062 class OxideQQuickWebView;
1063@@ -133,6 +134,10 @@
1064
1065 Q_PROPERTY(QUrl hoveredUrl READ hoveredUrl NOTIFY hoveredUrlChanged REVISION 7)
1066
1067+ Q_PROPERTY(OxideQQuickTouchSelectionController* touchSelectionController READ touchSelectionController CONSTANT REVISION 7)
1068+
1069+ Q_PROPERTY(EditCapabilities editingCapabilities READ editingCapabilities NOTIFY editingCapabilitiesChanged REVISION 7)
1070+
1071 Q_DECLARE_PRIVATE(OxideQQuickWebView)
1072
1073 public:
1074@@ -303,6 +308,10 @@
1075
1076 Q_REVISION(4) Q_INVOKABLE void executeEditingCommand(EditingCommands command) const;
1077
1078+ OxideQQuickTouchSelectionController* touchSelectionController();
1079+
1080+ EditCapabilities editingCapabilities() const;
1081+
1082 public Q_SLOTS:
1083 void goBack();
1084 void goForward();
1085@@ -362,6 +371,7 @@
1086 Q_REVISION(4) void webProcessStatusChanged();
1087 Q_REVISION(5) void httpAuthenticationRequested(const QJSValue& request);
1088 Q_REVISION(7) void hoveredUrlChanged();
1089+ Q_REVISION(7) void editingCapabilitiesChanged();
1090
1091 // Deprecated since 1.3
1092 void loadingChanged(const OxideQLoadEvent& loadEvent);
1093
1094=== modified file 'qt/quick/api/oxideqquickwebview_p_p.h'
1095--- qt/quick/api/oxideqquickwebview_p_p.h 2015-11-23 17:58:35 +0000
1096+++ qt/quick/api/oxideqquickwebview_p_p.h 2016-01-08 22:47:28 +0000
1097@@ -1,5 +1,5 @@
1098 // vim:expandtab:shiftwidth=2:tabstop=2:
1099-// Copyright (C) 2013-2015 Canonical Ltd.
1100+// Copyright (C) 2013-2016 Canonical Ltd.
1101
1102 // This library is free software; you can redistribute it and/or
1103 // modify it under the terms of the GNU Lesser General Public
1104@@ -33,6 +33,7 @@
1105 class OxideQNewViewRequest;
1106 class OxideQQuickLocationBarController;
1107 class OxideQQuickScriptMessageHandler;
1108+class OxideQQuickTouchSelectionController;
1109 class OxideQQuickWebContextPrivate;
1110 class OxideQQuickWebView;
1111
1112@@ -94,6 +95,7 @@
1113 oxide::qt::JavaScriptDialogProxyClient* client) override;
1114 oxide::qt::FilePickerProxy* CreateFilePicker(
1115 oxide::qt::FilePickerProxyClient* client) override;
1116+ oxide::qt::TouchHandleDrawableProxy* CreateTouchHandleDrawable() override;
1117 void WebProcessStatusChanged() override;
1118 void URLChanged() override;
1119 void TitleChanged() override;
1120@@ -105,6 +107,7 @@
1121 void NavigationEntryCommitted() override;
1122 void NavigationListPruned(bool from_front, int count) override;
1123 void NavigationEntryChanged(int index) override;
1124+ void TouchSelectionChanged(bool active, QRectF bounds) override;
1125 void CreateWebFrame(oxide::qt::WebFrameProxy* proxy) override;
1126 QScreen* GetScreen() const override;
1127 QRect GetViewBoundsPix() const override;
1128@@ -143,6 +146,7 @@
1129 void PrepareToCloseResponse(bool proceed) override;
1130 void CloseRequested() override;
1131 void TargetURLChanged() override;
1132+ void OnEditingCapabilitiesChanged() override;
1133
1134 oxide::qt::WebViewProxy* proxy() const {
1135 return oxide::qt::WebViewProxyHandle::proxy();
1136@@ -209,6 +213,8 @@
1137 QScopedPointer<ConstructProps> construct_props_;
1138
1139 QScopedPointer<OxideQQuickLocationBarController> location_bar_controller_;
1140+
1141+ QScopedPointer<OxideQQuickTouchSelectionController> touch_selection_controller_;
1142 };
1143
1144 #endif // _OXIDE_QT_QUICK_API_WEB_VIEW_P_P_H_
1145
1146=== added file 'qt/quick/oxide_qquick_touch_handle_drawable.cc'
1147--- qt/quick/oxide_qquick_touch_handle_drawable.cc 1970-01-01 00:00:00 +0000
1148+++ qt/quick/oxide_qquick_touch_handle_drawable.cc 2016-01-08 22:47:28 +0000
1149@@ -0,0 +1,286 @@
1150+// vim:expandtab:shiftwidth=2:tabstop=2:
1151+// Copyright (C) 2015-2016 Canonical Ltd.
1152+
1153+// This library is free software; you can redistribute it and/or
1154+// modify it under the terms of the GNU Lesser General Public
1155+// License as published by the Free Software Foundation; either
1156+// version 2.1 of the License, or (at your option) any later version.
1157+
1158+// This library is distributed in the hope that it will be useful,
1159+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1160+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1161+// Lesser General Public License for more details.
1162+
1163+// You should have received a copy of the GNU Lesser General Public
1164+// License along with this library; if not, write to the Free Software
1165+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1166+
1167+#include "oxide_qquick_touch_handle_drawable.h"
1168+
1169+#include <QDebug>
1170+#include <QObject>
1171+#include <QQmlComponent>
1172+#include <QQmlContext>
1173+#include <QQmlEngine>
1174+#include <QQuickItem>
1175+
1176+#include "qt/quick/api/oxideqquicktouchselectioncontroller_p.h"
1177+#include "qt/quick/api/oxideqquickwebview_p.h"
1178+#include "qt/quick/api/oxideqquickwebview_p_p.h"
1179+
1180+namespace oxide {
1181+namespace qquick {
1182+
1183+class TouchHandleDrawableContext : public QObject {
1184+ Q_OBJECT
1185+ Q_PROPERTY(OxideQQuickTouchSelectionController::HandleOrientation orientation READ orientation NOTIFY orientationChanged FINAL)
1186+ Q_PROPERTY(bool mirrorVertical READ mirrorVertical NOTIFY mirrorVerticalChanged FINAL)
1187+ Q_PROPERTY(bool mirrorHorizontal READ mirrorHorizontal NOTIFY mirrorHorizontalChanged FINAL)
1188+ Q_PROPERTY(qreal horizontalPaddingRatio READ horizontalPaddingRatio WRITE setHorizontalPaddingRatio NOTIFY horizontalPaddingRatioChanged)
1189+
1190+ public:
1191+ virtual ~TouchHandleDrawableContext() {}
1192+ TouchHandleDrawableContext();
1193+
1194+ OxideQQuickTouchSelectionController::HandleOrientation orientation() const;
1195+ void setOrientation(
1196+ OxideQQuickTouchSelectionController::HandleOrientation orientation);
1197+
1198+ bool mirrorVertical() const;
1199+ void setMirrorVertical(bool mirror);
1200+
1201+ bool mirrorHorizontal() const;
1202+ void setMirrorHorizontal(bool mirror);
1203+
1204+ qreal horizontalPaddingRatio() const;
1205+ void setHorizontalPaddingRatio(qreal ratio);
1206+
1207+ Q_SIGNALS:
1208+ void orientationChanged() const;
1209+ void mirrorVerticalChanged() const;
1210+ void mirrorHorizontalChanged() const;
1211+ void horizontalPaddingRatioChanged() const;
1212+
1213+ private:
1214+ OxideQQuickTouchSelectionController::HandleOrientation orientation_;
1215+ bool mirror_vertical_;
1216+ bool mirror_horizontal_;
1217+ qreal horizontal_padding_ratio_;
1218+};
1219+
1220+TouchHandleDrawableContext::TouchHandleDrawableContext()
1221+ : orientation_(
1222+ OxideQQuickTouchSelectionController::HandleOrientationUndefined)
1223+ , mirror_vertical_(false)
1224+ , mirror_horizontal_(false)
1225+ , horizontal_padding_ratio_(0.0) {}
1226+
1227+OxideQQuickTouchSelectionController::HandleOrientation
1228+TouchHandleDrawableContext::orientation() const {
1229+ return orientation_;
1230+}
1231+
1232+void TouchHandleDrawableContext::setOrientation(
1233+ OxideQQuickTouchSelectionController::HandleOrientation orientation) {
1234+ if (orientation_ != orientation) {
1235+ orientation_ = orientation;
1236+ Q_EMIT orientationChanged();
1237+ }
1238+}
1239+
1240+bool TouchHandleDrawableContext::mirrorVertical() const {
1241+ return mirror_vertical_;
1242+}
1243+
1244+void TouchHandleDrawableContext::setMirrorVertical(bool mirror) {
1245+ if (mirror_vertical_ != mirror) {
1246+ mirror_vertical_ = mirror;
1247+ Q_EMIT mirrorVerticalChanged();
1248+ }
1249+}
1250+
1251+bool TouchHandleDrawableContext::mirrorHorizontal() const {
1252+ return mirror_horizontal_;
1253+}
1254+
1255+void TouchHandleDrawableContext::setMirrorHorizontal(bool mirror) {
1256+ if (mirror_horizontal_ != mirror) {
1257+ mirror_horizontal_ = mirror;
1258+ Q_EMIT mirrorHorizontalChanged();
1259+ }
1260+}
1261+
1262+qreal TouchHandleDrawableContext::horizontalPaddingRatio() const {
1263+ return horizontal_padding_ratio_;
1264+}
1265+
1266+void TouchHandleDrawableContext::setHorizontalPaddingRatio(qreal ratio) {
1267+ qreal bound = qBound(0.0, ratio, 1.0);
1268+ if (horizontal_padding_ratio_ != bound) {
1269+ horizontal_padding_ratio_ = bound;
1270+ Q_EMIT horizontalPaddingRatioChanged();
1271+ }
1272+}
1273+
1274+TouchHandleDrawable::~TouchHandleDrawable() {}
1275+
1276+void TouchHandleDrawable::SetEnabled(bool enabled) {
1277+ if (!item_.isNull()) {
1278+ item_->setVisible(enabled);
1279+ }
1280+}
1281+
1282+void TouchHandleDrawable::SetOrientation(Orientation orientation,
1283+ bool mirror_vertical,
1284+ bool mirror_horizontal) {
1285+ if (!context_.isNull()) {
1286+ TouchHandleDrawableContext* context =
1287+ qobject_cast<TouchHandleDrawableContext*>(context_->contextObject());
1288+ if (context) {
1289+ OxideQQuickTouchSelectionController::HandleOrientation o;
1290+ switch (orientation) {
1291+ case Orientation::Left:
1292+ o = OxideQQuickTouchSelectionController::HandleOrientationLeft;
1293+ break;
1294+ case Orientation::Center:
1295+ o = OxideQQuickTouchSelectionController::HandleOrientationCenter;
1296+ break;
1297+ case Orientation::Right:
1298+ o = OxideQQuickTouchSelectionController::HandleOrientationRight;
1299+ break;
1300+ case Orientation::Undefined:
1301+ o = OxideQQuickTouchSelectionController::HandleOrientationUndefined;
1302+ break;
1303+ default:
1304+ Q_UNREACHABLE();
1305+ }
1306+ context->setOrientation(o);
1307+ context->setMirrorVertical(mirror_vertical);
1308+ context->setMirrorHorizontal(mirror_horizontal);
1309+ }
1310+ }
1311+}
1312+
1313+void TouchHandleDrawable::SetOrigin(const QPointF& origin) {
1314+ if (!item_.isNull()) {
1315+ item_->setX(origin.x());
1316+ item_->setY(origin.y());
1317+ }
1318+}
1319+
1320+void TouchHandleDrawable::SetAlpha(float alpha) {
1321+ if (!item_.isNull()) {
1322+ item_->setOpacity(alpha);
1323+ }
1324+}
1325+
1326+QRectF TouchHandleDrawable::GetVisibleBounds() const {
1327+ if (item_.isNull()) {
1328+ return QRectF();
1329+ }
1330+
1331+ return QRectF(item_->x(), item_->y(), item_->width(), item_->height());
1332+}
1333+
1334+float TouchHandleDrawable::GetDrawableHorizontalPaddingRatio() const {
1335+ if (context_.isNull()) {
1336+ return 0.0f;
1337+ }
1338+
1339+ TouchHandleDrawableContext* context =
1340+ qobject_cast<TouchHandleDrawableContext*>(context_->contextObject());
1341+ return context->horizontalPaddingRatio();
1342+}
1343+
1344+void TouchHandleDrawable::instantiateComponent() {
1345+ if (view_.isNull()) {
1346+ qWarning() <<
1347+ "TouchHandleDrawable: "
1348+ "Can't instantiate after the view has gone";
1349+ return;
1350+ }
1351+
1352+ TouchHandleDrawableContext* contextObject =
1353+ new TouchHandleDrawableContext();
1354+ QQmlComponent* component = view_->touchSelectionController()->handle();
1355+ if (!component) {
1356+ qWarning() <<
1357+ "TouchHandleDrawable: Content requested a touch handle "
1358+ "drawable, but the application hasn't provided one";
1359+ delete contextObject;
1360+ return;
1361+ }
1362+
1363+ QQmlContext* baseContext = component->creationContext();
1364+ if (!baseContext) {
1365+ baseContext = QQmlEngine::contextForObject(view_.data());
1366+ }
1367+ context_.reset(new QQmlContext(baseContext));
1368+
1369+ context_->setContextObject(contextObject);
1370+ contextObject->setParent(context_.data());
1371+
1372+ item_.reset(
1373+ qobject_cast<QQuickItem*>(component->beginCreate(context_.data())));
1374+ if (!item_) {
1375+ qWarning() <<
1376+ "TouchHandleDrawable: Failed to create instance of "
1377+ "Qml touch selection handle component";
1378+ context_.reset();
1379+ return;
1380+ }
1381+
1382+ OxideQQuickWebViewPrivate::get(
1383+ view_.data())->addAttachedPropertyTo(item_.data());
1384+ item_->setParentItem(view_.data());
1385+ component->completeCreate();
1386+}
1387+
1388+TouchHandleDrawable::TouchHandleDrawable(OxideQQuickWebView* view)
1389+ : view_(view) {
1390+ instantiateComponent();
1391+
1392+ if (view) {
1393+ connect(view->touchSelectionController(), SIGNAL(handleChanged()),
1394+ SLOT(handleComponentChanged()));
1395+ }
1396+}
1397+
1398+void TouchHandleDrawable::handleComponentChanged() {
1399+ bool visible = item_.isNull() ? false : item_->isVisible();
1400+ OxideQQuickTouchSelectionController::HandleOrientation orientation =
1401+ OxideQQuickTouchSelectionController::HandleOrientationUndefined;
1402+ bool mirror_vertical = false;
1403+ bool mirror_horizontal = false;
1404+ if (!context_.isNull()) {
1405+ TouchHandleDrawableContext* context =
1406+ qobject_cast<TouchHandleDrawableContext*>(context_->contextObject());
1407+ orientation = context->orientation();
1408+ mirror_vertical = context->mirrorVertical();
1409+ mirror_horizontal = context->mirrorHorizontal();
1410+ }
1411+ QPointF position(item_.isNull() ? 0.0 : item_->x(),
1412+ item_.isNull() ? 0.0 : item_->y());
1413+ qreal opacity = item_.isNull() ? 0.0 : item_->opacity();
1414+
1415+ item_.reset();
1416+ context_.reset();
1417+ instantiateComponent();
1418+
1419+ if (!item_.isNull()) {
1420+ SetEnabled(visible);
1421+ TouchHandleDrawableContext* context =
1422+ qobject_cast<TouchHandleDrawableContext*>(
1423+ context_->contextObject());
1424+ context->setOrientation(orientation);
1425+ context->setMirrorVertical(mirror_vertical);
1426+ context->setMirrorHorizontal(mirror_horizontal);
1427+ SetOrigin(position);
1428+ SetAlpha(opacity);
1429+ }
1430+}
1431+
1432+} // namespace qquick
1433+} // namespace oxide
1434+
1435+#include "oxide_qquick_touch_handle_drawable.moc"
1436
1437=== added file 'qt/quick/oxide_qquick_touch_handle_drawable.h'
1438--- qt/quick/oxide_qquick_touch_handle_drawable.h 1970-01-01 00:00:00 +0000
1439+++ qt/quick/oxide_qquick_touch_handle_drawable.h 2016-01-08 22:47:28 +0000
1440@@ -0,0 +1,70 @@
1441+// vim:expandtab:shiftwidth=2:tabstop=2:
1442+// Copyright (C) 2015-2016 Canonical Ltd.
1443+
1444+// This library is free software; you can redistribute it and/or
1445+// modify it under the terms of the GNU Lesser General Public
1446+// License as published by the Free Software Foundation; either
1447+// version 2.1 of the License, or (at your option) any later version.
1448+
1449+// This library is distributed in the hope that it will be useful,
1450+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1451+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1452+// Lesser General Public License for more details.
1453+
1454+// You should have received a copy of the GNU Lesser General Public
1455+// License along with this library; if not, write to the Free Software
1456+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1457+
1458+#ifndef _OXIDE_QT_QUICK_TOUCH_HANDLE_DRAWABLE_H_
1459+#define _OXIDE_QT_QUICK_TOUCH_HANDLE_DRAWABLE_H_
1460+
1461+#include <QPointer>
1462+#include <QScopedPointer>
1463+#include <QtGlobal>
1464+
1465+#include "qt/core/glue/oxide_qt_touch_handle_drawable_proxy.h"
1466+
1467+class OxideQQuickWebView;
1468+
1469+QT_BEGIN_NAMESPACE
1470+class QQmlContext;
1471+class QQuickItem;
1472+QT_END_NAMESPACE
1473+
1474+namespace oxide {
1475+namespace qquick {
1476+
1477+class TouchHandleDrawable :
1478+ public QObject, public oxide::qt::TouchHandleDrawableProxy {
1479+ Q_OBJECT
1480+
1481+ public:
1482+ TouchHandleDrawable(OxideQQuickWebView* view);
1483+
1484+ private Q_SLOTS:
1485+ void handleComponentChanged();
1486+
1487+ private:
1488+ ~TouchHandleDrawable() override;
1489+
1490+ void instantiateComponent();
1491+
1492+ // oxide::qt::TouchHandleDrawableProxy implementation
1493+ void SetEnabled(bool enabled);
1494+ void SetOrientation(Orientation orientation,
1495+ bool mirror_vertical,
1496+ bool mirror_horizontal);
1497+ void SetOrigin(const QPointF& origin);
1498+ void SetAlpha(float alpha);
1499+ QRectF GetVisibleBounds() const;
1500+ float GetDrawableHorizontalPaddingRatio() const;
1501+
1502+ QPointer<OxideQQuickWebView> view_;
1503+ QScopedPointer<QQmlContext> context_;
1504+ QScopedPointer<QQuickItem> item_;
1505+};
1506+
1507+} // namespace qquick
1508+} // namespace oxide
1509+
1510+#endif // _OXIDE_QT_QUICK_TOUCH_HANDLE_DRAWABLE_H_
1511
1512=== modified file 'qt/quick/oxide_qquick_web_context_menu.cc'
1513--- qt/quick/oxide_qquick_web_context_menu.cc 2015-05-28 23:51:39 +0000
1514+++ qt/quick/oxide_qquick_web_context_menu.cc 2016-01-08 22:47:28 +0000
1515@@ -27,6 +27,7 @@
1516 #include <QUrl>
1517
1518 #include "qt/core/glue/oxide_qt_web_context_menu_proxy_client.h"
1519+#include "qt/core/glue/oxide_qt_web_view_proxy_client.h"
1520 #include "qt/quick/api/oxideqquickwebview_p.h"
1521 #include "qt/quick/api/oxideqquickwebview_p_p.h"
1522
1523
1524=== added file 'qt/tests/qmltests/api/tst_WebView_editingCapabilities.html'
1525--- qt/tests/qmltests/api/tst_WebView_editingCapabilities.html 1970-01-01 00:00:00 +0000
1526+++ qt/tests/qmltests/api/tst_WebView_editingCapabilities.html 2016-01-08 22:47:28 +0000
1527@@ -0,0 +1,6 @@
1528+<html>
1529+<body id="body">
1530+ <p id="p">lorem ipsum</p>
1531+ <textarea id="textarea" rows="3" cols="10">dolor sit amet</textarea>
1532+</body>
1533+</html>
1534
1535=== added file 'qt/tests/qmltests/api/tst_WebView_editingCapabilities.qml'
1536--- qt/tests/qmltests/api/tst_WebView_editingCapabilities.qml 1970-01-01 00:00:00 +0000
1537+++ qt/tests/qmltests/api/tst_WebView_editingCapabilities.qml 2016-01-08 22:47:28 +0000
1538@@ -0,0 +1,132 @@
1539+import QtQuick 2.0
1540+import QtTest 1.0
1541+import com.canonical.Oxide 1.12
1542+import com.canonical.Oxide.Testing 1.0
1543+
1544+TestWebView {
1545+ id: webView
1546+ focus: true
1547+ width: 200
1548+ height: 200
1549+
1550+ SignalSpy {
1551+ id: editingCapabilitiesSpy
1552+ target: webView
1553+ signalName: "editingCapabilitiesChanged"
1554+ }
1555+
1556+ TestCase {
1557+ name: "WebView_editingCapabilities"
1558+ when: windowShown
1559+
1560+ function focus_textarea() {
1561+ var r = webView.getTestApi().getBoundingClientRectForSelector("#textarea");
1562+ mouseClick(webView, r.x + r.width / 2, r.y + r.height / 2, Qt.LeftButton);
1563+ compare(webView.getTestApi().evaluateCode(
1564+ "return document.activeElement.id;", true),
1565+ "textarea");
1566+ }
1567+
1568+ function unfocus_textarea() {
1569+ var r = webView.getTestApi().getBoundingClientRectForSelector("#p");
1570+ mouseClick(webView, r.x + r.width / 2, r.y + r.height / 2, Qt.LeftButton);
1571+ compare(webView.getTestApi().evaluateCode(
1572+ "return document.activeElement.id;", true),
1573+ "body");
1574+ }
1575+
1576+ function init() {
1577+ webView.url = "http://testsuite/tst_WebView_editingCapabilities.html";
1578+ verify(webView.waitForLoadSucceeded(),
1579+ "Timed out waiting for successful load");
1580+ Utils.clearClipboard();
1581+ editingCapabilitiesSpy.clear();
1582+ }
1583+
1584+ function test_WebView_editingCapabilities_no_selection() {
1585+ compare(webView.editingCapabilities, WebView.SelectAllCapability);
1586+ }
1587+
1588+ function test_WebView_editingCapabilities_page_selection() {
1589+ webView.executeEditingCommand(WebView.EditingCommandSelectAll);
1590+ editingCapabilitiesSpy.wait();
1591+ compare(webView.editingCapabilities,
1592+ WebView.CopyCapability | WebView.SelectAllCapability);
1593+
1594+ editingCapabilitiesSpy.clear();
1595+ webView.executeEditingCommand(WebView.EditingCommandCopy);
1596+ compare(webView.editingCapabilities,
1597+ WebView.CopyCapability | WebView.SelectAllCapability);
1598+ compare(editingCapabilitiesSpy.count, 0);
1599+ }
1600+
1601+ function test_WebView_editingCapabilities_textarea_selection() {
1602+ focus_textarea();
1603+ editingCapabilitiesSpy.wait();
1604+ compare(webView.editingCapabilities, WebView.SelectAllCapability);
1605+
1606+ webView.executeEditingCommand(WebView.EditingCommandSelectAll);
1607+ editingCapabilitiesSpy.wait();
1608+ compare(webView.editingCapabilities,
1609+ WebView.CutCapability | WebView.CopyCapability |
1610+ WebView.EraseCapability | WebView.SelectAllCapability);
1611+
1612+ webView.executeEditingCommand(WebView.EditingCommandCopy);
1613+ editingCapabilitiesSpy.wait();
1614+ compare(webView.editingCapabilities,
1615+ WebView.CutCapability | WebView.CopyCapability |
1616+ WebView.PasteCapability | WebView.EraseCapability |
1617+ WebView.SelectAllCapability);
1618+
1619+ webView.executeEditingCommand(WebView.EditingCommandCut);
1620+ editingCapabilitiesSpy.wait();
1621+ compare(webView.editingCapabilities,
1622+ WebView.PasteCapability | WebView.SelectAllCapability);
1623+
1624+ webView.executeEditingCommand(WebView.EditingCommandUndo);
1625+ // FIXME: https://launchpad.net/bugs/1524288
1626+ /*editingCapabilitiesSpy.wait();
1627+ compare(webView.editingCapabilities,
1628+ WebView.CutCapability | WebView.CopyCapability |
1629+ WebView.PasteCapability | WebView.EraseCapability |
1630+ WebView.SelectAllCapability);*/
1631+
1632+ webView.executeEditingCommand(WebView.EditingCommandRedo);
1633+ // FIXME: https://launchpad.net/bugs/1524288
1634+ /*editingCapabilitiesSpy.wait();
1635+ compare(webView.editingCapabilities,
1636+ WebView.PasteCapability | WebView.SelectAllCapability);*/
1637+
1638+ webView.executeEditingCommand(WebView.EditingCommandPaste);
1639+ compare(webView.editingCapabilities,
1640+ WebView.PasteCapability | WebView.SelectAllCapability);
1641+
1642+ webView.executeEditingCommand(WebView.EditingCommandSelectAll);
1643+ editingCapabilitiesSpy.wait();
1644+ compare(webView.editingCapabilities,
1645+ WebView.CutCapability | WebView.CopyCapability |
1646+ WebView.PasteCapability | WebView.EraseCapability |
1647+ WebView.SelectAllCapability);
1648+
1649+ webView.executeEditingCommand(WebView.EditingCommandErase);
1650+ // FIXME: https://launchpad.net/bugs/1524288
1651+ /*editingCapabilitiesSpy.wait();
1652+ compare(webView.editingCapabilities,
1653+ WebView.PasteCapability | WebView.SelectAllCapability);*/
1654+ }
1655+
1656+ function test_WebView_editingCapabilities_clipboard_data_changed() {
1657+ focus_textarea();
1658+ compare(webView.editingCapabilities, WebView.SelectAllCapability);
1659+
1660+ Utils.copyToClipboard("text/plain", "foo bar baz");
1661+ editingCapabilitiesSpy.wait();
1662+ compare(webView.editingCapabilities,
1663+ WebView.PasteCapability | WebView.SelectAllCapability);
1664+
1665+ Utils.clearClipboard();
1666+ editingCapabilitiesSpy.wait();
1667+ compare(webView.editingCapabilities, WebView.SelectAllCapability);
1668+ }
1669+ }
1670+}
1671
1672=== modified file 'shared/browser/oxide_browser_platform_integration.cc'
1673--- shared/browser/oxide_browser_platform_integration.cc 2015-11-30 11:23:36 +0000
1674+++ shared/browser/oxide_browser_platform_integration.cc 2016-01-08 22:47:28 +0000
1675@@ -101,4 +101,10 @@
1676 ApplicationStateChanged());
1677 }
1678
1679+void BrowserPlatformIntegration::NotifyClipboardDataChanged() {
1680+ FOR_EACH_OBSERVER(BrowserPlatformIntegrationObserver,
1681+ observers_,
1682+ ClipboardDataChanged());
1683+}
1684+
1685 } // namespace oxide
1686
1687=== modified file 'shared/browser/oxide_browser_platform_integration.h'
1688--- shared/browser/oxide_browser_platform_integration.h 2015-11-30 11:23:36 +0000
1689+++ shared/browser/oxide_browser_platform_integration.h 2016-01-08 22:47:28 +0000
1690@@ -110,6 +110,8 @@
1691
1692 void NotifyApplicationStateChanged();
1693
1694+ void NotifyClipboardDataChanged();
1695+
1696 private:
1697 friend class BrowserPlatformIntegrationObserver;
1698
1699
1700=== modified file 'shared/browser/oxide_browser_platform_integration_observer.h'
1701--- shared/browser/oxide_browser_platform_integration_observer.h 2015-11-30 11:23:36 +0000
1702+++ shared/browser/oxide_browser_platform_integration_observer.h 2016-01-08 22:47:28 +0000
1703@@ -1,5 +1,5 @@
1704 // vim:expandtab:shiftwidth=2:tabstop=2:
1705-// Copyright (C) 2014 Canonical Ltd.
1706+// Copyright (C) 2014-2015 Canonical Ltd.
1707
1708 // This library is free software; you can redistribute it and/or
1709 // modify it under the terms of the GNU Lesser General Public
1710@@ -28,6 +28,8 @@
1711
1712 virtual void ApplicationStateChanged() {}
1713
1714+ virtual void ClipboardDataChanged() {}
1715+
1716 protected:
1717 BrowserPlatformIntegrationObserver();
1718 };
1719
1720=== modified file 'shared/browser/oxide_render_widget_host_view.cc'
1721--- shared/browser/oxide_render_widget_host_view.cc 2016-01-04 13:40:25 +0000
1722+++ shared/browser/oxide_render_widget_host_view.cc 2016-01-08 22:47:28 +0000
1723@@ -1,5 +1,5 @@
1724 // vim:expandtab:shiftwidth=2:tabstop=2:
1725-// Copyright (C) 2013-2015 Canonical Ltd.
1726+// Copyright (C) 2013-2016 Canonical Ltd.
1727
1728 // This library is free software; you can redistribute it and/or
1729 // modify it under the terms of the GNU Lesser General Public
1730@@ -29,17 +29,23 @@
1731 #include "cc/output/compositor_frame.h"
1732 #include "cc/output/compositor_frame_ack.h"
1733 #include "cc/output/delegated_frame_data.h"
1734+#include "cc/output/viewport_selection_bound.h"
1735 #include "cc/quads/render_pass.h"
1736+#include "content/browser/renderer_host/render_widget_host_delegate.h"
1737 #include "content/browser/renderer_host/render_widget_host_impl.h"
1738 #include "content/public/browser/browser_thread.h"
1739 #include "content/public/browser/render_process_host.h"
1740+#include "content/public/browser/render_view_host.h"
1741 #include "content/public/common/content_switches.h"
1742 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
1743 #include "third_party/WebKit/public/platform/WebGestureDevice.h"
1744 #include "third_party/WebKit/public/web/WebInputEvent.h"
1745+#include "ui/base/touch/selection_bound.h"
1746 #include "ui/events/gesture_detection/motion_event.h"
1747+#include "ui/gfx/geometry/point_conversions.h"
1748 #include "ui/gfx/geometry/rect_conversions.h"
1749 #include "ui/gfx/geometry/size_conversions.h"
1750+#include "ui/touch_selection/touch_selection_controller.h"
1751
1752 #include "shared/browser/compositor/oxide_compositor.h"
1753 #include "shared/browser/input/oxide_input_method_context.h"
1754@@ -78,7 +84,35 @@
1755 return content_width_css <= window_width_dip + kMobileViewportWidthEpsilon;
1756 }
1757
1758-}
1759+ui::SelectionBound::Type ConvertSelectionBoundType(
1760+ cc::SelectionBoundType type) {
1761+ switch (type) {
1762+ case cc::SELECTION_BOUND_LEFT:
1763+ return ui::SelectionBound::LEFT;
1764+ case cc::SELECTION_BOUND_RIGHT:
1765+ return ui::SelectionBound::RIGHT;
1766+ case cc::SELECTION_BOUND_CENTER:
1767+ return ui::SelectionBound::CENTER;
1768+ case cc::SELECTION_BOUND_EMPTY:
1769+ return ui::SelectionBound::EMPTY;
1770+ }
1771+ NOTREACHED() << "Unknown selection bound type";
1772+ return ui::SelectionBound::EMPTY;
1773+}
1774+
1775+// Copied from content/browser/renderer_host/input/ui_touch_selection_helper.cc,
1776+// because that helper is not part of content’s public API.
1777+ui::SelectionBound ConvertSelectionBound(
1778+ const cc::ViewportSelectionBound& bound) {
1779+ ui::SelectionBound ui_bound;
1780+ ui_bound.set_type(ConvertSelectionBoundType(bound.type));
1781+ ui_bound.set_visible(bound.visible);
1782+ if (ui_bound.type() != ui::SelectionBound::EMPTY)
1783+ ui_bound.SetEdge(bound.edge_top, bound.edge_bottom);
1784+ return ui_bound;
1785+}
1786+
1787+} // namespace
1788
1789 void RenderWidgetHostView::OnTextInputStateChanged(
1790 ui::TextInputType type,
1791@@ -112,6 +146,10 @@
1792 ime_bridge_.SelectionBoundsChanged(caret_rect,
1793 selection_cursor_position,
1794 selection_anchor_position);
1795+
1796+ if (container_) {
1797+ container_->EditingCapabilitiesChanged();
1798+ }
1799 }
1800
1801 void RenderWidgetHostView::SelectionChanged(const base::string16& text,
1802@@ -266,6 +304,13 @@
1803 if (!compositor || !compositor->IsActive()) {
1804 RunAckCallbacks();
1805 }
1806+
1807+ const cc::ViewportSelection& selection = compositor_frame_metadata_.selection;
1808+ selection_controller_->OnSelectionEditable(selection.is_editable);
1809+ selection_controller_->OnSelectionEmpty(selection.is_empty_text_form_control);
1810+ selection_controller_->OnSelectionBoundsChanged(
1811+ ConvertSelectionBound(selection.start),
1812+ ConvertSelectionBound(selection.end));
1813 }
1814
1815 void RenderWidgetHostView::ClearCompositorFrame() {
1816@@ -473,6 +518,10 @@
1817 return;
1818 }
1819
1820+ if (HandleGestureForTouchSelection(event)) {
1821+ return;
1822+ }
1823+
1824 if (event.type == blink::WebInputEvent::GestureTapDown) {
1825 // Webkit does not stop a fling-scroll on tap-down. So explicitly send an
1826 // event to stop any in-progress flings.
1827@@ -489,6 +538,43 @@
1828 host_->ForwardGestureEvent(event);
1829 }
1830
1831+bool RenderWidgetHostView::HandleGestureForTouchSelection(
1832+ const blink::WebGestureEvent& event) const {
1833+ switch (event.type) {
1834+ case blink::WebInputEvent::GestureLongPress: {
1835+ base::TimeTicks event_time = base::TimeTicks() +
1836+ base::TimeDelta::FromSecondsD(event.timeStampSeconds);
1837+ gfx::PointF location(event.x, event.y);
1838+ if (selection_controller_->WillHandleLongPressEvent(
1839+ event_time, location)) {
1840+ return true;
1841+ }
1842+ break;
1843+ }
1844+ case blink::WebInputEvent::GestureTap: {
1845+ gfx::PointF location(event.x, event.y);
1846+ if (selection_controller_->WillHandleTapEvent(
1847+ location, event.data.tap.tapCount)) {
1848+ return true;
1849+ }
1850+ break;
1851+ }
1852+ case blink::WebInputEvent::GestureScrollBegin:
1853+ // XXX: currently commented out because when doing a pinch-to-zoom
1854+ // gesture, we don’t always get the corresponding GestureScrollEnd event,
1855+ // so selection handles would remain hidden.
1856+ //selection_controller()->SetTemporarilyHidden(true);
1857+ break;
1858+ case blink::WebInputEvent::GestureScrollEnd:
1859+ // XXX: see above
1860+ //selection_controller()->SetTemporarilyHidden(false);
1861+ break;
1862+ default:
1863+ break;
1864+ }
1865+ return false;
1866+}
1867+
1868 void RenderWidgetHostView::EvictCurrentFrame() {
1869 frame_is_evicted_ = true;
1870 DestroyDelegatedContent();
1871@@ -500,6 +586,55 @@
1872 }
1873 }
1874
1875+bool RenderWidgetHostView::SupportsAnimation() const {
1876+ return false;
1877+}
1878+
1879+void RenderWidgetHostView::SetNeedsAnimate() {
1880+ NOTREACHED();
1881+}
1882+
1883+void RenderWidgetHostView::MoveCaret(const gfx::PointF& position) {
1884+ content::RenderWidgetHostImpl* rwhi =
1885+ content::RenderWidgetHostImpl::From(host_);
1886+ rwhi->MoveCaret(gfx::ToRoundedPoint(position));
1887+}
1888+
1889+void RenderWidgetHostView::MoveRangeSelectionExtent(const gfx::PointF& extent) {
1890+ content::RenderWidgetHostImpl* rwhi =
1891+ content::RenderWidgetHostImpl::From(host_);
1892+ content::RenderWidgetHostDelegate* host_delegate = rwhi->delegate();
1893+ if (host_delegate) {
1894+ host_delegate->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent));
1895+ }
1896+}
1897+
1898+void RenderWidgetHostView::SelectBetweenCoordinates(const gfx::PointF& base,
1899+ const gfx::PointF& extent) {
1900+ content::RenderWidgetHostImpl* rwhi =
1901+ content::RenderWidgetHostImpl::From(host_);
1902+ content::RenderWidgetHostDelegate* host_delegate = rwhi->delegate();
1903+ if (host_delegate) {
1904+ host_delegate->SelectRange(gfx::ToRoundedPoint(base),
1905+ gfx::ToRoundedPoint(extent));
1906+ }
1907+}
1908+
1909+void RenderWidgetHostView::OnSelectionEvent(ui::SelectionEventType event) {
1910+ if (container_) {
1911+ container_->TouchSelectionChanged();
1912+ }
1913+}
1914+
1915+scoped_ptr<ui::TouchHandleDrawable> RenderWidgetHostView::CreateDrawable() {
1916+ if (!container_) {
1917+ return nullptr;
1918+ }
1919+
1920+ return scoped_ptr<ui::TouchHandleDrawable>(
1921+ container_->CreateTouchHandleDrawable());
1922+}
1923+
1924 void RenderWidgetHostView::UpdateCurrentCursor() {
1925 if (is_loading_) {
1926 content::WebCursor::CursorInfo busy_cursor_info(
1927@@ -593,6 +728,16 @@
1928 host_->SetView(this);
1929
1930 gesture_provider_->SetDoubleTapSupportForPageEnabled(false);
1931+
1932+ ui::TouchSelectionController::Config tsc_config;
1933+ // default values from ui/events/gesture_detection/gesture_configuration.cc
1934+ tsc_config.max_tap_duration = base::TimeDelta::FromMilliseconds(150);
1935+ tsc_config.tap_slop = 15;
1936+ tsc_config.enable_adaptive_handle_orientation = false;
1937+ tsc_config.show_on_tap_for_empty_editable = true;
1938+ tsc_config.enable_longpress_drag_selection = false;
1939+ selection_controller_.reset(
1940+ new ui::TouchSelectionController(this, tsc_config));
1941 }
1942
1943 RenderWidgetHostView::~RenderWidgetHostView() {
1944@@ -624,9 +769,15 @@
1945 void RenderWidgetHostView::Blur() {
1946 host_->SetActive(false);
1947 host_->Blur();
1948+
1949+ selection_controller_->HideAndDisallowShowingAutomatically();
1950 }
1951
1952 void RenderWidgetHostView::HandleTouchEvent(const ui::MotionEvent& event) {
1953+ if (selection_controller_->WillHandleTouchEvent(event)) {
1954+ return;
1955+ }
1956+
1957 auto rv = gesture_provider_->OnTouchEvent(event);
1958 if (!rv.succeeded) {
1959 return;
1960
1961=== modified file 'shared/browser/oxide_render_widget_host_view.h'
1962--- shared/browser/oxide_render_widget_host_view.h 2016-01-04 13:40:25 +0000
1963+++ shared/browser/oxide_render_widget_host_view.h 2016-01-08 22:47:28 +0000
1964@@ -1,5 +1,5 @@
1965 // vim:expandtab:shiftwidth=2:tabstop=2:
1966-// Copyright (C) 2013-2015 Canonical Ltd.
1967+// Copyright (C) 2013-2016 Canonical Ltd.
1968
1969 // This library is free software; you can redistribute it and/or
1970 // modify it under the terms of the GNU Lesser General Public
1971@@ -30,6 +30,7 @@
1972 #include "cc/output/compositor_frame_metadata.h"
1973 #include "content/common/cursors/webcursor.h"
1974 #include "ui/gfx/geometry/size.h"
1975+#include "ui/touch_selection/touch_selection_controller.h"
1976
1977 #include "shared/browser/compositor/oxide_compositor_observer.h"
1978 #include "shared/browser/input/oxide_ime_bridge_impl.h"
1979@@ -48,6 +49,8 @@
1980
1981 namespace ui {
1982 class MotionEvent;
1983+class TouchHandleDrawable;
1984+class TouchSelectionController;
1985 }
1986
1987 namespace oxide {
1988@@ -60,6 +63,7 @@
1989 public GestureProviderClient,
1990 public RendererFrameEvictorClient,
1991 public cc::DelegatedFrameResourceCollectionClient,
1992+ public ui::TouchSelectionControllerClient,
1993 public base::SupportsWeakPtr<RenderWidgetHostView> {
1994 public:
1995 RenderWidgetHostView(content::RenderWidgetHostImpl* render_widget_host);
1996@@ -73,6 +77,10 @@
1997 return selection_text_;
1998 }
1999
2000+ const gfx::Range& selection_range() const {
2001+ return selection_range_;
2002+ }
2003+
2004 const cc::CompositorFrameMetadata& compositor_frame_metadata() const {
2005 return compositor_frame_metadata_;
2006 }
2007@@ -92,6 +100,10 @@
2008 void Show() final;
2009 void Hide() final;
2010
2011+ ui::TouchSelectionController* selection_controller() const {
2012+ return selection_controller_.get();
2013+ }
2014+
2015 private:
2016 // content::RenderWidgetHostViewOxide implementation
2017 void OnTextInputStateChanged(ui::TextInputType type,
2018@@ -172,6 +184,16 @@
2019 // cc::DelegatedFrameResourceCollectionClient implementation
2020 void UnusedResourcesAreAvailable() final;
2021
2022+ // ui::TouchSelectionControllerClient implementation
2023+ bool SupportsAnimation() const override;
2024+ void SetNeedsAnimate() override;
2025+ void MoveCaret(const gfx::PointF& position) override;
2026+ void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
2027+ void SelectBetweenCoordinates(const gfx::PointF& base,
2028+ const gfx::PointF& extent) override;
2029+ void OnSelectionEvent(ui::SelectionEventType event) override;
2030+ scoped_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
2031+
2032 // ===================
2033
2034 void UpdateCurrentCursor();
2035@@ -183,6 +205,8 @@
2036 void AttachLayer();
2037 void DetachLayer();
2038
2039+ bool HandleGestureForTouchSelection(const blink::WebGestureEvent& event) const;
2040+
2041 content::RenderWidgetHostImpl* host_;
2042
2043 RenderWidgetHostViewContainer* container_;
2044@@ -217,6 +241,8 @@
2045
2046 scoped_ptr<GestureProvider> gesture_provider_;
2047
2048+ scoped_ptr<ui::TouchSelectionController> selection_controller_;
2049+
2050 DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostView);
2051 };
2052
2053
2054=== modified file 'shared/browser/oxide_render_widget_host_view_container.h'
2055--- shared/browser/oxide_render_widget_host_view_container.h 2015-10-27 19:37:13 +0000
2056+++ shared/browser/oxide_render_widget_host_view_container.h 2016-01-08 22:47:28 +0000
2057@@ -1,5 +1,5 @@
2058 // vim:expandtab:shiftwidth=2:tabstop=2:
2059-// Copyright (C) 2014-2015 Canonical Ltd.
2060+// Copyright (C) 2014-2016 Canonical Ltd.
2061
2062 // This library is free software; you can redistribute it and/or
2063 // modify it under the terms of the GNU Lesser General Public
2064@@ -21,6 +21,7 @@
2065 #include <vector>
2066
2067 #include "base/memory/ref_counted.h"
2068+#include "base/memory/scoped_ptr.h"
2069 #include "content/public/common/menu_item.h"
2070 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
2071 #include "ui/gfx/geometry/rect.h"
2072@@ -39,6 +40,10 @@
2073 class Rect;
2074 }
2075
2076+namespace ui {
2077+class TouchHandleDrawable;
2078+}
2079+
2080 namespace oxide {
2081
2082 class Compositor;
2083@@ -79,6 +84,12 @@
2084 const std::vector<content::MenuItem>& items,
2085 bool allow_multiple_selection) = 0;
2086 virtual void HidePopupMenu() = 0;
2087+
2088+ virtual ui::TouchHandleDrawable* CreateTouchHandleDrawable() const = 0;
2089+
2090+ virtual void TouchSelectionChanged() const = 0;
2091+
2092+ virtual void EditingCapabilitiesChanged() = 0;
2093 };
2094
2095 } // namespace oxide
2096
2097=== modified file 'shared/browser/oxide_web_view.cc'
2098--- shared/browser/oxide_web_view.cc 2016-01-04 13:40:25 +0000
2099+++ shared/browser/oxide_web_view.cc 2016-01-08 22:47:28 +0000
2100@@ -1,5 +1,5 @@
2101 // vim:expandtab:shiftwidth=2:tabstop=2:
2102-// Copyright (C) 2013-2015 Canonical Ltd.
2103+// Copyright (C) 2013-2016 Canonical Ltd.
2104
2105 // This library is free software; you can redistribute it and/or
2106 // modify it under the terms of the GNU Lesser General Public
2107@@ -60,10 +60,12 @@
2108 #include "net/base/net_errors.h"
2109 #include "net/ssl/ssl_info.h"
2110 #include "third_party/WebKit/public/web/WebInputEvent.h"
2111+#include "ui/base/clipboard/clipboard.h"
2112 #include "ui/base/window_open_disposition.h"
2113 #include "ui/events/event.h"
2114 #include "ui/gl/gl_implementation.h"
2115 #include "ui/shell_dialogs/selected_file_info.h"
2116+#include "ui/touch_selection/touch_selection_controller.h"
2117 #include "url/gurl.h"
2118 #include "url/url_constants.h"
2119
2120@@ -149,6 +151,18 @@
2121 FaviconHelper::CreateForWebContents(contents);
2122 }
2123
2124+bool HasLocationBarOffsetChanged(const cc::CompositorFrameMetadata& old,
2125+ const cc::CompositorFrameMetadata& current) {
2126+ if (old.location_bar_offset.y() != current.location_bar_offset.y()) {
2127+ return true;
2128+ }
2129+ if (old.location_bar_content_translation.y() !=
2130+ current.location_bar_content_translation.y()) {
2131+ return true;
2132+ }
2133+ return false;
2134+}
2135+
2136 OXIDE_MAKE_ENUM_BITWISE_OPERATORS(ui::PageTransition)
2137 OXIDE_MAKE_ENUM_BITWISE_OPERATORS(ContentType)
2138
2139@@ -211,6 +225,7 @@
2140 location_bar_height_pix_(0),
2141 location_bar_constraints_(blink::WebTopControlsBoth),
2142 location_bar_animated_(true),
2143+ edit_flags_(blink::WebContextMenuData::CanDoNone),
2144 weak_factory_(this) {
2145 CHECK(client) << "Didn't specify a client";
2146
2147@@ -435,6 +450,21 @@
2148 // TODO(chrisccoulson): Merge these
2149 client_->FrameMetadataUpdated(old);
2150 client_->SwapCompositorFrame();
2151+
2152+ RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
2153+ if (rwhv) {
2154+ ui::TouchSelectionController* controller = rwhv->selection_controller();
2155+ // If the location bar offset changes while a touch selection is active,
2156+ // the bounding rect and the position of the handles need to be updated.
2157+ if ((controller->active_status() !=
2158+ ui::TouchSelectionController::INACTIVE) &&
2159+ HasLocationBarOffsetChanged(old, compositor_frame_metadata_)) {
2160+ TouchSelectionChanged();
2161+ // XXX: hack to ensure the position of the handles is updated.
2162+ controller->SetTemporarilyHidden(true);
2163+ controller->SetTemporarilyHidden(false);
2164+ }
2165+ }
2166 }
2167
2168 void WebView::WebPreferencesDestroyed() {
2169@@ -537,6 +567,62 @@
2170 active_popup_menu_->Close();
2171 }
2172
2173+ui::TouchHandleDrawable* WebView::CreateTouchHandleDrawable() const {
2174+ return client_->CreateTouchHandleDrawable();
2175+}
2176+
2177+void WebView::TouchSelectionChanged() const {
2178+ RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
2179+ if (!rwhv) {
2180+ return;
2181+ }
2182+
2183+ ui::TouchSelectionController* controller = rwhv->selection_controller();
2184+ bool active =
2185+ (controller->active_status() != ui::TouchSelectionController::INACTIVE);
2186+
2187+ gfx::RectF bounds = controller->GetRectBetweenBounds();
2188+ bounds.Offset(0, GetLocationBarContentOffsetDip());
2189+
2190+ client_->TouchSelectionChanged(active, bounds);
2191+}
2192+
2193+void WebView::EditingCapabilitiesChanged() {
2194+ int flags = blink::WebContextMenuData::CanDoNone;
2195+ RenderWidgetHostView* rwhv = GetRenderWidgetHostView();
2196+ if (!rwhv) {
2197+ edit_flags_ = flags;
2198+ return;
2199+ }
2200+
2201+ ui::TextInputType text_input_type = rwhv->ime_bridge()->text_input_type();
2202+ bool editable = (text_input_type != ui::TEXT_INPUT_TYPE_NONE);
2203+ bool readable = (text_input_type != ui::TEXT_INPUT_TYPE_PASSWORD);
2204+ bool has_selection = !rwhv->selection_range().is_empty();
2205+ base::string16 clipboard;
2206+ ui::Clipboard::GetForCurrentThread()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE,
2207+ &clipboard);
2208+ // XXX: if editable, can we determine whether undo/redo is available?
2209+ if (editable && readable && has_selection) {
2210+ flags |= blink::WebContextMenuData::CanCut;
2211+ }
2212+ if (readable && has_selection) {
2213+ flags |= blink::WebContextMenuData::CanCopy;
2214+ }
2215+ if (editable && !clipboard.empty()) {
2216+ flags |= blink::WebContextMenuData::CanPaste;
2217+ }
2218+ if (editable && has_selection) {
2219+ flags |= blink::WebContextMenuData::CanDelete;
2220+ }
2221+ flags |= blink::WebContextMenuData::CanSelectAll;
2222+
2223+ if (flags != edit_flags_) {
2224+ edit_flags_ = flags;
2225+ client_->OnEditingCapabilitiesChanged();
2226+ }
2227+}
2228+
2229 content::WebContents* WebView::OpenURLFromTab(
2230 content::WebContents* source,
2231 const content::OpenURLParams& params) {
2232@@ -971,6 +1057,8 @@
2233 }
2234
2235 InitializeTopControlsForHost(new_host, !old_host);
2236+
2237+ EditingCapabilitiesChanged();
2238 }
2239
2240 void WebView::DidStartLoading() {
2241@@ -1190,6 +1278,10 @@
2242 return handled;
2243 }
2244
2245+void WebView::ClipboardDataChanged() {
2246+ EditingCapabilitiesChanged();
2247+}
2248+
2249 WebView::WebView(const Params& params)
2250 : WebView(params.client) {
2251 CHECK(params.context) << "Didn't specify a BrowserContext";
2252@@ -1676,17 +1768,17 @@
2253 return gfx::Size(std::round(size.width()), std::round(size.height()));
2254 }
2255
2256-int WebView::GetLocationBarOffsetPix() {
2257+int WebView::GetLocationBarOffsetPix() const {
2258 return compositor_frame_metadata().location_bar_offset.y() *
2259 compositor_frame_metadata().device_scale_factor;
2260 }
2261
2262-int WebView::GetLocationBarContentOffsetPix() {
2263+int WebView::GetLocationBarContentOffsetPix() const {
2264 return compositor_frame_metadata().location_bar_content_translation.y() *
2265 compositor_frame_metadata().device_scale_factor;
2266 }
2267
2268-float WebView::GetLocationBarContentOffsetDip() {
2269+float WebView::GetLocationBarContentOffsetDip() const {
2270 return compositor_frame_metadata().location_bar_content_translation.y();
2271 }
2272
2273@@ -1958,5 +2050,9 @@
2274 return client_->CanCreateWindows();
2275 }
2276
2277+int WebView::GetEditFlags() const {
2278+ return edit_flags_;
2279+}
2280+
2281 } // namespace oxide
2282
2283
2284=== modified file 'shared/browser/oxide_web_view.h'
2285--- shared/browser/oxide_web_view.h 2016-01-04 13:40:25 +0000
2286+++ shared/browser/oxide_web_view.h 2016-01-08 22:47:28 +0000
2287@@ -1,5 +1,5 @@
2288 // vim:expandtab:shiftwidth=2:tabstop=2:
2289-// Copyright (C) 2013-2015 Canonical Ltd.
2290+// Copyright (C) 2013-2016 Canonical Ltd.
2291
2292 // This library is free software; you can redistribute it and/or
2293 // modify it under the terms of the GNU Lesser General Public
2294@@ -44,6 +44,7 @@
2295 #include "shared/browser/compositor/oxide_compositor_client.h"
2296 #include "shared/browser/compositor/oxide_compositor_observer.h"
2297 #include "shared/browser/input/oxide_input_method_context_observer.h"
2298+#include "shared/browser/oxide_browser_platform_integration_observer.h"
2299 #include "shared/browser/oxide_content_types.h"
2300 #include "shared/browser/oxide_render_object_id.h"
2301 #include "shared/browser/oxide_render_widget_host_view_container.h"
2302@@ -85,6 +86,7 @@
2303
2304 namespace ui {
2305 class TouchEvent;
2306+class TouchHandleDrawable;
2307 }
2308
2309 namespace oxide {
2310@@ -131,7 +133,8 @@
2311 private content::NotificationObserver,
2312 private RenderWidgetHostViewContainer,
2313 private content::WebContentsDelegate,
2314- private content::WebContentsObserver {
2315+ private content::WebContentsObserver,
2316+ private BrowserPlatformIntegrationObserver {
2317 public:
2318
2319 struct Params {
2320@@ -225,9 +228,9 @@
2321 gfx::Size GetCompositorFrameContentSizePix();
2322 gfx::Size GetCompositorFrameViewportSizePix();
2323
2324- int GetLocationBarOffsetPix();
2325- int GetLocationBarContentOffsetPix();
2326- float GetLocationBarContentOffsetDip();
2327+ int GetLocationBarOffsetPix() const;
2328+ int GetLocationBarContentOffsetPix() const;
2329+ float GetLocationBarContentOffsetDip() const;
2330
2331 const SecurityStatus& security_status() const { return security_status_; }
2332
2333@@ -290,6 +293,8 @@
2334
2335 const GURL& target_url() const { return target_url_; }
2336
2337+ int GetEditFlags() const;
2338+
2339 private:
2340 WebView(WebViewClient* client);
2341
2342@@ -358,6 +363,9 @@
2343 const std::vector<content::MenuItem>& items,
2344 bool allow_multiple_selection) final;
2345 void HidePopupMenu() final;
2346+ ui::TouchHandleDrawable* CreateTouchHandleDrawable() const final;
2347+ void TouchSelectionChanged() const final;
2348+ void EditingCapabilitiesChanged() final;
2349
2350 // content::WebContentsDelegate implementation
2351 content::WebContents* OpenURLFromTab(content::WebContents* source,
2352@@ -472,6 +480,9 @@
2353 bool OnMessageReceived(const IPC::Message& msg,
2354 content::RenderFrameHost* render_frame_host) final;
2355
2356+ // BrowserPlatformIntegrationObserver implementation
2357+ void ClipboardDataChanged() final;
2358+
2359 WebViewClient* client_;
2360
2361 struct WebContentsDeleter {
2362@@ -516,6 +527,8 @@
2363
2364 GURL target_url_;
2365
2366+ int edit_flags_;
2367+
2368 base::WeakPtrFactory<WebView> weak_factory_;
2369
2370 DISALLOW_COPY_AND_ASSIGN(WebView);
2371
2372=== modified file 'shared/browser/oxide_web_view_client.cc'
2373--- shared/browser/oxide_web_view_client.cc 2015-11-23 17:58:35 +0000
2374+++ shared/browser/oxide_web_view_client.cc 2016-01-08 22:47:28 +0000
2375@@ -1,5 +1,5 @@
2376 // vim:expandtab:shiftwidth=2:tabstop=2:
2377-// Copyright (C) 2015 Canonical Ltd.
2378+// Copyright (C) 2015-2016 Canonical Ltd.
2379
2380 // This library is free software; you can redistribute it and/or
2381 // modify it under the terms of the GNU Lesser General Public
2382@@ -131,6 +131,13 @@
2383 return nullptr;
2384 }
2385
2386+ui::TouchHandleDrawable* WebViewClient::CreateTouchHandleDrawable() const {
2387+ return nullptr;
2388+}
2389+
2390+void WebViewClient::TouchSelectionChanged(bool active,
2391+ const gfx::RectF& bounds) const {}
2392+
2393 void WebViewClient::EvictCurrentFrame() {}
2394
2395 InputMethodContext* WebViewClient::GetInputMethodContext() const {
2396@@ -152,4 +159,6 @@
2397 void WebViewClient::HttpAuthenticationRequested(
2398 ResourceDispatcherHostLoginDelegate* login_delegate) {}
2399
2400+void WebViewClient::OnEditingCapabilitiesChanged() {}
2401+
2402 } // namespace oxide
2403
2404=== modified file 'shared/browser/oxide_web_view_client.h'
2405--- shared/browser/oxide_web_view_client.h 2015-11-23 17:58:35 +0000
2406+++ shared/browser/oxide_web_view_client.h 2016-01-08 22:47:28 +0000
2407@@ -1,5 +1,5 @@
2408 // vim:expandtab:shiftwidth=2:tabstop=2:
2409-// Copyright (C) 2015 Canonical Ltd.
2410+// Copyright (C) 2015-2016 Canonical Ltd.
2411
2412 // This library is free software; you can redistribute it and/or
2413 // modify it under the terms of the GNU Lesser General Public
2414@@ -44,6 +44,14 @@
2415 class WebCursor;
2416 }
2417
2418+namespace gfx {
2419+class RectF;
2420+}
2421+
2422+namespace ui {
2423+class TouchHandleDrawable;
2424+}
2425+
2426 namespace oxide {
2427
2428 class CertificateError;
2429@@ -52,6 +60,7 @@
2430 class JavaScriptDialog;
2431 class ResourceDispatcherHostLoginDelegate;
2432 class SecurityStatus;
2433+class TouchHandleDrawableDelegate;
2434 class WebContextMenu;
2435 class WebPopupMenu;
2436 class WebView;
2437@@ -162,6 +171,10 @@
2438
2439 virtual FilePicker* CreateFilePicker(content::RenderViewHost* rvh);
2440
2441+ virtual ui::TouchHandleDrawable* CreateTouchHandleDrawable() const;
2442+ virtual void TouchSelectionChanged(bool active,
2443+ const gfx::RectF& bounds) const;
2444+
2445 virtual void SwapCompositorFrame() = 0;
2446
2447 virtual void EvictCurrentFrame();
2448@@ -187,6 +200,8 @@
2449
2450 virtual void HttpAuthenticationRequested(
2451 ResourceDispatcherHostLoginDelegate* login_delegate);
2452+
2453+ virtual void OnEditingCapabilitiesChanged();
2454 };
2455
2456 } // namespace oxide
2457
2458=== modified file 'shared/renderer/oxide_content_renderer_client.cc'
2459--- shared/renderer/oxide_content_renderer_client.cc 2015-10-13 21:42:44 +0000
2460+++ shared/renderer/oxide_content_renderer_client.cc 2016-01-08 22:47:28 +0000
2461@@ -100,9 +100,6 @@
2462 blink::WebSettings* settings = render_view->GetWebView()->settings();
2463 settings->setDoubleTapToZoomEnabled(true); // XXX: Make this configurable
2464
2465- // Remove this when we implement a selection API (see bug #1324292)
2466- settings->setTouchEditingEnabled(false);
2467-
2468 if (GetFormFactorHint() == FORM_FACTOR_TABLET ||
2469 GetFormFactorHint() == FORM_FACTOR_PHONE) {
2470 settings->setAllowCustomScrollbarInMainFrame(false);
2471@@ -110,6 +107,7 @@
2472 settings->setMainFrameClipsContent(false);
2473 settings->setShrinksViewportContentToFit(true);
2474 settings->setUseMobileViewportStyle(true);
2475+ settings->setTouchEditingEnabled(true);
2476 }
2477 }
2478
2479
2480=== modified file 'shared/shared.gyp'
2481--- shared/shared.gyp 2016-01-08 21:31:20 +0000
2482+++ shared/shared.gyp 2016-01-08 22:47:28 +0000
2483@@ -1,4 +1,4 @@
2484-# Copyright (C) 2013 Canonical Ltd.
2485+# Copyright (C) 2013-2016 Canonical Ltd.
2486
2487 # This library is free software; you can redistribute it and/or
2488 # modify it under the terms of the GNU Lesser General Public
2489@@ -265,6 +265,7 @@
2490 '<(DEPTH)/ui/gl/gl.gyp:gl',
2491 '<(DEPTH)/ui/native_theme/native_theme.gyp:native_theme',
2492 '<(DEPTH)/ui/ozone/ozone.gyp:ozone',
2493+ '<(DEPTH)/ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection',
2494 '<(DEPTH)/url/url.gyp:url_lib',
2495 '<(DEPTH)/v8/tools/gyp/v8.gyp:v8',
2496 '../build/system.gyp:gdkpixbuf',

Subscribers

People subscribed via source and target branches