| 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 da475fa4ff31846e45c1d289f7458c3089e82b03..8feaf2ecc3ad591cdc7b0a948d756e02d784201d 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"
|
| @@ -47,12 +48,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:
|
| @@ -71,14 +71,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)
|
| {
|
| }
|
| @@ -107,22 +102,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);
|
| }
|
| @@ -139,144 +130,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, wrapUnique(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, wrapUnique(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
|
|
|