summaryrefslogtreecommitdiffstats
path: root/WebCore/loader
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/loader')
-rw-r--r--WebCore/loader/Cache.cpp40
-rw-r--r--WebCore/loader/Cache.h28
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.cpp3
-rw-r--r--WebCore/loader/CachedFont.cpp2
-rw-r--r--WebCore/loader/CachedImage.cpp3
-rw-r--r--WebCore/loader/CachedScript.cpp3
-rw-r--r--WebCore/loader/EmptyClients.h5
-rw-r--r--WebCore/loader/FrameLoaderClient.h4
-rw-r--r--WebCore/loader/PingLoader.cpp32
-rw-r--r--WebCore/loader/PingLoader.h4
-rw-r--r--WebCore/loader/RedirectScheduler.cpp2
11 files changed, 112 insertions, 14 deletions
diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/Cache.cpp
index dbcec00..28c9f93 100644
--- a/WebCore/loader/Cache.cpp
+++ b/WebCore/loader/Cache.cpp
@@ -238,11 +238,15 @@ void Cache::revalidationFailed(CachedResource* revalidatingResource)
CachedResource* Cache::resourceForURL(const String& url)
{
CachedResource* resource = m_resources.get(url);
+ bool wasPurgeable = Cache::shouldMakeResourcePurgeableOnEviction() && resource && resource->isPurgeable();
if (resource && !resource->makePurgeable(false)) {
ASSERT(!resource->hasClients());
evict(resource);
return 0;
}
+ // Add the size back since we had subtracted it when we marked the memory as purgeable.
+ if (wasPurgeable)
+ adjustSize(resource->hasClients(), resource->size());
return resource;
}
@@ -363,7 +367,9 @@ void Cache::pruneDeadResources()
while (current) {
CachedResource* prev = current->m_prevInAllResourcesList;
if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) {
- evict(current);
+ if (!makeResourcePurgeable(current))
+ evict(current);
+
// If evict() caused pruneDeadResources() to be re-entered, bail out. This can happen when removing an
// SVG CachedImage that has subresources.
if (!m_inPruneDeadResources)
@@ -397,6 +403,25 @@ void Cache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned
prune();
}
+bool Cache::makeResourcePurgeable(CachedResource* resource)
+{
+ if (!Cache::shouldMakeResourcePurgeableOnEviction())
+ return false;
+
+ if (!resource->inCache())
+ return false;
+
+ if (!resource->isSafeToMakePurgeable())
+ return false;
+
+ if (!resource->makePurgeable(true))
+ return false;
+
+ adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
+
+ return true;
+}
+
void Cache::evict(CachedResource* resource)
{
// The resource may have already been removed by someone other than our caller,
@@ -410,10 +435,10 @@ void Cache::evict(CachedResource* resource)
removeFromLRUList(resource);
removeFromLiveDecodedResourcesList(resource);
- // Subtract from our size totals.
- int delta = -static_cast<int>(resource->size());
- if (delta)
- adjustSize(resource->hasClients(), delta);
+ // If the resource was purged, it means we had already decremented the size when we made the
+ // resource purgeable in makeResourcePurgeable().
+ if (!Cache::shouldMakeResourcePurgeableOnEviction() || !resource->wasPurged())
+ adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
} else
ASSERT(m_resources.get(resource->url()) != resource);
@@ -725,7 +750,7 @@ void Cache::dumpStats()
void Cache::dumpLRULists(bool includeLive) const
{
- printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n");
+ printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n");
int size = m_allResources.size();
for (int i = size - 1; i >= 0; i--) {
@@ -734,7 +759,8 @@ void Cache::dumpLRULists(bool includeLive) const
while (current) {
CachedResource* prev = current->m_prevInAllResourcesList;
if (includeLive || !current->hasClients())
- printf("(%.1fK, %.1fK, %uA, %dR); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients());
+ printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged());
+
current = prev;
}
}
diff --git a/WebCore/loader/Cache.h b/WebCore/loader/Cache.h
index 9d7e8be..eb5b398 100644
--- a/WebCore/loader/Cache.h
+++ b/WebCore/loader/Cache.h
@@ -55,6 +55,22 @@ class KURL;
// -------|-----+++++++++++++++|
// -------|-----+++++++++++++++|+++++
+// The behavior of the cache changes in the following way if shouldMakeResourcePurgeableOnEviction
+// returns true.
+//
+// 1. Dead resources in the cache are kept in non-purgeable memory.
+// 2. When we prune dead resources, instead of freeing them, we mark their memory as purgeable and
+// keep the resources until the kernel reclaims the purgeable memory.
+//
+// By leaving the in-cache dead resources in dirty resident memory, we decrease the likelihood of
+// the kernel claiming that memory and forcing us to refetch the resource (for example when a user
+// presses back).
+//
+// And by having an unbounded number of resource objects using purgeable memory, we can use as much
+// memory as is available on the machine. The trade-off here is that the CachedResource object (and
+// its member variables) are allocated in non-purgeable TC-malloc'd memory so we would see slightly
+// more memory use due to this.
+
class Cache : public Noncopyable {
public:
friend Cache* cache();
@@ -148,6 +164,8 @@ public:
void addToLiveResourcesSize(CachedResource*);
void removeFromLiveResourcesSize(CachedResource*);
+ static bool shouldMakeResourcePurgeableOnEviction();
+
// Function to collect cache statistics for the caches window in the Safari Debug menu.
Statistics getStatistics();
@@ -173,6 +191,7 @@ private:
void pruneDeadResources(); // Flush decoded and encoded data from resources not referenced by Web pages.
void pruneLiveResources(); // Flush decoded data from resources still referenced by Web pages.
+ bool makeResourcePurgeable(CachedResource*);
void evict(CachedResource*);
// Member variables.
@@ -204,6 +223,15 @@ private:
HashMap<String, CachedResource*> m_resources;
};
+inline bool Cache::shouldMakeResourcePurgeableOnEviction()
+{
+#if PLATFORM(IOS)
+ return true;
+#else
+ return false;
+#endif
+}
+
// Function to obtain the global cache.
Cache* cache();
diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp
index 7866efd..877cd1d 100644
--- a/WebCore/loader/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/CachedCSSStyleSheet.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "CachedCSSStyleSheet.h"
+#include "Cache.h"
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
#include "HTTPParsers.h"
@@ -58,7 +59,7 @@ void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c)
void CachedCSSStyleSheet::allClientsRemoved()
{
- if (isSafeToMakePurgeable())
+ if (!Cache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
makePurgeable(true);
}
diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/CachedFont.cpp
index 166fa85..ef88af8 100644
--- a/WebCore/loader/CachedFont.cpp
+++ b/WebCore/loader/CachedFont.cpp
@@ -27,7 +27,7 @@
#include "config.h"
#include "CachedFont.h"
-#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX))) || PLATFORM(HAIKU) || OS(WINCE) || PLATFORM(ANDROID)
+#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX) || OS(FREEBSD))) || PLATFORM(HAIKU) || OS(WINCE) || PLATFORM(ANDROID)
#define STORE_FONT_CUSTOM_PLATFORM_DATA
#endif
diff --git a/WebCore/loader/CachedImage.cpp b/WebCore/loader/CachedImage.cpp
index 908c425..641ce94 100644
--- a/WebCore/loader/CachedImage.cpp
+++ b/WebCore/loader/CachedImage.cpp
@@ -338,7 +338,8 @@ void CachedImage::destroyDecodedData()
// Invoking addClient() will reconstruct the image object.
m_image = 0;
setDecodedSize(0);
- makePurgeable(true);
+ if (!Cache::shouldMakeResourcePurgeableOnEviction())
+ makePurgeable(true);
} else if (m_image && !errorOccurred())
m_image->destroyDecodedData();
}
diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/CachedScript.cpp
index 58895d6..1898438 100644
--- a/WebCore/loader/CachedScript.cpp
+++ b/WebCore/loader/CachedScript.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "CachedScript.h"
+#include "Cache.h"
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
#include "SharedBuffer.h"
@@ -110,7 +111,7 @@ void CachedScript::destroyDecodedData()
{
m_script = String();
setDecodedSize(0);
- if (isSafeToMakePurgeable())
+ if (!Cache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
makePurgeable(true);
}
diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h
index f295663..6fb003e 100644
--- a/WebCore/loader/EmptyClients.h
+++ b/WebCore/loader/EmptyClients.h
@@ -340,7 +340,7 @@ public:
virtual void didDisplayInsecureContent() { }
virtual void didRunInsecureContent(SecurityOrigin*) { }
virtual PassRefPtr<Frame> createFrame(const KURL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) { return 0; }
- virtual void didTransferChildFrameToNewDocument() { }
+ virtual void didTransferChildFrameToNewDocument(Page*) { }
virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool) { return 0; }
virtual PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL&, const Vector<String>&, const Vector<String>&) { return 0; }
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
@@ -361,6 +361,7 @@ public:
virtual void didCreateScriptContextForFrame() { }
virtual void didDestroyScriptContextForFrame() { }
virtual void didCreateIsolatedScriptContext() { }
+ virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; }
#endif
virtual void registerForIconNotification(bool) { }
@@ -550,6 +551,7 @@ public:
virtual void startUpdating() { }
virtual void stopUpdating() { }
virtual DeviceMotionData* currentDeviceMotion() const { return 0; }
+ virtual void deviceMotionControllerDestroyed() { }
};
class EmptyDeviceOrientationClient : public DeviceOrientationClient {
@@ -558,6 +560,7 @@ public:
virtual void startUpdating() { }
virtual void stopUpdating() { }
virtual DeviceOrientation* lastOrientation() const { return 0; }
+ virtual void deviceOrientationControllerDestroyed() { }
};
}
diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h
index 427b81e..803eb11 100644
--- a/WebCore/loader/FrameLoaderClient.h
+++ b/WebCore/loader/FrameLoaderClient.h
@@ -64,6 +64,7 @@ namespace WebCore {
class IntSize;
class KURL;
class NavigationAction;
+ class Page;
class ProtectionSpace;
class PluginView;
class PolicyChecker;
@@ -229,7 +230,7 @@ namespace WebCore {
virtual PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0;
- virtual void didTransferChildFrameToNewDocument() = 0;
+ virtual void didTransferChildFrameToNewDocument(Page* oldPage) = 0;
virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually) = 0;
virtual void redirectDataToPlugin(Widget* pluginWidget) = 0;
@@ -253,6 +254,7 @@ namespace WebCore {
virtual void didCreateScriptContextForFrame() = 0;
virtual void didDestroyScriptContextForFrame() = 0;
virtual void didCreateIsolatedScriptContext() = 0;
+ virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) = 0;
#endif
virtual void registerForIconNotification(bool listen = true) = 0;
diff --git a/WebCore/loader/PingLoader.cpp b/WebCore/loader/PingLoader.cpp
index 2a628ce..dd00128 100644
--- a/WebCore/loader/PingLoader.cpp
+++ b/WebCore/loader/PingLoader.cpp
@@ -32,6 +32,7 @@
#include "config.h"
#include "PingLoader.h"
+#include "FormData.h"
#include "Frame.h"
#include "ResourceHandle.h"
#include "SecurityOrigin.h"
@@ -60,9 +61,40 @@ void PingLoader::loadImage(Frame* frame, const KURL& url)
UNUSED_PARAM(leakedPingLoader);
}
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
+void PingLoader::sendPing(Frame* frame, const KURL& pingURL, const KURL& destinationURL)
+{
+ ResourceRequest request(pingURL);
+ request.setTargetType(ResourceRequest::TargetIsSubresource);
+ request.setHTTPMethod("POST");
+ request.setHTTPContentType("text/ping");
+ request.setHTTPBody(FormData::create("PING"));
+ request.setHTTPHeaderField("Cache-Control", "max-age=0");
+ frame->loader()->addExtraFieldsToSubresourceRequest(request);
+
+ SecurityOrigin* sourceOrigin = frame->document()->securityOrigin();
+ RefPtr<SecurityOrigin> pingOrigin = SecurityOrigin::create(pingURL);
+ FrameLoader::addHTTPOriginIfNeeded(request, sourceOrigin->toString());
+ request.setHTTPHeaderField("Ping-To", destinationURL);
+ if (sourceOrigin->isSameSchemeHostPort(pingOrigin.get()))
+ request.setHTTPHeaderField("Ping-From", frame->document()->url());
+ else if (!SecurityOrigin::shouldHideReferrer(pingURL, frame->loader()->outgoingReferrer()))
+ request.setHTTPReferrer(frame->loader()->outgoingReferrer());
+ OwnPtr<PingLoader> pingLoader = adoptPtr(new PingLoader(frame, request));
+
+ // Leak the ping loader, since it will kill itself as soon as it receives a response.
+ PingLoader* leakedPingLoader = pingLoader.leakPtr();
+ UNUSED_PARAM(leakedPingLoader);
+}
+
PingLoader::PingLoader(Frame* frame, const ResourceRequest& request)
+ : m_timeout(this, &PingLoader::timeout)
{
m_handle = ResourceHandle::create(frame->loader()->networkingContext(), request, this, false, false);
+
+ // If the server never responds, FrameLoader won't be able to cancel this load and
+ // we'll sit here waiting forever. Set a very generous timeout, just in case.
+ m_timeout.startOneShot(60000);
}
PingLoader::~PingLoader()
diff --git a/WebCore/loader/PingLoader.h b/WebCore/loader/PingLoader.h
index e26a9c9..eb43166 100644
--- a/WebCore/loader/PingLoader.h
+++ b/WebCore/loader/PingLoader.h
@@ -33,6 +33,7 @@
#define PingLoader_h
#include "ResourceHandleClient.h"
+#include "Timer.h"
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
@@ -52,6 +53,7 @@ class ResourceResponse;
class PingLoader : private ResourceHandleClient, public Noncopyable {
public:
static void loadImage(Frame*, const KURL& url);
+ static void sendPing(Frame*, const KURL& pingURL, const KURL& destinationURL);
~PingLoader();
@@ -62,8 +64,10 @@ private:
void didReceiveData(ResourceHandle*, const char*, int) { delete this; }
void didFinishLoading(ResourceHandle*, double) { delete this; }
void didFail(ResourceHandle*, const ResourceError&) { delete this; }
+ void timeout(Timer<PingLoader>*) { delete this; }
RefPtr<ResourceHandle> m_handle;
+ Timer<PingLoader> m_timeout;
};
}
diff --git a/WebCore/loader/RedirectScheduler.cpp b/WebCore/loader/RedirectScheduler.cpp
index ce0e3f8..ce41cde 100644
--- a/WebCore/loader/RedirectScheduler.cpp
+++ b/WebCore/loader/RedirectScheduler.cpp
@@ -318,7 +318,7 @@ void RedirectScheduler::scheduleFormSubmission(PassRefPtr<FormSubmission> submis
// to match IE and Opera.
// See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
bool isUserGesture = m_frame->loader()->isProcessingUserGesture();
- bool lockBackForwardList = mustLockBackForwardList(m_frame, isUserGesture) || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent());
+ bool lockBackForwardList = mustLockBackForwardList(m_frame, isUserGesture) || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent() && !isUserGesture);
schedule(adoptPtr(new ScheduledFormSubmission(submission, lockBackForwardList, duringLoad, isUserGesture)));
}