diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/loader/ProgressTracker.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/loader/ProgressTracker.cpp')
-rw-r--r-- | Source/WebCore/loader/ProgressTracker.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp new file mode 100644 index 0000000..cd15433 --- /dev/null +++ b/Source/WebCore/loader/ProgressTracker.cpp @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProgressTracker.h" + +#include "DocumentLoader.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderStateMachine.h" +#include "FrameLoaderClient.h" +#include "Logging.h" +#include "ResourceResponse.h" +#include <wtf/text/CString.h> +#include <wtf/CurrentTime.h> + +using std::min; + +namespace WebCore { + +// Always start progress at initialProgressValue. This helps provide feedback as +// 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 * 16; + +struct ProgressItem : Noncopyable { + ProgressItem(long long length) + : bytesReceived(0) + , estimatedLength(length) { } + + long long bytesReceived; + long long estimatedLength; +}; + +unsigned long ProgressTracker::s_uniqueIdentifier = 0; + +ProgressTracker::ProgressTracker() + : m_totalPageAndResourceBytesToLoad(0) + , m_totalBytesReceived(0) + , m_lastNotifiedProgressValue(0) + , m_lastNotifiedProgressTime(0) + , m_progressNotificationInterval(0.02) + , m_progressNotificationTimeInterval(0.1) + , m_finalProgressChangedSent(false) + , m_progressValue(0) + , m_numProgressTrackedFrames(0) +{ +} + +ProgressTracker::~ProgressTracker() +{ + deleteAllValues(m_progressItems); +} + +double ProgressTracker::estimatedProgress() const +{ + return m_progressValue; +} + +void ProgressTracker::reset() +{ + deleteAllValues(m_progressItems); + m_progressItems.clear(); + + m_totalPageAndResourceBytesToLoad = 0; + m_totalBytesReceived = 0; + m_progressValue = 0; + m_lastNotifiedProgressValue = 0; + m_lastNotifiedProgressTime = 0; + m_finalProgressChangedSent = false; + m_numProgressTrackedFrames = 0; + m_originatingProgressFrame = 0; +} + +void ProgressTracker::progressStarted(Frame* frame) +{ + LOG(Progress, "Progress started (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, frame, frame->tree()->uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get()); + + frame->loader()->client()->willChangeEstimatedProgress(); + + if (m_numProgressTrackedFrames == 0 || m_originatingProgressFrame == frame) { + reset(); + m_progressValue = initialProgressValue; + m_originatingProgressFrame = frame; + + m_originatingProgressFrame->loader()->client()->postProgressStartedNotification(); + } + m_numProgressTrackedFrames++; + + frame->loader()->client()->didChangeEstimatedProgress(); +} + +void ProgressTracker::progressCompleted(Frame* frame) +{ + LOG(Progress, "Progress completed (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, frame, frame->tree()->uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get()); + + if (m_numProgressTrackedFrames <= 0) + return; + + frame->loader()->client()->willChangeEstimatedProgress(); + + m_numProgressTrackedFrames--; + if (m_numProgressTrackedFrames == 0 || + (frame == m_originatingProgressFrame && m_numProgressTrackedFrames != 0)) + finalProgressComplete(); + + frame->loader()->client()->didChangeEstimatedProgress(); +} + +void ProgressTracker::finalProgressComplete() +{ + LOG(Progress, "Final progress complete (%p)", this); + + RefPtr<Frame> frame = m_originatingProgressFrame.release(); + + // Before resetting progress value be sure to send client a least one notification + // with final progress value. + if (!m_finalProgressChangedSent) { + m_progressValue = 1; + frame->loader()->client()->postProgressEstimateChangedNotification(); + } + + reset(); + + frame->loader()->client()->setMainFrameDocumentReady(true); + frame->loader()->client()->postProgressFinishedNotification(); +} + +void ProgressTracker::incrementProgress(unsigned long identifier, const ResourceResponse& response) +{ + LOG(Progress, "Progress incremented (%p) - value %f, tracked frames %d, originating frame %p", this, m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get()); + + if (m_numProgressTrackedFrames <= 0) + 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)).leakPtr()); +} + +void ProgressTracker::incrementProgress(unsigned long identifier, const char*, int length) +{ + ProgressItem* item = m_progressItems.get(identifier); + + // FIXME: Can this ever happen? + if (!item) + return; + + RefPtr<Frame> frame = m_originatingProgressFrame; + + frame->loader()->client()->willChangeEstimatedProgress(); + + 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; + } + + int numPendingOrLoadingRequests = frame->loader()->numPendingOrLoadingRequests(true); + 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. + // FIXME: The hasHTMLView function is a sort of roundabout way of asking "do you use WebCore's layout system". + bool useClampedMaxProgress = frame->loader()->client()->hasHTMLView() + && !frame->loader()->stateMachine()->firstLayoutDone(); + double maxProgressValue = useClampedMaxProgress ? 0.5 : finalProgressValue; + increment = (maxProgressValue - m_progressValue) * percentOfRemainingBytes; + m_progressValue += increment; + m_progressValue = min(m_progressValue, maxProgressValue); + ASSERT(m_progressValue >= initialProgressValue); + + m_totalBytesReceived += bytesReceived; + + double now = currentTime(); + double notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime; + + LOG(Progress, "Progress incremented (%p) - value %f, tracked frames %d", this, m_progressValue, m_numProgressTrackedFrames); + double notificationProgressDelta = m_progressValue - m_lastNotifiedProgressValue; + if ((notificationProgressDelta >= m_progressNotificationInterval || + notifiedProgressTimeDelta >= m_progressNotificationTimeInterval) && + m_numProgressTrackedFrames > 0) { + if (!m_finalProgressChangedSent) { + if (m_progressValue == 1) + m_finalProgressChangedSent = true; + + frame->loader()->client()->postProgressEstimateChangedNotification(); + + m_lastNotifiedProgressValue = m_progressValue; + m_lastNotifiedProgressTime = now; + } + } + + frame->loader()->client()->didChangeEstimatedProgress(); +} + +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; + item->estimatedLength = item->bytesReceived; + + m_progressItems.remove(identifier); + delete item; +} + +unsigned long ProgressTracker::createUniqueIdentifier() +{ + return ++s_uniqueIdentifier; +} + + +} |