Merge lp:~osomon/webbrowser-app/webview-capture into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 843
Merged at revision: 840
Proposed branch: lp:~osomon/webbrowser-app/webview-capture
Merge into: lp:webbrowser-app
Diff against target: 726 lines (+471/-65)
12 files modified
src/app/webbrowser/Browser.qml (+60/-33)
src/app/webbrowser/CMakeLists.txt (+5/-1)
src/app/webbrowser/TabPreview.qml (+19/-25)
src/app/webbrowser/TabsView.qml (+1/-2)
src/app/webbrowser/file-operations.cpp (+32/-0)
src/app/webbrowser/file-operations.h (+36/-0)
src/app/webbrowser/item-capture.cpp (+123/-0)
src/app/webbrowser/item-capture.h (+63/-0)
src/app/webbrowser/webbrowser-app.cpp (+11/-0)
tests/unittests/qml/CMakeLists.txt (+7/-2)
tests/unittests/qml/tst_ItemCapture.qml (+108/-0)
tests/unittests/qml/tst_QmlTests.cpp (+6/-2)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/webview-capture
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+243034@code.launchpad.net

Commit message

Take captures of live webviews and cache them on disk, to use them as tab previews.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
842. By Olivier Tilloy

Remove an unnecessary mutex, when updatePainNode() is called, the GUI thread is blocked.

843. By Olivier Tilloy

