From 25bb229aa707d5652cf4479a8c7008a02574f2e3 Mon Sep 17 00:00:00 2001
From: Viktor Engelmann <viktor.engelmann@qt.io>
Date: Fri, 18 Aug 2017 12:56:53 +0200
Subject: [PATCH] Emit loadProgress only between loadStarted and loadFinished

We now track the values we send to the loadProgress signal. We store
the last value in a new int WebContentsDelegateQt::m_lastLoadProgress
and only send values that are >= m_lastLoadProgress to ensure
monotonicity.
A value < 0 indicates that no loading is going on. Only on loadStarted
it is set to 0 (and a loadProgress is emitted with progress 0) and
on loadFinished, it is set to -1 (and a loadProgress is emitted with
progress 100).
This way, we ensure that you first get a loadStarted signal, at least
two loadProgress signals (0 and 100) and a loadFinished signal
AND all loadProgress signals come in a monotonous order.

Task-number: QTBUG-57839
Task-number: QTBUG-61815
Change-Id: I219d3bffbd5691adb892a11b79647ba9e1ed248e
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
---
 src/core/web_contents_delegate_qt.cpp | 40 +++++++++++++++++++++------
 src/core/web_contents_delegate_qt.h   |  3 ++
 tests/auto/quick/qmltests/BLACKLIST   |  3 --
 3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 1121714eb..b2df7e993 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -94,6 +94,7 @@ WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents *webContents,
     : m_viewClient(adapterClient)
     , m_lastReceivedFindReply(0)
     , m_faviconManager(new FaviconManager(new FaviconManagerPrivate(webContents, adapterClient)))
+    , m_lastLoadProgress(-1)
 {
     webContents->SetDelegate(this);
     Observe(webContents);
@@ -177,7 +178,11 @@ void WebContentsDelegateQt::LoadProgressChanged(content::WebContents */*source*/
 {
     if (!m_loadingErrorFrameList.isEmpty())
         return;
-    m_viewClient->loadProgressChanged(qRound(progress * 100));
+    if (m_lastLoadProgress < 0) // suppress signals that aren't between loadStarted and loadFinished
+        return;
+    m_lastLoadProgress = qMax(m_lastLoadProgress, qRound(progress * 100)); // ensure monotonicity
+    m_lastLoadProgress = qMin(m_lastLoadProgress, 100);
+    m_viewClient->loadProgressChanged(m_lastLoadProgress);
 }
 
 void WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const content::NativeWebKeyboardEvent &event)
@@ -192,6 +197,15 @@ void WebContentsDelegateQt::RenderFrameDeleted(content::RenderFrameHost *render_
     m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID());
 }
 
+void WebContentsDelegateQt::EmitLoadStarted(const QUrl &url, bool isErrorPage)
+{
+    if (m_lastLoadProgress >= 0) // already running
+        return;
+    m_viewClient->loadStarted(url, isErrorPage);
+    m_viewClient->loadProgressChanged(0);
+    m_lastLoadProgress = 0;
+}
+
 void WebContentsDelegateQt::DidStartNavigation(content::NavigationHandle *navigation_handle)
 {
     if (!navigation_handle->IsInMainFrame())
@@ -212,7 +226,16 @@ void WebContentsDelegateQt::DidStartNavigation(content::NavigationHandle *naviga
 
     m_loadingErrorFrameList.clear();
     m_faviconManager->resetCandidates();
-    m_viewClient->loadStarted(toQt(navigation_handle->GetURL()));
+    EmitLoadStarted(toQt(navigation_handle->GetURL()));
+}
+
+void WebContentsDelegateQt::EmitLoadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, const QString &errorDescription)
+{
+    if (m_lastLoadProgress < 0) // not currently running
+        return;
+    m_lastLoadProgress = -1;
+    m_viewClient->loadProgressChanged(100);
+    m_viewClient->loadFinished(success, url, isErrorPage, errorCode, errorDescription);
 }
 
 void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navigation_handle)
@@ -245,7 +268,7 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig
         // Now report we are starting to load an error-page.
         m_loadingErrorFrameList.append(navigation_handle->GetRenderFrameHost()->GetRoutingID());
         m_faviconManager->resetCandidates();
-        m_viewClient->loadStarted(toQt(GURL(content::kUnreachableWebDataURL)), true);
+        EmitLoadStarted(toQt(GURL(content::kUnreachableWebDataURL)), true);
 
         // If it is already committed we will not see another DidFinishNavigation call or a DidFinishLoad call.
         if (navigation_handle->HasCommitted()) {
@@ -258,8 +281,7 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig
 void WebContentsDelegateQt::didFailLoad(const QUrl &url, int errorCode, const QString &errorDescription)
 {
     m_viewClient->iconChanged(QUrl());
-    m_viewClient->loadFinished(false /* success */ , url, false /* isErrorPage */, errorCode, errorDescription);
-    m_viewClient->loadProgressChanged(0);
+    EmitLoadFinished(false /* success */ , url, false /* isErrorPage */, errorCode, errorDescription);
 }
 
 void WebContentsDelegateQt::DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description, bool was_ignored_by_handler)
@@ -273,7 +295,8 @@ void WebContentsDelegateQt::DidFailLoad(content::RenderFrameHost* render_frame_h
         Q_ASSERT(error_code == -3 /* ERR_ABORTED */);
         m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID());
         m_viewClient->iconChanged(QUrl());
-        m_viewClient->loadFinished(false /* success */, toQt(validated_url), true /* isErrorPage */);
+
+        EmitLoadFinished(false /* success */, toQt(validated_url), true /* isErrorPage */);
         return;
     }
 
@@ -289,7 +312,7 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame
 
         // Trigger LoadFinished signal for main frame's error page only.
         if (!render_frame_host->GetParent())
-            m_viewClient->loadFinished(true /* success */, toQt(validated_url), true /* isErrorPage */);
+            EmitLoadFinished(true /* success */, toQt(validated_url), true /* isErrorPage */);
 
         return;
     }
@@ -300,8 +323,7 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame
     if (!m_faviconManager->hasCandidate())
         m_viewClient->iconChanged(QUrl());
 
-    m_viewClient->loadProgressChanged(100);
-    m_viewClient->loadFinished(true, toQt(validated_url));
+    EmitLoadFinished(true, toQt(validated_url));
 }
 
 void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates)
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 84799c2cd..20c70ef21 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -149,6 +149,8 @@ public:
 
 private:
     QWeakPointer<WebContentsAdapter> createWindow(content::WebContents *new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture);
+    void EmitLoadStarted(const QUrl &url, bool isErrorPage = false);
+    void EmitLoadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString());
 
     WebContentsAdapterClient *m_viewClient;
     QString m_lastSearchedString;
@@ -158,6 +160,7 @@ private:
     SavePageInfo m_savePageInfo;
     QSharedPointer<FilePickerController> m_filePickerController;
     QUrl m_initialTargetUrl;
+    int m_lastLoadProgress;
 };
 
 } // namespace QtWebEngineCore
diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST
index 010b014d7..19d75dfb7 100644
--- a/tests/auto/quick/qmltests/BLACKLIST
+++ b/tests/auto/quick/qmltests/BLACKLIST
@@ -19,6 +19,3 @@ linux
 
 [WebEngineViewSingleFileUpload::test_acceptSingleFileSelection]
 *
-
-[WebEngineViewLoadProgress::test_loadProgress]
-osx
-- 
GitLab