Index: third_party/WebKit/Source/core/loader/ProgressTracker.cpp |
diff --git a/third_party/WebKit/Source/core/loader/ProgressTracker.cpp b/third_party/WebKit/Source/core/loader/ProgressTracker.cpp |
index 66c8517af76c01b766ba78e6c636b151a8b8a9f2..df784a0b5444dfb29d0636ed0f35ca3959cd114c 100644 |
--- a/third_party/WebKit/Source/core/loader/ProgressTracker.cpp |
+++ b/third_party/WebKit/Source/core/loader/ProgressTracker.cpp |
@@ -25,6 +25,7 @@ |
#include "core/loader/ProgressTracker.h" |
+#include "core/fetch/Resource.h" |
#include "core/fetch/ResourceFetcher.h" |
#include "core/frame/FrameView.h" |
#include "core/frame/LocalFrame.h" |
@@ -46,12 +47,11 @@ namespace blink { |
// soon as a load starts. |
static const double initialProgressValue = 0.1; |
-// Similarly, always leave space at the end. This helps show the user that we're not done |
-// until we're done. |
-static const double finalProgressValue = 0.9; // 1.0 - initialProgressValue |
- |
static const int progressItemDefaultEstimatedLength = 1024 * 1024; |
+static const double progressNotificationInterval = 0.02; |
+static const double progressNotificationTimeInterval = 0.1; |
+ |
struct ProgressItem { |
WTF_MAKE_NONCOPYABLE(ProgressItem); USING_FAST_MALLOC(ProgressItem); |
public: |
@@ -70,14 +70,9 @@ ProgressTracker* ProgressTracker::create(LocalFrame* frame) |
ProgressTracker::ProgressTracker(LocalFrame* frame) |
: m_frame(frame) |
- , m_mainResourceIdentifier(0) |
- , m_totalPageAndResourceBytesToLoad(0) |
- , m_totalBytesReceived(0) |
, m_lastNotifiedProgressValue(0) |
, m_lastNotifiedProgressTime(0) |
- , m_progressNotificationInterval(0.02) |
- , m_progressNotificationTimeInterval(0.1) |
- , m_finalProgressChangedSent(false) |
+ , m_finishedParsing(false) |
, m_progressValue(0) |
{ |
} |
@@ -106,22 +101,18 @@ double ProgressTracker::estimatedProgress() const |
void ProgressTracker::reset() |
{ |
m_progressItems.clear(); |
- |
- m_totalPageAndResourceBytesToLoad = 0; |
- m_totalBytesReceived = 0; |
m_progressValue = 0; |
m_lastNotifiedProgressValue = 0; |
m_lastNotifiedProgressTime = 0; |
- m_finalProgressChangedSent = false; |
+ m_finishedParsing = false; |
} |
void ProgressTracker::progressStarted() |
{ |
- if (!m_frame->isLoading()) { |
- reset(); |
- m_progressValue = initialProgressValue; |
+ if (!m_frame->isLoading()) |
m_frame->loader().client()->didStartLoading(NavigationToDifferentDocument); |
- } |
+ reset(); |
+ m_progressValue = initialProgressValue; |
m_frame->setIsLoading(true); |
InspectorInstrumentation::frameStartedLoading(m_frame); |
} |
@@ -138,144 +129,111 @@ void ProgressTracker::progressCompleted() |
void ProgressTracker::finishedParsing() |
{ |
- if (m_frame->settings()->mainResourceOnlyProgress()) |
- sendFinalProgress(); |
+ m_finishedParsing = true; |
+ maybeSendProgress(); |
} |
void ProgressTracker::sendFinalProgress() |
{ |
- if (!m_finalProgressChangedSent) { |
- m_progressValue = 1; |
- m_frame->loader().client()->progressEstimateChanged(m_progressValue); |
- } |
+ if (m_progressValue == 1) |
+ return; |
+ m_progressValue = 1; |
+ m_frame->loader().client()->progressEstimateChanged(m_progressValue); |
} |
-void ProgressTracker::incrementProgress(unsigned long identifier, const ResourceResponse& response) |
+void ProgressTracker::willStartLoading(unsigned long identifier) |
{ |
if (!m_frame->isLoading()) |
return; |
+ // All of the progress bar completion policies besides LoadEvent instead block on parsing |
+ // completion, which corresponds to finishing parsing. For those policies, don't consider |
+ // resource load that start after DOMContentLoaded finishes. |
+ if (m_frame->settings()->progressBarCompletion() != ProgressBarCompletion::LoadEvent && m_finishedParsing) |
+ return; |
+ DCHECK(!m_progressItems.get(identifier)); |
+ m_progressItems.set(identifier, adoptPtr(new ProgressItem(progressItemDefaultEstimatedLength))); |
+} |
- if (m_frame->loader().provisionalDocumentLoader() && m_frame->loader().provisionalDocumentLoader()->mainResourceIdentifier() == identifier) |
- m_mainResourceIdentifier = identifier; |
+void ProgressTracker::incrementProgress(unsigned long identifier, const ResourceResponse& response) |
+{ |
+ ProgressItem* item = m_progressItems.get(identifier); |
+ if (!item) |
+ return; |
long long estimatedLength = response.expectedContentLength(); |
if (estimatedLength < 0) |
estimatedLength = progressItemDefaultEstimatedLength; |
- |
- m_totalPageAndResourceBytesToLoad += estimatedLength; |
- |
- if (ProgressItem* item = m_progressItems.get(identifier)) { |
- item->bytesReceived = 0; |
- item->estimatedLength = estimatedLength; |
- } else { |
- m_progressItems.set(identifier, adoptPtr(new ProgressItem(estimatedLength))); |
- } |
+ item->bytesReceived = 0; |
+ item->estimatedLength = estimatedLength; |
} |
-void ProgressTracker::incrementProgressForMainResourceOnly(unsigned long identifier, int length) |
+void ProgressTracker::incrementProgress(unsigned long identifier, int length) |
{ |
- if (identifier != m_mainResourceIdentifier) |
- return; |
- |
ProgressItem* item = m_progressItems.get(identifier); |
if (!item) |
return; |
item->bytesReceived += length; |
if (item->bytesReceived > item->estimatedLength) |
- item->estimatedLength *= 2; |
- double newProgress = initialProgressValue + 0.1; // +0.1 for committing |
- if (m_frame->view()->didFirstLayout()) |
- newProgress += 0.2; |
- // 0.4 possible so far, allow 0.5 from bytes loaded, for a max of 0.9. |
- newProgress += ((double) item->bytesReceived / (double) item->estimatedLength) / 2; |
- |
- if (newProgress < m_progressValue) |
- return; |
- |
- m_progressValue = newProgress; |
- double now = currentTime(); |
- double notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime; |
- |
- double notificationProgressDelta = m_progressValue - m_lastNotifiedProgressValue; |
- if (notificationProgressDelta < m_progressNotificationInterval && notifiedProgressTimeDelta < m_progressNotificationTimeInterval) |
- return; |
- m_frame->loader().client()->progressEstimateChanged(m_progressValue); |
- m_lastNotifiedProgressValue = m_progressValue; |
- m_lastNotifiedProgressTime = now; |
+ item->estimatedLength = item->bytesReceived * 2; |
+ maybeSendProgress(); |
} |
-void ProgressTracker::incrementProgress(unsigned long identifier, int length) |
+void ProgressTracker::maybeSendProgress() |
{ |
- if (m_frame->settings()->mainResourceOnlyProgress()) { |
- incrementProgressForMainResourceOnly(identifier, length); |
- return; |
+ m_progressValue = initialProgressValue + 0.1; // +0.1 for committing |
+ if (m_finishedParsing) |
+ m_progressValue += 0.2; |
+ |
+ long long bytesReceived = 0; |
+ long long estimatedBytesForPendingRequests = 0; |
+ for (const auto& progressItem : m_progressItems) { |
+ bytesReceived += progressItem.value->bytesReceived; |
+ estimatedBytesForPendingRequests += progressItem.value->estimatedLength; |
} |
+ DCHECK_GE(estimatedBytesForPendingRequests, 0); |
+ DCHECK_GE(estimatedBytesForPendingRequests, bytesReceived); |
- ProgressItem* item = m_progressItems.get(identifier); |
- |
- // FIXME: Can this ever happen? |
- if (!item) |
- return; |
- |
- unsigned bytesReceived = length; |
- double increment, percentOfRemainingBytes; |
- long long remainingBytes, estimatedBytesForPendingRequests; |
- |
- item->bytesReceived += bytesReceived; |
- if (item->bytesReceived > item->estimatedLength) { |
- m_totalPageAndResourceBytesToLoad += ((item->bytesReceived * 2) - item->estimatedLength); |
- item->estimatedLength = item->bytesReceived * 2; |
+ if (m_finishedParsing) { |
+ if (m_frame->settings()->progressBarCompletion() == ProgressBarCompletion::DOMContentLoaded) { |
+ sendFinalProgress(); |
+ return; |
+ } |
+ if (m_frame->settings()->progressBarCompletion() != ProgressBarCompletion::LoadEvent && estimatedBytesForPendingRequests == bytesReceived) { |
+ sendFinalProgress(); |
+ return; |
+ } |
} |
- int numPendingOrLoadingRequests = m_frame->document()->fetcher()->requestCount(); |
- estimatedBytesForPendingRequests = progressItemDefaultEstimatedLength * numPendingOrLoadingRequests; |
- remainingBytes = ((m_totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - m_totalBytesReceived); |
- if (remainingBytes > 0) // Prevent divide by 0. |
- percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes; |
- else |
- percentOfRemainingBytes = 1.0; |
- |
- // For documents that use WebCore's layout system, treat first layout as the half-way point. |
- bool useClampedMaxProgress = !m_frame->view()->didFirstLayout(); |
- double maxProgressValue = useClampedMaxProgress ? 0.5 : finalProgressValue; |
- increment = (maxProgressValue - m_progressValue) * percentOfRemainingBytes; |
- m_progressValue += increment; |
- m_progressValue = min(m_progressValue, maxProgressValue); |
- ASSERT(m_progressValue >= initialProgressValue); |
+ double percentOfBytesReceived = !estimatedBytesForPendingRequests ? 1.0 : (double)bytesReceived / (double)estimatedBytesForPendingRequests; |
+ m_progressValue += percentOfBytesReceived / 2; |
- m_totalBytesReceived += bytesReceived; |
+ DCHECK_GE(m_progressValue, initialProgressValue); |
+ // Always leave space at the end. This helps show the user that we're not |
+ // done until we're done. |
+ DCHECK(m_progressValue <= 0.9); |
+ if (m_progressValue < m_lastNotifiedProgressValue) |
+ return; |
double now = currentTime(); |
double notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime; |
double notificationProgressDelta = m_progressValue - m_lastNotifiedProgressValue; |
- if (notificationProgressDelta >= m_progressNotificationInterval || notifiedProgressTimeDelta >= m_progressNotificationTimeInterval) { |
- if (!m_finalProgressChangedSent) { |
- if (m_progressValue == 1) |
- m_finalProgressChangedSent = true; |
- |
- m_frame->loader().client()->progressEstimateChanged(m_progressValue); |
- |
- m_lastNotifiedProgressValue = m_progressValue; |
- m_lastNotifiedProgressTime = now; |
- } |
+ if (notificationProgressDelta >= progressNotificationInterval || notifiedProgressTimeDelta >= progressNotificationTimeInterval) { |
+ m_frame->loader().client()->progressEstimateChanged(m_progressValue); |
+ m_lastNotifiedProgressValue = m_progressValue; |
+ m_lastNotifiedProgressTime = now; |
} |
} |
void ProgressTracker::completeProgress(unsigned long identifier) |
{ |
ProgressItem* item = m_progressItems.get(identifier); |
- |
- // This can happen if a load fails without receiving any response data. |
if (!item) |
return; |
- // Adjust the total expected bytes to account for any overage/underage. |
- long long delta = item->bytesReceived - item->estimatedLength; |
- m_totalPageAndResourceBytesToLoad += delta; |
- |
- m_progressItems.remove(identifier); |
+ item->estimatedLength = item->bytesReceived; |
+ maybeSendProgress(); |
} |
} // namespace blink |