Remove the superfluous onCaptureFinished wrapper.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/webbrowser/Browser.qml'
2--- src/app/webbrowser/Browser.qml 2014-11-11 18:30:38 +0000
3+++ src/app/webbrowser/Browser.qml 2014-12-11 18:51:44 +0000
4@@ -76,37 +76,6 @@
5 ]
6
7 Item {
8- id: previewsContainer
9-
10- width: tabContainer.width
11- height: tabContainer.height
12- y: tabContainer.y
13-
14- Component {
15- id: previewComponent
16-
17- ShaderEffectSource {
18- id: preview
19-
20- property var tab
21-
22- width: parent.width
23- height: parent.height
24-
25- sourceItem: tab ? tab.webview : null
26-
27- onTabChanged: {
28- if (!tab) {
29- this.destroy()
30- }
31- }
32-
33- live: mainView.visible && (browser.currentWebview === sourceItem)
34- }
35- }
36- }
37-
38- Item {
39 id: mainView
40
41 anchors.fill: parent
42@@ -363,6 +332,7 @@
43 id: tabComponent
44
45 FocusScope {
46+ property string uniqueId: this.toString() + "-" + Date.now()
47 property url initialUrl
48 property string initialTitle
49 property var request
50@@ -370,7 +340,7 @@
51 readonly property url url: webview ? webview.url : initialUrl
52 readonly property string title: webview ? webview.title : initialTitle
53 readonly property url icon: webview ? webview.icon : ""
54- property var preview
55+ property url preview
56
57 anchors.fill: parent
58
59@@ -388,6 +358,56 @@
60 }
61 }
62
63+ function close() {
64+ unload()
65+ if (preview) {
66+ FileOperations.remove(preview)
67+ }
68+ destroy()
69+ }
70+
71+ property var captureTaker
72+ Component {
73+ id: captureComponent
74+ ItemCapture {
75+ quality: 50
76+ onCaptureFinished: {
77+ if ((request == uniqueId) && capture.toString()) {
78+ if (preview == capture) {
79+ // Ensure that the preview URL actually changes,
80+ // for the image to be reloaded
81+ preview = ""
82+ }
83+ preview = capture
84+ }
85+ if (!webview.visible) {
86+ captureTaker.destroy()
87+ }
88+ }
89+ }
90+ }
91+ function createCaptureTakerIfNeeded() {
92+ if (!captureTaker) {
93+ captureTaker = captureComponent.createObject(webview)
94+ }
95+ }
96+ onWebviewChanged: {
97+ if (webview) {
98+ createCaptureTakerIfNeeded()
99+ }
100+ }
101+
102+ Connections {
103+ target: webview
104+ onVisibleChanged: {
105+ if (webview.visible) {
106+ createCaptureTakerIfNeeded()
107+ } else {
108+ captureTaker.requestCapture(uniqueId)
109+ }
110+ }
111+ }
112+
113 Component.onCompleted: {
114 if (request) {
115 // Instantiating the webview cannot be delayed because the request
116@@ -502,7 +522,6 @@
117 tabsModel.setCurrent(index)
118 chrome.requestedUrl = tab.initialUrl
119 }
120- tab.preview = previewComponent.createObject(previewsContainer, {tab: tab})
121 }
122
123 function focusAddressBar() {
124@@ -568,13 +587,21 @@
125 // history, current scroll offset and form data. See http://pad.lv/1353143.
126 function serializeTabState(tab) {
127 var state = {}
128+ state.uniqueId = tab.uniqueId
129 state.url = tab.url.toString()
130 state.title = tab.title
131+ state.preview = tab.preview.toString()
132 return state
133 }
134
135 function createTabFromState(state) {
136 var properties = {"initialUrl": state.url, "initialTitle": state.title}
137+ if ('uniqueId' in state) {
138+ properties["uniqueId"] = state.uniqueId
139+ }
140+ if ('preview' in state) {
141+ properties["preview"] = state.preview
142+ }
143 return tabComponent.createObject(tabContainer, properties)
144 }
145 }
146
147=== modified file 'src/app/webbrowser/CMakeLists.txt'
148--- src/app/webbrowser/CMakeLists.txt 2014-10-15 09:57:35 +0000
149+++ src/app/webbrowser/CMakeLists.txt 2014-12-11 18:51:44 +0000
150@@ -25,7 +25,11 @@
151
152 qt5_use_modules(${WEBBROWSER_APP_MODELS} Core Sql)
153
154+include_directories(${Qt5Quick_PRIVATE_INCLUDE_DIRS})
155+
156 set(WEBBROWSER_APP_SRC
157+ file-operations.cpp
158+ item-capture.cpp
159 searchengine.cpp
160 settings.cpp
161 webbrowser-app.cpp
162@@ -37,7 +41,7 @@
163
164 target_link_libraries(${WEBBROWSER_APP} ${COMMONLIB} ${WEBBROWSER_APP_MODELS})
165
166-qt5_use_modules(${WEBBROWSER_APP} Core Gui Qml Quick)
167+qt5_use_modules(${WEBBROWSER_APP} Concurrent Core Gui Qml Quick)
168
169 install(TARGETS ${WEBBROWSER_APP}
170 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
171
172=== modified file 'src/app/webbrowser/TabPreview.qml'
173--- src/app/webbrowser/TabPreview.qml 2014-08-21 08:02:42 +0000
174+++ src/app/webbrowser/TabPreview.qml 2014-12-11 18:51:44 +0000
175@@ -146,6 +146,7 @@
176 Image {
177 visible: !previewContainer.visible
178 source: "assets/tab-artwork.png"
179+ asynchronous: true
180 fillMode: Image.PreserveAspectFit
181 height: Math.min(parent.height / 1.6, units.gu(28))
182 width: height
183@@ -166,11 +167,25 @@
184 }
185 }
186
187- Item {
188+ Image {
189 id: previewContainer
190- visible: tabPreview.tab ? tabPreview.tab.webview : false
191- anchors.fill: parent
192- clip: true
193+ visible: source.toString() && (status == Image.Ready)
194+ anchors {
195+ left: parent.left
196+ right: parent.right
197+ top: parent.top
198+ }
199+ height: sourceSize.height
200+ fillMode: Image.Pad
201+ source: tabPreview.tab ? tabPreview.tab.preview : ""
202+ asynchronous: true
203+ cache: false
204+ onStatusChanged: {
205+ if (status == Image.Error) {
206+ // The cached preview doesn’t exist any longer
207+ tabPreview.tab.preview = ""
208+ }
209+ }
210 }
211
212 MouseArea {
213@@ -189,25 +204,4 @@
214 opacity: 0.3
215 }
216 }
217-
218- QtObject {
219- id: internal
220- property var previewParent
221- }
222-
223- Component.onCompleted: {
224- var preview = tabPreview.tab.preview
225- internal.previewParent = preview.parent
226- preview.parent = previewContainer
227- preview.width = internal.previewParent.width
228- preview.height = internal.previewParent.height
229- }
230- Component.onDestruction: {
231- if (tabPreview.tab) {
232- var preview = tabPreview.tab.preview
233- preview.parent = internal.previewParent
234- preview.width = preview.parent.width
235- preview.height = preview.parent.height
236- }
237- }
238 }
239
240=== modified file 'src/app/webbrowser/TabsView.qml'
241--- src/app/webbrowser/TabsView.qml 2014-11-12 11:04:34 +0000
242+++ src/app/webbrowser/TabsView.qml 2014-12-11 18:51:44 +0000
243@@ -66,8 +66,7 @@
244 onCloseRequested: {
245 var tab = tabsview.model.remove(index)
246 if (tab) {
247- tab.unload()
248- tab.destroy()
249+ tab.close()
250 }
251 if (tabsview.model.count === 0) {
252 tabsview.newTabRequested()
253
254=== added file 'src/app/webbrowser/file-operations.cpp'
255--- src/app/webbrowser/file-operations.cpp 1970-01-01 00:00:00 +0000
256+++ src/app/webbrowser/file-operations.cpp 2014-12-11 18:51:44 +0000
257@@ -0,0 +1,32 @@
258+/*
259+ * Copyright 2014 Canonical Ltd.
260+ *
261+ * This file is part of webbrowser-app.
262+ *
263+ * webbrowser-app is free software; you can redistribute it and/or modify
264+ * it under the terms of the GNU General Public License as published by
265+ * the Free Software Foundation; version 3.
266+ *
267+ * webbrowser-app is distributed in the hope that it will be useful,
268+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
269+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
270+ * GNU General Public License for more details.
271+ *
272+ * You should have received a copy of the GNU General Public License
273+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
274+ */
275+
276+#include "file-operations.h"
277+
278+#include <QtCore/QFile>
279+#include <QtCore/QUrl>
280+
281+FileOperations::FileOperations(QObject* parent)
282+ : QObject(parent)
283+{
284+}
285+
286+bool FileOperations::remove(const QUrl& file) const
287+{
288+ return QFile::remove(file.toLocalFile());
289+}
290
291=== added file 'src/app/webbrowser/file-operations.h'
292--- src/app/webbrowser/file-operations.h 1970-01-01 00:00:00 +0000
293+++ src/app/webbrowser/file-operations.h 2014-12-11 18:51:44 +0000
294@@ -0,0 +1,36 @@
295+/*
296+ * Copyright 2014 Canonical Ltd.
297+ *
298+ * This file is part of webbrowser-app.
299+ *
300+ * webbrowser-app is free software; you can redistribute it and/or modify
301+ * it under the terms of the GNU General Public License as published by
302+ * the Free Software Foundation; version 3.
303+ *
304+ * webbrowser-app is distributed in the hope that it will be useful,
305+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
306+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
307+ * GNU General Public License for more details.
308+ *
309+ * You should have received a copy of the GNU General Public License
310+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
311+ */
312+
313+#ifndef __FILE_OPERATIONS_H__
314+#define __FILE_OPERATIONS_H__
315+
316+#include <QtCore/QObject>
317+
318+class QUrl;
319+
320+class FileOperations : public QObject
321+{
322+ Q_OBJECT
323+
324+public:
325+ explicit FileOperations(QObject* parent=0);
326+
327+ Q_INVOKABLE bool remove(const QUrl& file) const;
328+};
329+
330+#endif // __FILE_OPERATIONS_H__
331
332=== added file 'src/app/webbrowser/item-capture.cpp'
333--- src/app/webbrowser/item-capture.cpp 1970-01-01 00:00:00 +0000
334+++ src/app/webbrowser/item-capture.cpp 2014-12-11 18:51:44 +0000
335@@ -0,0 +1,123 @@
336+/*
337+ * Copyright 2014 Canonical Ltd.
338+ *
339+ * This file is part of webbrowser-app.
340+ *
341+ * webbrowser-app is free software; you can redistribute it and/or modify
342+ * it under the terms of the GNU General Public License as published by
343+ * the Free Software Foundation; version 3.
344+ *
345+ * webbrowser-app is distributed in the hope that it will be useful,
346+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
347+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
348+ * GNU General Public License for more details.
349+ *
350+ * You should have received a copy of the GNU General Public License
351+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
352+ */
353+
354+// local
355+#include "item-capture.h"
356+
357+// Qt
358+#include <QtConcurrent/QtConcurrent>
359+#include <QtCore/QDebug>
360+#include <QtCore/QDir>
361+#include <QtCore/QMetaObject>
362+#include <QtCore/QStandardPaths>
363+#include <QtGui/QImage>
364+#include <QtQuick/private/qquickitem_p.h>
365+
366+ItemCapture::ItemCapture(QQuickItem* parent)
367+ : QQuickShaderEffectSource(parent)
368+ , m_quality(-1)
369+{
370+ connect(this, SIGNAL(parentChanged(QQuickItem*)), SLOT(onParentChanged(QQuickItem*)));
371+
372+ setScale(0);
373+
374+ QDir cacheLocation(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/captures");
375+ m_cacheLocation = cacheLocation.absolutePath();
376+ if (!cacheLocation.exists()) {
377+ QDir::root().mkpath(m_cacheLocation);
378+ }
379+}
380+
381+const int ItemCapture::quality() const
382+{
383+ return m_quality;
384+}
385+
386+void ItemCapture::setQuality(const int quality)
387+{
388+ if (quality != m_quality) {
389+ if ((quality >= -1) && (quality <= 100)) {
390+ m_quality = quality;
391+ Q_EMIT qualityChanged();
392+ } else {
393+ qWarning() << "Invalid value for quality, must be between 0 and 100 (or -1 for default)";
394+ }
395+ }
396+}
397+
398+void ItemCapture::onParentChanged(QQuickItem* parent)
399+{
400+ if (sourceItem()) {
401+ sourceItem()->disconnect(this);
402+ }
403+ QQuickItemPrivate::get(this)->anchors()->setFill(parent);
404+ setSourceItem(parent);
405+ if (parent) {
406+ connect(parent, SIGNAL(visibleChanged()), SLOT(onParentVisibleChanged()));
407+ }
408+}
409+
410+void ItemCapture::onParentVisibleChanged()
411+{
412+ setLive(parentItem()->isVisible());
413+}
414+
415+QSGNode* ItemCapture::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData)
416+{
417+ QSGNode* newNode = QQuickShaderEffectSource::updatePaintNode(oldNode, updatePaintNodeData);
418+ if (!m_request.isEmpty()) {
419+ QString request = m_request;
420+ m_request.clear();
421+ QQuickShaderEffectTexture* texture =
422+ qobject_cast<QQuickShaderEffectTexture*>(textureProvider()->texture());
423+ QOpenGLContext* ctx =
424+ QQuickItemPrivate::get(this)->sceneGraphRenderContext()->openglContext();
425+ if (ctx->makeCurrent(ctx->surface())) {
426+ QImage image = texture->toImage().mirrored();
427+ if (!image.isNull()) {
428+ QString filePath = m_cacheLocation + "/" + request + ".jpg";
429+ QtConcurrent::run(this, &ItemCapture::saveImage, image, filePath, m_quality, request);
430+ return newNode;
431+ }
432+ }
433+ QMetaObject::invokeMethod(this, "captureFinished", Qt::QueuedConnection,
434+ Q_ARG(QString, request), Q_ARG(QUrl, QUrl()));
435+ }
436+ return newNode;
437+}
438+
439+void ItemCapture::requestCapture(const QString& id)
440+{
441+ if (id.contains("/")) {
442+ qWarning() << "Invalid ID (contains slashes)";
443+ Q_EMIT captureFinished(id, QUrl());
444+ }
445+ m_request = id;
446+ scheduleUpdate();
447+}
448+
449+void ItemCapture::saveImage(const QImage& image, const QString& filePath,
450+ const int quality, const QString& request)
451+{
452+ QUrl capture;
453+ if (image.save(filePath, 0, quality)) {
454+ capture = QUrl::fromLocalFile(filePath);
455+ }
456+ QMetaObject::invokeMethod(this, "captureFinished", Qt::QueuedConnection,
457+ Q_ARG(QString, request), Q_ARG(QUrl, capture));
458+}
459
460=== added file 'src/app/webbrowser/item-capture.h'
461--- src/app/webbrowser/item-capture.h 1970-01-01 00:00:00 +0000
462+++ src/app/webbrowser/item-capture.h 2014-12-11 18:51:44 +0000
463@@ -0,0 +1,63 @@
464+/*
465+ * Copyright 2014 Canonical Ltd.
466+ *
467+ * This file is part of webbrowser-app.
468+ *
469+ * webbrowser-app is free software; you can redistribute it and/or modify
470+ * it under the terms of the GNU General Public License as published by
471+ * the Free Software Foundation; version 3.
472+ *
473+ * webbrowser-app is distributed in the hope that it will be useful,
474+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
475+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
476+ * GNU General Public License for more details.
477+ *
478+ * You should have received a copy of the GNU General Public License
479+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
480+ */
481+
482+#ifndef __ITEM_CAPTURE_H__
483+#define __ITEM_CAPTURE_H__
484+
485+// Qt
486+#include <QtCore/QString>
487+#include <QtCore/QUrl>
488+#include <QtQuick/private/qquickshadereffectsource_p.h>
489+
490+class QImage;
491+
492+class ItemCapture : public QQuickShaderEffectSource
493+{
494+ Q_OBJECT
495+
496+ Q_PROPERTY(int quality READ quality WRITE setQuality NOTIFY qualityChanged)
497+
498+public:
499+ ItemCapture(QQuickItem* parent=0);
500+
501+ const int quality() const;
502+ void setQuality(const int quality);
503+
504+public Q_SLOTS:
505+ void requestCapture(const QString& id);
506+
507+Q_SIGNALS:
508+ void qualityChanged() const;
509+ void captureFinished(QString request, QUrl capture) const;
510+
511+protected:
512+ QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData);
513+
514+private Q_SLOTS:
515+ void onParentChanged(QQuickItem* parent);
516+ void onParentVisibleChanged();
517+ void saveImage(const QImage& image, const QString& filePath,
518+ const int quality, const QString& request);
519+
520+private:
521+ QString m_cacheLocation;
522+ QString m_request;
523+ int m_quality;
524+};
525+
526+#endif // __ITEM_CAPTURE_H__
527
528=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
529--- src/app/webbrowser/webbrowser-app.cpp 2014-10-22 18:02:03 +0000
530+++ src/app/webbrowser/webbrowser-app.cpp 2014-12-11 18:51:44 +0000
531@@ -18,12 +18,14 @@
532
533 #include "bookmarks-model.h"
534 #include "config.h"
535+#include "file-operations.h"
536 #include "history-model.h"
537 #include "history-matches-model.h"
538 #include "history-timeframe-model.h"
539 #include "history-byvisits-model.h"
540 #include "history-domainlist-model.h"
541 #include "history-domainlist-chronological-model.h"
542+#include "item-capture.h"
543 #include "limit-proxy-model.h"
544 #include "searchengine.h"
545 #include "settings.h"
546@@ -49,6 +51,13 @@
547 {
548 }
549
550+static QObject* FileOperations_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine)
551+{
552+ Q_UNUSED(engine);
553+ Q_UNUSED(scriptEngine);
554+ return new FileOperations();
555+}
556+
557 bool WebbrowserApp::initialize()
558 {
559 // Re-direct webapps to the dedicated container for backward compatibility
560@@ -82,6 +91,8 @@
561 qmlRegisterType<LimitProxyModel>(uri, 0 , 1, "LimitProxyModel");
562 qmlRegisterType<TabsModel>(uri, 0, 1, "TabsModel");
563 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");
564+ qmlRegisterType<ItemCapture>(uri, 0, 1, "ItemCapture");
565+ qmlRegisterSingletonType<FileOperations>(uri, 0, 1, "FileOperations", FileOperations_singleton_factory);
566
567 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
568 Settings settings;
569
570=== modified file 'tests/unittests/qml/CMakeLists.txt'
571--- tests/unittests/qml/CMakeLists.txt 2014-11-26 11:33:10 +0000
572+++ tests/unittests/qml/CMakeLists.txt 2014-12-11 18:51:44 +0000
573@@ -9,11 +9,16 @@
574 set(TEST tst_QmlTests)
575 set(SOURCES
576 ${webbrowser-common_SOURCE_DIR}/favicon-fetcher.cpp
577+ ${webbrowser-app_SOURCE_DIR}/item-capture.cpp
578 tst_QmlTests.cpp
579 )
580 add_executable(${TEST} ${SOURCES})
581-qt5_use_modules(${TEST} Qml QuickTest)
582-include_directories(${webbrowser-common_SOURCE_DIR})
583+qt5_use_modules(${TEST} Qml Quick QuickTest)
584+include_directories(
585+ ${webbrowser-common_SOURCE_DIR}
586+ ${webbrowser-app_SOURCE_DIR}
587+ ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
588+)
589 add_test(${TEST} ${XVFB_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}
590 -input ${CMAKE_CURRENT_SOURCE_DIR}
591 -import ${CMAKE_BINARY_DIR}/src)
592
593=== added file 'tests/unittests/qml/tst_ItemCapture.qml'
594--- tests/unittests/qml/tst_ItemCapture.qml 1970-01-01 00:00:00 +0000
595+++ tests/unittests/qml/tst_ItemCapture.qml 2014-12-11 18:51:44 +0000
596@@ -0,0 +1,108 @@
597+/*
598+ * Copyright 2014 Canonical Ltd.
599+ *
600+ * This file is part of webbrowser-app.
601+ *
602+ * webbrowser-app is free software; you can redistribute it and/or modify
603+ * it under the terms of the GNU General Public License as published by
604+ * the Free Software Foundation; version 3.
605+ *
606+ * webbrowser-app is distributed in the hope that it will be useful,
607+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
608+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
609+ * GNU General Public License for more details.
610+ *
611+ * You should have received a copy of the GNU General Public License
612+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
613+ */
614+
615+import QtQuick 2.0
616+import QtTest 1.0
617+import webbrowserapp.private 0.1
618+
619+Item {
620+ width: 200
621+ height: 200
622+
623+ Rectangle {
624+ id: rect
625+
626+ width: 123
627+ height: 157
628+ color: "red"
629+ anchors.centerIn: parent
630+
631+ ItemCapture {
632+ id: capture
633+ onCaptureFinished: image.source = capture
634+ }
635+
636+ SignalSpy {
637+ id: spyReady
638+ target: capture
639+ signalName: "scheduledUpdateCompleted"
640+ }
641+
642+ SignalSpy {
643+ id: spyCaptured
644+ target: capture
645+ signalName: "captureFinished"
646+ }
647+ }
648+
649+ Image {
650+ id: image
651+ }
652+
653+ TestCase {
654+ name: "ItemCapture"
655+ when: windowShown
656+
657+ function test_quality_data() {
658+ return [
659+ {get: -1},
660+ {set: 58, get: 58},
661+ {set: 122},
662+ {set: -39},
663+ {set: -1, get: -1},
664+ {set: 0, get: 0},
665+ {set: 100, get: 100}
666+ ]
667+ }
668+
669+ function test_quality(data) {
670+ var quality = capture.quality
671+ if ('set' in data) {
672+ capture.quality = data.set
673+ }
674+ if ('get' in data) {
675+ compare(capture.quality, data.get)
676+ } else {
677+ compare(capture.quality, quality)
678+ }
679+ }
680+
681+ function test_capture() {
682+ spyReady.wait()
683+ spyCaptured.clear()
684+ var id = "test"
685+ capture.requestCapture(id)
686+ spyCaptured.wait()
687+ compare(spyCaptured.signalArguments[0][0], id)
688+ verify(image.source.toString())
689+ compare(image.status, Image.Ready)
690+ compare(image.sourceSize.width, rect.width)
691+ compare(image.sourceSize.height, rect.height)
692+ }
693+
694+ function test_capture_invalid_id() {
695+ spyReady.wait()
696+ spyCaptured.clear()
697+ var invalid = "foo/bar"
698+ capture.requestCapture(invalid)
699+ spyCaptured.wait()
700+ compare(spyCaptured.signalArguments[0][0], invalid)
701+ verify(!spyCaptured.signalArguments[0][1].toString())
702+ }
703+ }
704+}
705
706=== modified file 'tests/unittests/qml/tst_QmlTests.cpp'
707--- tests/unittests/qml/tst_QmlTests.cpp 2014-11-26 11:33:10 +0000
708+++ tests/unittests/qml/tst_QmlTests.cpp 2014-12-11 18:51:44 +0000
709@@ -22,11 +22,15 @@
710
711 // local
712 #include "favicon-fetcher.h"
713+#include "item-capture.h"
714
715 int main(int argc, char** argv)
716 {
717- const char* uri = "webbrowsercommon.private";
718- qmlRegisterType<FaviconFetcher>(uri, 0, 1, "FaviconFetcher");
719+ const char* commonUri = "webbrowsercommon.private";
720+ qmlRegisterType<FaviconFetcher>(commonUri, 0, 1, "FaviconFetcher");
721+
722+ const char* browserUri = "webbrowserapp.private";
723+ qmlRegisterType<ItemCapture>(browserUri, 0, 1, "ItemCapture");
724
725 return quick_test_main(argc, argv, "QmlTests", 0);
726 }

Subscribers

People subscribed via source and target branches

to status/vote changes: